diff --git a/.github/workflows/windows-release.yml b/.github/workflows/windows-release.yml index 0654b18..a47b33d 100644 --- a/.github/workflows/windows-release.yml +++ b/.github/workflows/windows-release.yml @@ -2,8 +2,8 @@ name: Windows Release on: push: - tags: - - "v1.0.0" + branches: + - dev jobs: build: @@ -15,7 +15,7 @@ jobs: - name: Install Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.19.0' + flutter-version: '3.27.3' channel: 'stable' cache: true @@ -31,7 +31,7 @@ jobs: - name: Create ZIP archive run: | cd build/windows/x64/runner - Compress-Archive -Path Release/* -DestinationPath ../../../Begzar-Windows.zip + Compress-Archive -Path Release/* -DestinationPath ../../../Begzar-Windows-x64.zip - name: Create Release uses: softprops/action-gh-release@v1 @@ -40,5 +40,6 @@ jobs: draft: false prerelease: false generate_release_notes: true + tag_name: v1.0.${{ github.run_number }}-beta env: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 195f765..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "begzar_windows", - "request": "launch", - "type": "dart" - }, - { - "name": "begzar_windows (profile mode)", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "begzar_windows (release mode)", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "Bcore", - "cwd": "Bcore", - "request": "launch", - "type": "dart" - }, - { - "name": "Bcore (profile mode)", - "cwd": "Bcore", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "Bcore (release mode)", - "cwd": "Bcore", - "request": "launch", - "type": "dart", - "flutterMode": "release" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ddeaf23..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "cmake.sourceDirectory": "F:/begzar_windows/windows" -} \ No newline at end of file diff --git a/Bcore/lib/sing/parser.dart b/Bcore/lib/sing/parser.dart index c28b9a8..ecb5bce 100644 --- a/Bcore/lib/sing/parser.dart +++ b/Bcore/lib/sing/parser.dart @@ -31,7 +31,7 @@ class V2raySingParser { throw V2rayParserError; } final raw = (res.stdout as String); - final json = jsonDecode(raw); + final json = jsonDecode(raw.replaceAll("tcp", 'http')); // just a litte issue in sing-parser (i lost the source code for sing-parser so i guess its the only way ...) return Map.from(json); } diff --git a/Bcore/windows/resources/README.md b/Bcore/windows/resources/README.md index 8b30901..fb90340 100644 --- a/Bcore/windows/resources/README.md +++ b/Bcore/windows/resources/README.md @@ -27,10 +27,10 @@ go build -tags "with_utls,with_clash_api,with_gvisor" -ldflags "-X 'github.com/s ===== -// for ARM windows ( new surface & ... ) +// for ARM windows ( new microsoft surface & ... ) $Env:GOOS="windows" $Env:GOARCH="arm64" go build -tags "with_utls,with_clash_api,with_gvisor" -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=1.10.1'" ./cmd/sing-box ``` -Fuck all of your documentions... \ No newline at end of file +Fuck all of sing-box & xray docs... \ No newline at end of file diff --git a/cache.db b/cache.db index b350a81..6fc5434 100644 Binary files a/cache.db and b/cache.db differ diff --git a/lib/screens/home_screens.dart b/lib/screens/home_screens.dart index b146dfe..d7c46f1 100644 --- a/lib/screens/home_screens.dart +++ b/lib/screens/home_screens.dart @@ -7,7 +7,6 @@ import 'package:begzar_windows/common/http_client.dart'; import 'package:begzar_windows/widgets/connection_widgets.dart'; import 'package:begzar_windows/widgets/logs_widget.dart'; import 'package:begzar_windows/widgets/server_selection_modal_widget.dart'; -import 'package:begzar_windows/widgets/vpn_status.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; @@ -26,6 +25,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:begzar_windows/common/settings_manager.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + class HomePage extends StatefulWidget { final ValueNotifier mainSingStatus; final ValueNotifier logsNotifier; @@ -332,20 +332,7 @@ class _HomePageState extends State { ); } - Widget _buildVpnStatus(double contentWidth) { - return Container( - width: contentWidth, - child: VpnCard( - downloadSpeed: singStatus.value.download.toInt(), - uploadSpeed: singStatus.value.upload.toInt(), - download: singStatus.value.downloadSpeed.toInt(), - upload: singStatus.value.uploadSpeed.toInt(), - selectedServer: selectedServer, - selectedServerLogo: selectedServerLogo ?? 'assets/images/auto.png', - duration: singStatus.value.duration, - ), - ); - } + void _handleConnectionTap(SingStatus value) async { if (value.state == "DISCONNECTED") { @@ -516,14 +503,14 @@ class _HomePageState extends State { } String decrypt(String secureData, String x1, String x2, String key) { - final encryptedData = { - 'ciphertext': secureData, // secure - 'nonce': x1, // x1 - 'tag': x2 // x2 - }; - final savedKey = key; + final encryptedData = { + 'ciphertext': secureData, // secure + 'nonce': x1, // x1 + 'tag': x2 // x2 + }; + final savedKey = key; try { - final decrypted = Decryptor.decryptChaCha20(encryptedData, savedKey); + final decrypted = Decryptor.decryptChaCha20(encryptedData, savedKey); return decrypted.toString(); } catch (e) { return 'Error during decryption: $e'; @@ -532,18 +519,18 @@ class _HomePageState extends State { Future getDomain() async { try { - singStatus.value = SingStatus( - state: 'CONNECTING', - duration: "00:00:00", - uploadSpeed: 0, - downloadSpeed: 0, - upload: 0, - download: 0); - + singStatus.value = SingStatus( + state: 'CONNECTING', + duration: "00:00:00", + uploadSpeed: 0, + downloadSpeed: 0, + upload: 0, + download: 0); + setState(() { isLoading = true; }); - final response = await httpClient.get('/'); + final response = await httpClient.get('/'); domainName = response.data; checkUpdate(); } catch (e) { @@ -564,38 +551,39 @@ class _HomePageState extends State { try { //final serverParam = getServerParam(); String userKey = await storage.read(key: 'user') ?? ''; - if (userKey == '') { - final response = await Dio().get( - "https://$domainName/api/firebase/init/android"); // change latar + if(userKey == ''){ + final response = await Dio().get("https://$domainName/api/firebase/init/android"); // change latar final dataJson = response.data as Map; final key = dataJson['key']; userKey = key; await storage.write(key: 'user', value: key); - } else { + }else{ userKey = await storage.read(key: 'user') ?? ''; - } + } - final response = await Dio().get( - "https://$domainName/api/firebase/init/data/$userKey"); // change latar + + final response = await Dio().get("https://$domainName/api/firebase/init/data/$userKey"); // change latar final dataJson = response.data as Map; - if (dataJson['status'] == true) { + if(dataJson['status'] == true){ final secureData = dataJson['data']['secure']; final x1 = dataJson['data']['x1']; final x2 = dataJson['data']['x2']; final serverEncode = decrypt(secureData, x1, x2, userKey); - + final List serverList = await fetchServers(serverEncode); print(serverList); await connect(serverList); - } else { + }else{ ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(dataJson['error'].toString()), + content: + Text(dataJson['error'].toString()), ), ); } + // final data_base64 = utf8.decode(base64.decode(response.data)); // final decode_json = jsonDecode(data_base64); @@ -633,37 +621,37 @@ class _HomePageState extends State { // } // } - // if (updateUrl.isNotEmpty) { - // AwesomeDialog( - // context: context, - // dialogType: DialogType.warning, - // animType: AnimType.rightSlide, - // title: 'آپدیت جدید', - // desc: 'برای دانلود ورژن جدید روی دکمه دانلود کلیک کنید', - // dialogBackgroundColor: Colors.white, - // btnCancelOnPress: () {}, - // btnOkOnPress: () async { - // await launchUrl(Uri.parse(utf8.decode(base64Decode(updateUrl))), - // mode: LaunchMode.externalApplication); - // }, - // btnOkText: 'دانلود', - // btnCancelText: 'بستن', - // buttonsTextStyle: - // TextStyle(fontFamily: 'sm', color: Colors.white, fontSize: 14), - // titleTextStyle: - // TextStyle(fontFamily: 'sb', color: Colors.black, fontSize: 16), - // descTextStyle: - // TextStyle(fontFamily: 'sm', color: Colors.black, fontSize: 14), - // ).show(); - // } else { - // if (mounted) { - // ScaffoldMessenger.of(context).showSnackBar( - // const SnackBar( - // content: Text('نسخه ی مجاز پدیت برای گوشی شما یافت نشد !'), - // ), - // ); - // } - // } + // if (updateUrl.isNotEmpty) { + // AwesomeDialog( + // context: context, + // dialogType: DialogType.warning, + // animType: AnimType.rightSlide, + // title: 'آپدیت جدید', + // desc: 'برای دانلود ورژن جدید روی دکمه دانلود کلیک کنید', + // dialogBackgroundColor: Colors.white, + // btnCancelOnPress: () {}, + // btnOkOnPress: () async { + // await launchUrl(Uri.parse(utf8.decode(base64Decode(updateUrl))), + // mode: LaunchMode.externalApplication); + // }, + // btnOkText: 'دانلود', + // btnCancelText: 'بستن', + // buttonsTextStyle: + // TextStyle(fontFamily: 'sm', color: Colors.white, fontSize: 14), + // titleTextStyle: + // TextStyle(fontFamily: 'sb', color: Colors.black, fontSize: 16), + // descTextStyle: + // TextStyle(fontFamily: 'sm', color: Colors.black, fontSize: 14), + // ).show(); + // } else { + // if (mounted) { + // ScaffoldMessenger.of(context).showSnackBar( + // const SnackBar( + // content: Text('نسخه ی مجاز پدیت برای گوشی شما یافت نشد !'), + // ), + // ); + // } + // } // } } catch (e) { print(e.toString()); @@ -684,7 +672,8 @@ class _HomePageState extends State { Future> fetchServers(String serverEncode) async { try { - final List serverList = LineSplitter.split(serverEncode).toList(); + final List serverList = + LineSplitter.split(serverEncode).toList(); return serverList; } catch (e) { if (mounted) { diff --git a/lib/widgets/navigation_rail_widget.dart b/lib/widgets/navigation_rail_widget.dart index 7e0b9f5..064696f 100644 --- a/lib/widgets/navigation_rail_widget.dart +++ b/lib/widgets/navigation_rail_widget.dart @@ -142,8 +142,7 @@ class _NavigationRailWidgetState extends State { ip!, style: TextStyle( color: Colors.grey[300], - fontFamily: - context.locale.languageCode == 'fa' ? 'sm' : 'GB', + fontFamily: context.locale.languageCode == 'fa' ? 'sm' : 'GB', fontSize: 12, ), ), @@ -237,7 +236,7 @@ class _NavigationRailWidgetState extends State { children: [ const SizedBox(height: 64), if (isExtraWideScreen) ...[ - _buildConnectionInfo(isExtraWideScreen), + _buildConnectionInfo(isExtraWideScreen), ], const Spacer(), _buildNavItems(isExtraWideScreen), diff --git a/lib/widgets/vpn_status.dart b/lib/widgets/vpn_status.dart deleted file mode 100644 index 84139e0..0000000 --- a/lib/widgets/vpn_status.dart +++ /dev/null @@ -1,345 +0,0 @@ -import 'dart:io'; - -import 'package:dio/dio.dart'; -import 'package:dio/io.dart'; -import 'package:flutter/material.dart'; -import 'package:easy_localization/easy_localization.dart'; - - -class VpnCard extends StatefulWidget { - final int downloadSpeed; - final int uploadSpeed; - final String selectedServer; - final String selectedServerLogo; - final String duration; - - final int download; - final int upload; - - const VpnCard( - {super.key, - required this.downloadSpeed, - required this.uploadSpeed, - required this.download, - required this.upload, - required this.selectedServer, - required this.selectedServerLogo, - required this.duration}); - - @override - State createState() => _VpnCardState(); -} - -class _VpnCardState extends State { - String? ipText; - String? ipflag; - bool isLoading = false; - @override - Widget build(BuildContext context) { - return Stack( - clipBehavior: Clip.none, - alignment: Alignment.center, - children: [ - Positioned( - top: -30, - child: Container( - width: 200, - height: 50, - decoration: BoxDecoration( - color: const Color(0xFF2A2A2A), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: Colors.grey.withOpacity(0.1), - ), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 8, - offset: Offset(0, 2), - ), - ], - ), - child: Center( - child: Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Text( - widget.duration, - style: TextStyle( - color: Colors.grey[300], - fontFamily: 'GM', - fontSize: 18, - ), - ), - ), - ), - ), - ), - Container( - width: 350, - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFF2A2A2A), - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: Colors.grey.withOpacity(0.1), - ), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: Offset(0, 4), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Image.asset( - widget.selectedServerLogo, - width: 40, - ), - SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.selectedServer, - style: TextStyle( - color: Colors.grey[300], - fontFamily: 'GM', - fontSize: 16, - ), - ), - SizedBox(height: 8), - _buildIpButton(), - ], - ), - ], - ), - Divider(color: Colors.grey.withOpacity(0.1)), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _buildStatColumn( - icon: Icons.data_usage_rounded, - download: formatBytes(widget.downloadSpeed), - upload: formatBytes(widget.uploadSpeed), - ), - _buildStatColumn( - icon: Icons.wifi_rounded, - download: formatSpeedBytes(widget.download), - upload: formatSpeedBytes(widget.upload), - ), - ], - ), - ), - ], - ), - ), - ], - ); - } - - String formatBytes(int bytes) { - if (bytes <= 0) return '0Byte'; - - const int kb = 1024; - const int mb = kb * 1024; - const int gb = mb * 1024; - - if (bytes < kb) return '$bytes Byte${bytes > 1 ? 's' : ''}'; - if (bytes < mb) return '${(bytes / kb).toStringAsFixed(2)}KB'; - if (bytes < gb) return '${(bytes / mb).toStringAsFixed(2)}MB'; - return '${(bytes / gb).toStringAsFixed(2)}GB'; - } - - String formatSpeedBytes(int bytes) { - if (bytes <= 0) return '0byte/s'; - - const int kb = 1024; - const int mb = kb * 1024; - const int gb = mb * 1024; - - if (bytes < kb) return '${bytes}byte/s'; - if (bytes < mb) return '${(bytes / kb).toStringAsFixed(2)}KB/s'; - if (bytes < gb) return '${(bytes / mb).toStringAsFixed(2)}MB/s'; - return '${(bytes / gb).toStringAsFixed(2)}GB/s'; - } - - Widget _buildIpButton() { - return Container( - decoration: BoxDecoration( - color: const Color(0xFF353535), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: Colors.white.withOpacity(0.1), - ), - ), - child: Material( - color: Colors.transparent, - child: InkWell( - borderRadius: BorderRadius.circular(12), - onTap: () async { - setState(() => isLoading = true); - final ipInfo = await getIpApi(); - setState(() { - ipflag = countryCodeToFlagEmoji(ipInfo['countryCode']!); - ipText = ipInfo['ip']; - isLoading = false; - }); - }, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (isLoading) - SizedBox( - width: 16, - height: 16, - child: CircularProgressIndicator( - strokeWidth: 2, - valueColor: AlwaysStoppedAnimation(Colors.grey[400]), - ), - ) - else ...[ - Text( - ipText ?? 'check_ip_button'.tr(), - style: TextStyle( - color: Colors.grey[300], - fontFamily: 'GM', - fontSize: 13, - ), - ), - if (ipflag != null) ...[ - SizedBox(width: 6), - Text( - ipflag!, - style: const TextStyle( - fontFamily: 'GoogeFontEmoji', - fontSize: 16, - ), - ), - ], - ], - ], - ), - ), - ), - ), - ); - } - - Widget _buildStatColumn({ - required IconData icon, - required String download, - required String upload, - }) { - return Row( - children: [ - Icon( - icon, - color: Colors.green[400], - size: 20, - ), - SizedBox(width: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "⬇️ $download", - style: TextStyle( - color: Colors.grey[300], - fontFamily: 'GM', - fontSize: 13, - ), - ), - Text( - "⬆️ $upload", - style: TextStyle( - color: Colors.grey[300], - fontFamily: 'GM', - fontSize: 13, - ), - ), - ], - ), - ], - ); - } -} - -String countryCodeToFlagEmoji(String countryCode) { - countryCode = countryCode.toUpperCase(); - final flag = countryCode.codeUnits - .map((codeUnit) => String.fromCharCode(0x1F1E6 + codeUnit - 0x41)) - .join(); - - return Text( - flag, - style: const TextStyle( - fontFamily: 'GoogeFontEmoji', - fontSize: 16, - ), - ).data ?? - flag; -} - -Future> getIpApi() async { - try { - - final dio = Dio(); - - dio.httpClientAdapter = IOHttpClientAdapter() - ..createHttpClient = () { - final client = HttpClient(); - client.findProxy = (uri) { - return 'PROXY 127.0.0.1:8569'; - }; - return client; - }; - - final response = await dio.get( - 'https://freeipapi.com/api/json', - options: Options( - followRedirects: true, - validateStatus: (status) => true, - receiveTimeout: const Duration(seconds: 10), - ), - ); - - if (response.statusCode == 200) { - final data = response.data; - if (data != null && data is Map) { - String ip = data['ipAddress'] ?? 'Unknown IP'; - - if (ip.contains('.')) { // IPv4 - final parts = ip.split('.'); - if (parts.length == 4) { - ip = '${parts[0]}.*.*.${parts[3]}'; - } - } else if (ip.contains(':')) { // IPv6 - final parts = ip.split(':'); - if (parts.length > 4) { - ip = '${parts[0]}:${parts[1]}:****:${parts.last}'; - } - } - - return { - 'countryCode': data['countryCode'] ?? 'Unknown', - 'ip': ip - }; - } - } - - return {'countryCode': 'Unknown', 'ip': 'Unknown IP'}; - } catch (e) { - print('Error getting IP info: $e'); - return {'countryCode': 'Error', 'ip': 'Error'}; - } -} diff --git a/pubspec.lock b/pubspec.lock index 25e0298..d868b30 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -84,10 +84,10 @@ packages: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.18.0" convert: dependency: transitive description: @@ -328,18 +328,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -592,7 +592,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_span: dependency: transitive description: @@ -605,10 +605,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.11.1" stream_channel: dependency: transitive description: @@ -621,10 +621,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.0" synchronized: dependency: transitive description: @@ -645,10 +645,10 @@ packages: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.2" typed_data: dependency: transitive description: @@ -733,10 +733,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.2.5" web: dependency: transitive description: