Browse Source

fix: 调整ui

lilu 1 tháng trước cách đây
mục cha
commit
5d7de8c019
66 tập tin đã thay đổi với 1651 bổ sung533 xóa
  1. 52 0
      README.md
  2. 7 2
      android/app/build.gradle.kts
  3. BIN
      android/app/libs/libxray.aar
  4. BIN
      assets/images/dark/equity1.png
  5. BIN
      assets/images/dark/equity2.png
  6. BIN
      assets/images/dark/equity3.png
  7. BIN
      assets/images/dark/equity4.png
  8. BIN
      assets/images/dark/equity5.png
  9. BIN
      assets/images/dark/equity6.png
  10. BIN
      assets/images/light/equity1.png
  11. BIN
      assets/images/light/equity2.png
  12. BIN
      assets/images/light/equity3.png
  13. BIN
      assets/images/light/equity4.png
  14. BIN
      assets/images/light/equity5.png
  15. BIN
      assets/images/light/equity6.png
  16. BIN
      assets/images/menus.png
  17. 3 0
      assets/vectors/arrow_down_circle_dark.svg
  18. 3 0
      assets/vectors/refresh_circle_dark.svg
  19. 1 0
      lib/app/app.dart
  20. 3 16
      lib/app/constants/api_domains.dart
  21. 33 0
      lib/app/constants/assets.dart
  22. 4 4
      lib/app/constants/configs.dart
  23. 15 0
      lib/app/constants/environment.dart
  24. 111 100
      lib/app/controllers/api_controller.dart
  25. 1 6
      lib/app/dialog/all_dialog.dart
  26. 3 3
      lib/app/dialog/error_dialog.dart
  27. 19 12
      lib/app/modules/feedback/controllers/feedback_controller.dart
  28. 2 0
      lib/app/modules/feedback/views/feedback_view.dart
  29. 5 2
      lib/app/modules/home/controllers/home_controller.dart
  30. 34 23
      lib/app/modules/home/views/home_view.dart
  31. 4 4
      lib/app/modules/home/widgets/connection_theme_button.dart
  32. 30 23
      lib/app/modules/language/controllers/language_controller.dart
  33. 1 1
      lib/app/modules/login/views/login_view.dart
  34. 63 0
      lib/app/modules/notfound/views/notfound_view.dart
  35. 1 1
      lib/app/modules/setting/controllers/setting_controller.dart
  36. 66 65
      lib/app/modules/setting/views/setting_view.dart
  37. 1 1
      lib/app/modules/signup/views/signup_view.dart
  38. 4 4
      lib/app/modules/subscription/controllers/subscription_controller.dart
  39. 232 128
      lib/app/modules/subscription/views/subscription_view.dart
  40. 8 0
      lib/app/routes/app_pages.dart
  41. 13 11
      lib/app/widgets/gradient_circle_header.dart
  42. 14 0
      lib/config/translations/ar_AR/ar_ar_translation.dart
  43. 14 0
      lib/config/translations/de_DE/de_de_translation.dart
  44. 60 27
      lib/config/translations/en_US/en_us_translation.dart
  45. 14 0
      lib/config/translations/es_ES/es_es_translation.dart
  46. 14 0
      lib/config/translations/fa_IR/fa_ir_translation.dart
  47. 14 0
      lib/config/translations/fr_FR/fr_fr_translation.dart
  48. 14 0
      lib/config/translations/hi_IN/hi_in_translation.dart
  49. 14 0
      lib/config/translations/id_ID/id_id_translation.dart
  50. 14 0
      lib/config/translations/ja_JP/ja_jp_translation.dart
  51. 14 0
      lib/config/translations/ko_KR/ko_kr_translation.dart
  52. 96 79
      lib/config/translations/localization_service.dart
  53. 14 0
      lib/config/translations/my_MM/my_mm_translation.dart
  54. 14 0
      lib/config/translations/pt_BR/pt_br_translation.dart
  55. 14 0
      lib/config/translations/ru_RU/ru_ru_translation.dart
  56. 20 0
      lib/config/translations/strings_enum.dart
  57. 14 0
      lib/config/translations/th_TH/th_th_translation.dart
  58. 14 0
      lib/config/translations/tk_TM/tk_tm_translation.dart
  59. 14 0
      lib/config/translations/tl_PH/tl_ph_translation.dart
  60. 14 0
      lib/config/translations/tr_TR/tr_tr_translation.dart
  61. 14 0
      lib/config/translations/vi_VN/vi_vn_translation.dart
  62. 476 0
      lib/config/translations/zh_CN/zh_cn_translation.dart
  63. 14 0
      lib/config/translations/zh_TW/zh_tw_translation.dart
  64. 3 0
      lib/main.dart
  65. 17 16
      lib/utils/api_statistics.dart
  66. 8 5
      lib/utils/log/log_manager.dart

+ 52 - 0
README.md

@@ -1,6 +1,58 @@
 # ixVPN - Flutter VPN 应用
 
 ixVPN 是一个基于 Flutter 开发的跨平台 VPN 应用,支持 Android、iOS、macOS、Windows 和 Linux 平台。
+## build command
+1. 请先确保`util/constants.dart`中`debug[*]`相关配置项的值为`false`
+2. 确认pubspec.yaml 文件中[version]版本号
+3. 执行对应平台的编译命令
+
+flutter run --flavor googleProd --dart-define=ENV=prod --release
+
+flutter run --flavor universalDev --dart-define=ENV=dev --release
+
+flutter run --flavor universalProd --dart-define=ENV=prod --release
+
+flutter run --flavor universalProd --dart-define=ENV=dev --release
+
+https://play.google.com/store/apps/details?id=win.fkey.netboost&referrer=utm_source%3Dtg%26utm_medium%3Dtg
+
+### android:
+编译测试版本:
+`flutter build apk --flavor universalDev --dart-define=ENV=dev --target-platform android-arm,android-arm64 --release`
+
+编译谷歌应用商店版本:
+`flutter build appbundle --flavor googleProd --dart-define=ENV=prod --target-platform android-arm,android-arm64 --release`
+
+编译官网渠道的通用APK版本:
+`flutter build apk --flavor universalProd --dart-define=ENV=prod --target-platform android-arm,android-arm64 --release`
+`flutter build apk --flavor universalProd --dart-define=ENV=dev --target-platform android-arm,android-arm64 --release`
+
+不修改pubspec.yaml中的版本号,编译指定版本号:
+`flutter build appbundle --flavor google --build-name=1.0.1 --build-number=101 --target-platform android-arm,android-arm64 --release`
+
+### ios:
+编译Apple Store版本:
+`flutter build ipa --release`
+
+不修改pubspec.yaml中的版本号,编译指定版本号:
+`flutter build ipa --build-name=1.0.1 --build-number=101 --release`
+
+* 无法打开“idevicesyslog”,因为无法验证开发者
+* 执行`sudo xattr -r -d com.apple.quarantine /Users/xxx/flutter/bin/cache/artifacts/libimobiledevice/idevicesyslog`
+* 无法打开“iproxy”,因为无法验证开发者。
+* 执行`sudo xattr -r -d com.apple.quarantine /Users/xxx/flutter/bin/cache/artifacts/usbmuxd/iproxy`
+
+## 谷歌商店上架流程
+1. 使用appbundle编译命令,编译谷歌商店版本。
+2. 将编译后的`build/app/outputs/bundle/googleRelease/app-google-release.aab`上传至`App bundle`资源管理器。
+3. 在`Google Play Console`创建发布版本。
+
+## 苹果商店上架流程
+1. 使用iOS编译命令编译iOS版本。
+2. 编译完成后,打开`build/ios/archive/Runner.xcarchive`文件。
+3. 在Xcode的Archives列表中选择刚编译的版本,点击 Distribute App上传至苹果商店。
+4. 也可以使用`Apple Transporter`将`build/ios/ipa/*.ipa`文件上传至苹果商店。
+5. 在苹果商店后台创建发布版本。
 
 ## License
 

+ 7 - 2
android/app/build.gradle.kts

@@ -50,13 +50,13 @@ android {
     productFlavors {
         create("googleDev") {
             dimension = "env"
-//            applicationIdSuffix = ".dev"
+           applicationIdSuffix = ".dev"
             resValue("string", "app_name", "NOMO Dev")
             manifestPlaceholders["CHANNEL"] = "google"
         }
         create("universalDev") {
             dimension = "env"
-//            applicationIdSuffix = ".dev"
+           applicationIdSuffix = ".dev"
             resValue("string", "app_name", "NOMO Dev")
             manifestPlaceholders["CHANNEL"] = "universal"
         }
@@ -80,6 +80,11 @@ android {
         jniLibs {
             useLegacyPackaging = true
             keepDebugSymbols += "**/*.so"
+            // 排除 x86 和 x86_64 架构
+            excludes += setOf(
+                "lib/x86/**",
+                "lib/x86_64/**"
+            )
         }
         resources {
             excludes += ":META-INF/LICENSE"

BIN
android/app/libs/libxray.aar


BIN
assets/images/dark/equity1.png


BIN
assets/images/dark/equity2.png


BIN
assets/images/dark/equity3.png


BIN
assets/images/dark/equity4.png


BIN
assets/images/dark/equity5.png


BIN
assets/images/dark/equity6.png


BIN
assets/images/light/equity1.png


BIN
assets/images/light/equity2.png


BIN
assets/images/light/equity3.png


BIN
assets/images/light/equity4.png


BIN
assets/images/light/equity5.png


BIN
assets/images/light/equity6.png


BIN
assets/images/menus.png


+ 3 - 0
assets/vectors/arrow_down_circle_dark.svg

@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10.7895 9.10105L12.1924 10.5039C12.3382 10.6497 12.5196 10.7226 12.7368 10.7226C12.954 10.7226 13.1355 10.6497 13.2813 10.5039C13.4271 10.3583 13.5 10.1746 13.5 9.95289C13.5 9.73096 13.4271 9.54833 13.2813 9.405L10.6558 6.77947C10.4656 6.58912 10.2437 6.49395 9.99 6.49395C9.73614 6.49395 9.51412 6.58912 9.32395 6.77947L6.69842 9.405C6.55263 9.54833 6.47974 9.73096 6.47974 9.95289C6.47974 10.1746 6.55263 10.3583 6.69842 10.5039C6.84421 10.6497 7.02798 10.7226 7.24974 10.7226C7.47149 10.7226 7.65412 10.6497 7.79763 10.5039L9.20053 9.10105V13.1074C9.20053 13.3311 9.27614 13.5185 9.42737 13.6697C9.57877 13.8211 9.7664 13.8968 9.99026 13.8968C10.2139 13.8968 10.4031 13.8211 10.5576 13.6697C10.7122 13.5185 10.7895 13.3311 10.7895 13.1074V9.10105ZM9.99816 0C11.3813 1.2092e-07 12.6814 0.262455 13.8984 0.787367C15.1154 1.31228 16.174 2.02465 17.0742 2.92447C17.9744 3.8243 18.6871 4.88245 19.2124 6.09895C19.7375 7.31544 20 8.61518 20 9.99816C20 11.3813 19.7375 12.6814 19.2126 13.8984C18.6877 15.1154 17.9754 16.174 17.0755 17.0742C16.1757 17.9744 15.1175 18.6871 13.9011 19.2124C12.6846 19.7375 11.3848 20 10.0018 20C8.61868 20 7.31859 19.7375 6.10158 19.2126C4.88456 18.6877 3.82596 17.9753 2.92579 17.0755C2.02561 16.1757 1.31289 15.1175 0.78763 13.9011C0.262542 12.6846 -1.20904e-07 11.3848 0 10.0018C1.20919e-07 8.61868 0.262455 7.31859 0.787367 6.10158C1.31228 4.88456 2.02465 3.82596 2.92447 2.92579C3.8243 2.02561 4.88246 1.31289 6.09895 0.78763C7.31544 0.262543 8.61518 -1.20904e-07 9.99816 0Z" fill="#727272" style="fill:#727272;fill-opacity:1;"/>
+</svg>

+ 3 - 0
assets/vectors/refresh_circle_dark.svg

@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10 15C11.2667 15 12.3667 14.5833 13.3 13.75C14.2333 12.9167 14.7833 11.8833 14.95 10.65C14.9833 10.4667 14.925 10.3125 14.775 10.1875C14.625 10.0625 14.45 10 14.25 10C14.0667 10 13.8958 10.0583 13.7375 10.175C13.5792 10.2917 13.4833 10.4417 13.45 10.625C13.3 11.4417 12.9042 12.125 12.2625 12.675C11.6208 13.225 10.8667 13.5 10 13.5C9.03333 13.5 8.20833 13.1583 7.525 12.475C6.84167 11.7917 6.5 10.9667 6.5 10C6.5 9.03333 6.84167 8.20833 7.525 7.525C8.20833 6.84167 9.03333 6.5 10 6.5H10.075L9.375 7.225C9.24167 7.375 9.17083 7.55 9.1625 7.75C9.15417 7.95 9.225 8.125 9.375 8.275C9.525 8.425 9.70417 8.5 9.9125 8.5C10.1208 8.5 10.3 8.425 10.45 8.275L12.55 6.175C12.65 6.075 12.7 5.95833 12.7 5.825C12.7 5.69167 12.65 5.575 12.55 5.475L10.425 3.35C10.275 3.2 10.1 3.125 9.9 3.125C9.7 3.125 9.525 3.2 9.375 3.35C9.225 3.5 9.15 3.67917 9.15 3.8875C9.15 4.09583 9.225 4.275 9.375 4.425L9.925 5C8.55833 5.03333 7.39583 5.53333 6.4375 6.5C5.47917 7.46667 5 8.63333 5 10C5 11.3833 5.4875 12.5625 6.4625 13.5375C7.4375 14.5125 8.61667 15 10 15ZM10 20C8.61667 20 7.31667 19.7375 6.1 19.2125C4.88333 18.6875 3.825 17.975 2.925 17.075C2.025 16.175 1.3125 15.1167 0.7875 13.9C0.2625 12.6833 0 11.3833 0 10C0 8.61667 0.2625 7.31667 0.7875 6.1C1.3125 4.88333 2.025 3.825 2.925 2.925C3.825 2.025 4.88333 1.3125 6.1 0.7875C7.31667 0.2625 8.61667 0 10 0C11.3833 0 12.6833 0.2625 13.9 0.7875C15.1167 1.3125 16.175 2.025 17.075 2.925C17.975 3.825 18.6875 4.88333 19.2125 6.1C19.7375 7.31667 20 8.61667 20 10C20 11.3833 19.7375 12.6833 19.2125 13.9C18.6875 15.1167 17.975 16.175 17.075 17.075C16.175 17.975 15.1167 18.6875 13.9 19.2125C12.6833 19.7375 11.3833 20 10 20Z" fill="#727272" style="fill:#727272;fill-opacity:1;"/>
+</svg>

+ 1 - 0
lib/app/app.dart

@@ -62,6 +62,7 @@ class App extends StatelessWidget {
       debugShowCheckedModeBanner: Configs.debug,
       backButtonDispatcher: IXBackButtonDispatcher(),
       getPages: AppPages.routes,
+      unknownRoute: AppPages.unknownRoute,
       theme: IXTheme.getThemeData(isLight: true),
       darkTheme: IXTheme.getThemeData(isLight: false),
       themeMode: ReactiveTheme.initialThemeMode,

+ 3 - 16
lib/app/constants/api_domains.dart

@@ -60,32 +60,19 @@ class ApiDomains {
   }
 
   // 默认API URL列表
-  final List<String> _defaultApiUrls = [
-    "https://d2aphju2iq7g2g.cloudfront.net",
-    "https://api.turboaccel.website",
-    "https://d1rvevafipy7o6.cloudfront.net",
-    "https://api.speedboost.website",
-    "https://dqmkongldmyxf.cloudfront.net",
-    "https://api.fastforward.website",
-    "https://d2cvqygi5xlqp3.cloudfront.net",
-    "https://api.odyxighs.com",
-    "https://service.fkey.club",
-  ];
+  final List<String> _defaultApiUrls = [];
 
   // 默认Router URL列表
   final List<String> _defaultRouterUrls = [];
 
   // 默认LOG API URL列表
-  final List<String> _defaultLogUrls = ['https://stat.fkey.win'];
+  final List<String> _defaultLogUrls = [];
 
   // 默认FILE API URL列表
   final List<String> _defaultFileUrls = [];
 
   // 默认备用URL列表(txt文件地址)
-  final List<String> _defaultBackupApiUrls = [
-    'https://drive.google.com/uc?export=download&id=1YMEZiAHPhlAg_xZqD7dSDt0WjlcogwVz',
-    'https://fkey.win/.well-known/backup/backup_fk.data',
-  ];
+  final List<String> _defaultBackupApiUrls = [];
 
   // 当前使用的URL列表
   List<String> _apiUrls = [];

+ 33 - 0
lib/app/constants/assets.dart

@@ -134,7 +134,11 @@ class Assets {
   static const String mediaBg = 'assets/images/media_bg.jpg';
 
   static const String arrowDownCircle = 'assets/vectors/arrow_down_circle.svg';
+  static const String arrowDownCircleDark =
+      'assets/vectors/arrow_down_circle_dark.svg';
   static const String refreshCircle = 'assets/vectors/refresh_circle.svg';
+  static const String refreshCircleDark =
+      'assets/vectors/refresh_circle_dark.svg';
   static const String successCircle = 'assets/vectors/success_circle.svg';
   static const String failedCircle = 'assets/vectors/failed_circle.svg';
 
@@ -168,4 +172,33 @@ class Assets {
       'assets/trayicon/light/connected.ico';
   static const String trayIconLightUnConnectedWin =
       'assets/trayicon/light/unconnected.ico';
+
+  // 权益图标
+  static const String _equity1Dark = 'assets/images/dark/equity1.png';
+  static const String _equity1Light = 'assets/images/light/equity1.png';
+  static const String _equity2Dark = 'assets/images/dark/equity2.png';
+  static const String _equity2Light = 'assets/images/light/equity2.png';
+  static const String _equity3Dark = 'assets/images/dark/equity3.png';
+  static const String _equity3Light = 'assets/images/light/equity3.png';
+  static const String _equity4Dark = 'assets/images/dark/equity4.png';
+  static const String _equity4Light = 'assets/images/light/equity4.png';
+  static const String _equity5Dark = 'assets/images/dark/equity5.png';
+  static const String _equity5Light = 'assets/images/light/equity5.png';
+  static const String _equity6Dark = 'assets/images/dark/equity6.png';
+  static const String _equity6Light = 'assets/images/light/equity6.png';
+
+  static String get equity1 =>
+      ReactiveTheme.isLightTheme ? _equity1Light : _equity1Dark;
+  static String get equity2 =>
+      ReactiveTheme.isLightTheme ? _equity2Light : _equity2Dark;
+  static String get equity3 =>
+      ReactiveTheme.isLightTheme ? _equity3Light : _equity3Dark;
+  static String get equity4 =>
+      ReactiveTheme.isLightTheme ? _equity4Light : _equity4Dark;
+  static String get equity5 =>
+      ReactiveTheme.isLightTheme ? _equity5Light : _equity5Dark;
+  static String get equity6 =>
+      ReactiveTheme.isLightTheme ? _equity6Light : _equity6Dark;
+
+  static const String menus = 'assets/images/menus.png';
 }

+ 4 - 4
lib/app/constants/configs.dart

@@ -2,15 +2,15 @@ class Configs {
   Configs._();
 
   //官网
-  static const String officialWebsiteEmail = "support@fkey.win";
-  static const String officialWebsiteHttp = "https://www.fkey.win";
+  static const String officialWebsiteEmail = "support@nomovpn.com";
+  static const String officialWebsiteHttp = "https://www.znomo.com";
 
   // 调试相关
-  static var debug = true;
+  static var debug = false;
 
   static var assetUrl = "https://res.golink.dev";
 
-  static var websiteUrl = "https://www.fkey.win";
+  static var websiteUrl = "https:/www.znomo.com";
 
   // 内核使用
   static const String appName = 'NOMO VPN';

+ 15 - 0
lib/app/constants/environment.dart

@@ -0,0 +1,15 @@
+import 'configs.dart';
+
+class Environment {
+  static const String dev = 'dev';
+  static const String prod = 'prod';
+
+  static late final String currentEnv;
+  static late final bool isDebug;
+
+  static void initialize() {
+    currentEnv = const String.fromEnvironment("ENV", defaultValue: prod);
+    isDebug = currentEnv == dev;
+    Configs.debug = isDebug;
+  }
+}

+ 111 - 100
lib/app/controllers/api_controller.dart

@@ -98,10 +98,6 @@ class ApiController extends GetxService with WidgetsBindingObserver {
   final _remainTimeFormatted = ''.obs;
   String get remainTimeFormatted => _remainTimeFormatted.value;
 
-  // 是否应该显示倒计时(响应式,只有状态变化时才更新 UI)
-  final _shouldShowCountdown = false.obs;
-  bool get shouldShowCountdown => _shouldShowCountdown.value;
-
   // 倒计时定时器
   Timer? _remainTimeTimer;
 
@@ -129,56 +125,93 @@ class ApiController extends GetxService with WidgetsBindingObserver {
   @override
   void didChangeAppLifecycleState(AppLifecycleState state) {
     log(TAG, "App state: $state");
-    if (state == AppLifecycleState.paused) {
-      isBackground = true;
-      // 记录切换到后台的系统时钟时间戳(不受系统时间修改影响)
-      _backgroundElapsedRealtime = SystemClock.elapsedRealtime().inMilliseconds;
-      ApiStatistics.instance.onAppPaused();
-      stopRemainTimeCountdown();
-    } else if (state == AppLifecycleState.resumed) {
-      if (isBackground) {
-        isBackground = false;
-        ApiStatistics.instance.onAppResumed();
-        // 计算后台经过的时间,继续倒计时
-        _resumeRemainTimeCountdown();
-        int currentTime = NtpTimeService().getCurrentTimestamp();
-        int activeInterval = IXSP.getAppConfig()?.activeInterval ?? 0;
-        if (activeInterval > 0 &&
-            lastActiveTime + activeInterval * 1000 * 60 > currentTime) {
-          return;
-        }
-        lastActiveTime = currentTime;
-        asyncHandleLaunch(isRefreshLaunch: true);
+    try {
+      if (state == AppLifecycleState.paused) {
+        _handleAppPaused();
+      } else if (state == AppLifecycleState.resumed) {
+        _handleAppResumed();
       }
+    } catch (e, s) {
+      log(TAG, "didChangeAppLifecycleState error: $e\n$s");
     }
   }
 
+  /// 处理 App 进入后台
+  void _handleAppPaused() {
+    isBackground = true;
+    // 停止倒计时(同步操作,立即执行)
+    stopRemainTimeCountdown();
+
+    _backgroundElapsedRealtime = SystemClock.elapsedRealtime().inMilliseconds;
+
+    ApiStatistics.instance.onAppPaused();
+  }
+
+  /// 处理 App 回到前台
+  Future<void> _handleAppResumed() async {
+    if (!isBackground) return;
+
+    isBackground = false;
+
+    // 恢复倒计时(同步操作)
+    _resumeRemainTimeCountdown();
+
+    final logs = await ApiStatistics.instance.onAppResumed();
+    if (logs.isNotEmpty) {
+      uploadLogs(logs);
+    }
+
+    // 检查是否需要刷新 launch
+    int currentTime = NtpTimeService().getCurrentTimestamp();
+    int activeInterval = IXSP.getAppConfig()?.activeInterval ?? 0;
+    if (activeInterval > 0 &&
+        lastActiveTime + activeInterval * 1000 * 60 > currentTime) {
+      return;
+    }
+    lastActiveTime = currentTime;
+    asyncHandleLaunch(isRefreshLaunch: true);
+  }
+
   /// 恢复倒计时(从后台切换到前台时调用)
   void _resumeRemainTimeCountdown() {
-    if (_backgroundElapsedRealtime > 0 && _remainTimeSeconds > 0) {
-      // 计算后台经过的秒数(使用系统时钟,不受系统时间修改影响)
-      final currentElapsedRealtime =
-          SystemClock.elapsedRealtime().inMilliseconds;
-      final elapsedSeconds =
-          (currentElapsedRealtime - _backgroundElapsedRealtime) ~/ 1000;
-      // 更新剩余时间
-      final newRemainTime = _remainTimeSeconds - elapsedSeconds;
-      log(
-        TAG,
-        'Resume countdown: elapsed=${elapsedSeconds}s, '
-        'old=$_remainTimeSeconds, new=$newRemainTime',
-      );
-      // 重新启动倒计时
-      if (newRemainTime > 0) {
-        startRemainTimeCountdown(newRemainTime);
-      } else {
-        // 时间已耗尽
-        _remainTimeSeconds = 0;
-        _updateRemainTimeFormatted();
-        _onRemainTimeExpired();
+    try {
+      if (_backgroundElapsedRealtime > 0 && _remainTimeSeconds > 0) {
+        // 计算后台经过的秒数(使用系统时钟,不受系统时间修改影响)
+        int currentElapsedRealtime;
+        try {
+          currentElapsedRealtime = SystemClock.elapsedRealtime().inMilliseconds;
+        } catch (e) {
+          log(TAG, "SystemClock.elapsedRealtime error in resume: $e");
+          // 使用备选方案:直接重启倒计时
+          startRemainTimeCountdown(_remainTimeSeconds);
+          _backgroundElapsedRealtime = 0;
+          return;
+        }
+
+        final elapsedSeconds =
+            (currentElapsedRealtime - _backgroundElapsedRealtime) ~/ 1000;
+        // 更新剩余时间
+        final newRemainTime = _remainTimeSeconds - elapsedSeconds;
+        log(
+          TAG,
+          'Resume countdown: elapsed=${elapsedSeconds}s, '
+          'old=$_remainTimeSeconds, new=$newRemainTime',
+        );
+        // 重新启动倒计时
+        if (newRemainTime > 0) {
+          startRemainTimeCountdown(newRemainTime);
+        } else {
+          // 时间已耗尽
+          _remainTimeSeconds = 0;
+          _updateRemainTimeFormatted();
+          _onRemainTimeExpired();
+        }
       }
+    } catch (e, s) {
+      log(TAG, "_resumeRemainTimeCountdown error: $e\n$s");
+    } finally {
+      _backgroundElapsedRealtime = 0;
     }
-    _backgroundElapsedRealtime = 0;
   }
 
   Future<Fingerprint> initFingerprint() async {
@@ -670,7 +703,7 @@ class ApiController extends GetxService with WidgetsBindingObserver {
         // 获取选中的路由模式
         final routingMode =
             IXSP.getString(SPKeys.routingModeSelected) ?? "smart";
-        request['routingMode'] = routingMode;
+        request['clientConfig'] = {'routingMode': routingMode};
         final result = await ApiRouter().getDispatchInfo(
           request,
           cancelToken: cancelToken,
@@ -1119,7 +1152,15 @@ class ApiController extends GetxService with WidgetsBindingObserver {
         log(TAG, 'uploadMetricsLog error: $e');
       }
       try {
-        await uploadLocalLog(appLog['sessionInfo']?['boostSessionId'] ?? '');
+        final boostSessionId = appLog['sessionInfo']?['boostSessionId'] ?? '';
+        if (boostSessionId.isEmpty) {
+          return;
+        }
+        final errorCode = appLog['sessionInfo']?['errorCode'] ?? -1;
+        if (errorCode <= 0) {
+          return;
+        }
+        await uploadLocalLog(boostSessionId);
       } catch (e) {
         log(TAG, 'uploadLocalLog error: $e');
       }
@@ -1488,51 +1529,30 @@ class ApiController extends GetxService with WidgetsBindingObserver {
     }
   }
 
-  Future<void> uploadApiStatisticsLog(
-    List<Map<String, dynamic>> logs, {
-    LogModule module = LogModule.NM_ApiLaunchLog,
-  }) async {
-    if (isNeedUploadLogs(module)) {
-      await uploadLogs(logs);
-    }
-  }
-
-  // 判断是否需要上传日志
-  bool isNeedUploadLogs(LogModule module) {
-    final launch = IXSP.getLaunch();
-    if (launch == null) {
-      return false;
-    }
-    if (launch.appConfig?.disabledLogModules?.contains(module.name) ?? false) {
-      return false;
-    }
-    return true;
-  }
-
   /// 获取订阅周期类型文本
   /// subscribeType: 1Day 2Week 3Month 4Year
-  String _getSubscribeTypeText() {
-    final user = IXSP.getUser();
-    final planInfo = user?.planInfo;
-
-    // 仅当 isSubscribe=true 时有效
-    if (planInfo?.isSubscribe != true) {
-      return planInfo?.subTitle ?? '';
-    }
-
-    switch (planInfo?.subscribeType) {
-      case 1:
-        return 'Day';
-      case 2:
-        return 'Week';
-      case 3:
-        return 'Month';
-      case 4:
-        return 'Year';
-      default:
-        return '';
-    }
-  }
+  // String _getSubscribeTypeText() {
+  //   final user = IXSP.getUser();
+  //   final planInfo = user?.planInfo;
+
+  //   // 仅当 isSubscribe=true 时有效
+  //   if (planInfo?.isSubscribe != true) {
+  //     return planInfo?.subTitle ?? '';
+  //   }
+
+  //   switch (planInfo?.subscribeType) {
+  //     case 1:
+  //       return 'Day';
+  //     case 2:
+  //       return 'Week';
+  //     case 3:
+  //       return 'Month';
+  //     case 4:
+  //       return 'Year';
+  //     default:
+  //       return '';
+  //   }
+  // }
 
   /// 获取过期时间文本
   String _getExpireTimeText() {
@@ -1598,15 +1618,6 @@ class ApiController extends GetxService with WidgetsBindingObserver {
     if (_remainTimeFormatted.value != newFormatted) {
       _remainTimeFormatted.value = newFormatted;
     }
-
-    // 更新是否显示倒计时的状态
-    final vipRemainNoticeSeconds =
-        (IXSP.getAppConfig()?.vipRemainNotice ?? 600) * 60;
-    final newShouldShow =
-        _remainTimeSeconds > 0 && _remainTimeSeconds < vipRemainNoticeSeconds;
-    if (_shouldShowCountdown.value != newShouldShow) {
-      _shouldShowCountdown.value = newShouldShow;
-    }
   }
 
   /// 停止剩余时间倒计时

+ 1 - 6
lib/app/dialog/all_dialog.dart

@@ -241,7 +241,7 @@ class AllDialog {
   /// 显示订阅网页弹窗
   static void showSubscriptionForWeb(Function() onRefresh) {
     final isLight = ReactiveTheme.isLightTheme;
-    CustomDialog.showError(
+    CustomDialog.showInfo(
       title: Strings.subscriptionForWebTitle.tr,
       message: Strings.subscriptionForWebMessage.tr,
       icon: IconFont.icon23,
@@ -250,16 +250,11 @@ class AllDialog {
           : DarkThemeColors.subscriptionColor,
       titleColor: isLight ? Get.reactiveTheme.primaryColor : null,
       buttonText: Strings.ok.tr,
-      cancelText: Strings.cancel.tr,
       onPressed: () {
         // 处理重试逻辑
         Navigator.of(Get.context!).pop();
         onRefresh();
       },
-      onCancel: () {
-        // 处理取消逻辑
-        Navigator.of(Get.context!).pop();
-      },
     );
   }
 

+ 3 - 3
lib/app/dialog/error_dialog.dart

@@ -71,16 +71,16 @@ class ErrorDialog {
                                 fontWeight: FontWeight.w600,
                               ),
                             ),
-                            8.verticalSpaceFromWidth,
+                            16.verticalSpaceFromWidth,
                             Text(
                               message ?? Strings.unknownError.tr,
                               style: TextStyle(
                                 color: Get.reactiveTheme.hintColor,
-                                fontSize: 12.sp,
+                                fontSize: 14.sp,
                               ),
                               textAlign: TextAlign.start,
                             ),
-                            16.verticalSpaceFromWidth,
+                            24.verticalSpaceFromWidth,
                             SubmitButton(
                               onPressed: () {
                                 Navigator.of(Get.context!).pop();

+ 19 - 12
lib/app/modules/feedback/controllers/feedback_controller.dart

@@ -7,6 +7,7 @@ import '../../../../config/translations/strings_enum.dart';
 import '../../../constants/configs.dart';
 import '../../../constants/enums.dart';
 import '../../../controllers/api_controller.dart';
+import '../../../data/sp/ix_sp.dart';
 
 class FeedbackController extends GetxController {
   final apiController = Get.find<ApiController>();
@@ -93,19 +94,25 @@ class FeedbackController extends GetxController {
     isSubmitting.value = true;
 
     try {
-      await apiController.uploadApiStatisticsLog([
-        {
-          "id": const Uuid().v4(),
-          "time": DateTime.now().millisecondsSinceEpoch,
-          "level": LogLevel.info.name,
-          'module': LogModule.NM_FeedbackLog.name,
-          "category": Configs.productCode,
-          "fields": {
-            'content': feedbackController.text.trim(),
-            'email': emailController.text.trim(),
+      final appConfig = IXSP.getAppConfig();
+
+      if (!((appConfig?.disabledLogModules ?? [])).contains(
+        LogModule.NM_FeedbackLog.name,
+      )) {
+        await apiController.uploadLogs([
+          {
+            "id": const Uuid().v4(),
+            "time": DateTime.now().millisecondsSinceEpoch,
+            "level": LogLevel.info.name,
+            'module': LogModule.NM_FeedbackLog.name,
+            "category": Configs.productCode,
+            "fields": {
+              'content': feedbackController.text.trim(),
+              'email': emailController.text.trim(),
+            },
           },
-        },
-      ]);
+        ]);
+      }
 
       // 提交成功
       IXSnackBar.showIXSnackBar(

+ 2 - 0
lib/app/modules/feedback/views/feedback_view.dart

@@ -144,6 +144,8 @@ class FeedbackView extends BaseView<FeedbackController> {
                       decoration: BoxDecoration(
                         color: isEnabled
                             ? Get.reactiveTheme.primaryColor
+                            : ReactiveTheme.isLightTheme
+                            ? Colors.black.withValues(alpha: 0.1)
                             : Get.reactiveTheme.highlightColor,
                         borderRadius: BorderRadius.circular(12.r),
                         border: Border.all(

+ 5 - 2
lib/app/modules/home/controllers/home_controller.dart

@@ -79,8 +79,11 @@ class HomeController extends BaseController {
     getBanner(position: 'banner');
     // 桌面模式不需要应用内通知
     if (!isDesktop) {
-      AwesomeNotificationsHelper.init();
-      AwesomeNotificationsHelper.showPushNoticeDialog();
+      // 延迟100ms后初始化通知
+      // Future.delayed(const Duration(milliseconds: 100), () {
+      //   AwesomeNotificationsHelper.init();
+      //   AwesomeNotificationsHelper.showPushNoticeDialog();
+      // });
     }
     checkUpdate();
   }

+ 34 - 23
lib/app/modules/home/views/home_view.dart

@@ -5,6 +5,7 @@ import 'package:flutter/material.dart' hide ConnectionState;
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
 import 'package:nomo/app/constants/iconfont/iconfont.dart';
+import 'package:nomo/app/data/sp/ix_sp.dart';
 import 'package:nomo/app/extensions/widget_extension.dart';
 import 'package:nomo/utils/misc.dart';
 import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
@@ -104,11 +105,15 @@ class HomeView extends BaseView<HomeController> {
                                       if (controller.bannerList.isEmpty) {
                                         return SizedBox.shrink();
                                       }
+                                      // 当前宽度 * 0.212
+                                      final height =
+                                          MediaQuery.of(context).size.width *
+                                          0.212;
                                       return Stack(
                                         children: [
                                           CarouselSlider(
                                             options: CarouselOptions(
-                                              height: 80.w,
+                                              height: height,
                                               viewportFraction: 1.0,
                                               autoPlay:
                                                   controller.bannerList.length >
@@ -137,7 +142,7 @@ class HomeView extends BaseView<HomeController> {
                                                               banner.img ?? '',
                                                           width:
                                                               double.infinity,
-                                                          height: 80.w,
+                                                          height: height,
                                                           sourceType:
                                                               ImageSourceType
                                                                   .network,
@@ -242,23 +247,32 @@ class HomeView extends BaseView<HomeController> {
               ? LightThemeColors.homeFreeColor
               : DarkThemeColors.homeFreeColor;
 
+          // 获取 vipRemainNotice 配置
+          final vipRemainNotice =
+              (IXSP.getAppConfig()?.vipRemainNotice ?? 0) * 60;
+          final remainTimeSeconds = controller.apiController.remainTimeSeconds;
+          // 只有当剩余时间 > 0 且 < vipRemainNotice 时才显示提醒
+          final showReminder =
+              remainTimeSeconds > 0 && remainTimeSeconds < vipRemainNotice;
+
           return ClickOpacity(
             onTap: () => Get.toNamed(Routes.SUBSCRIPTION),
             child: Stack(
               children: [
-                Container(
-                  height: 28.w,
-                  padding: EdgeInsets.only(left: 32.w, right: 8.w),
-                  alignment: Alignment.center,
-                  margin: controller.apiController.userLevel == 3
-                      ? EdgeInsets.only(left: 64.w)
-                      : EdgeInsets.only(left: 36.w),
-                  decoration: BoxDecoration(
-                    borderRadius: BorderRadius.circular(100.r),
-                    color: bgColor,
+                if (showReminder)
+                  Container(
+                    height: 28.w,
+                    padding: EdgeInsets.only(left: 32.w, right: 8.w),
+                    alignment: Alignment.center,
+                    margin: controller.apiController.userLevel == 3
+                        ? EdgeInsets.only(left: 64.w)
+                        : EdgeInsets.only(left: 36.w),
+                    decoration: BoxDecoration(
+                      borderRadius: BorderRadius.circular(100.r),
+                      color: bgColor,
+                    ),
+                    child: _buildReminder(),
                   ),
-                  child: _buildReminder(),
-                ),
                 Obx(
                   () => IXImage(
                     source: controller.apiController.userLevel == 3
@@ -288,10 +302,11 @@ class HomeView extends BaseView<HomeController> {
               top: 10.w,
               bottom: 10.w,
             ),
-            child: Icon(
-              IconFont.icon09,
-              size: 26.w,
-              color: Get.reactiveTheme.hintColor,
+            child: IXImage(
+              source: Assets.menus,
+              width: 26.w,
+              height: 26.w,
+              sourceType: ImageSourceType.asset,
             ),
           ),
           onTap: () {
@@ -327,11 +342,7 @@ class HomeView extends BaseView<HomeController> {
     // );
 
     return Obx(() {
-      // 只监听 shouldShowCountdown 和 remainTimeFormatted
-      // 只有文案或显示状态变化时才更新 UI
-      if (!controller.apiController.shouldShowCountdown) {
-        return const SizedBox.shrink();
-      }
+      // 只有文案变化时才更新 UI
       final textColor = controller.apiController.userLevel == 3
           ? ReactiveTheme.isLightTheme
                 ? LightThemeColors.homePremiumTextColor

+ 4 - 4
lib/app/modules/home/widgets/connection_theme_button.dart

@@ -22,7 +22,7 @@ class ConnectingBorderPainter extends CustomPainter {
   void paint(Canvas canvas, Size size) {
     final center = Offset(size.width / 2, size.height / 2);
     final radius = size.width / 2 - 1;
-    const strokeWidth = 2.0;
+    const strokeWidth = 3.0;
 
     final rect = Rect.fromCircle(center: center, radius: radius);
 
@@ -253,8 +253,8 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
           ),
           // 内层背景圆(遮住边框内侧)
           Container(
-            width: size - 4.w,
-            height: size - 4.w,
+            width: size - 6.w,
+            height: size - 6.w,
             decoration: BoxDecoration(
               color: Get.reactiveTheme.highlightColor,
               shape: BoxShape.circle,
@@ -282,7 +282,7 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
             shape: BoxShape.circle,
             border: Border.all(
               color: Get.reactiveTheme.dividerColor,
-              width: 2.w,
+              width: 3.w,
             ),
             boxShadow: [
               BoxShadow(

+ 30 - 23
lib/app/modules/language/controllers/language_controller.dart

@@ -21,34 +21,41 @@ class LanguageController extends GetxController {
   // 支持的语言列表
   final List<LanguageInfo> languages = [
     LanguageInfo(code: 'en', name: 'English', nativeName: '英语'),
-    LanguageInfo(code: 'es', name: 'Español', nativeName: '西班牙语'),
-    LanguageInfo(code: 'fr', name: 'Français', nativeName: '法语'),
-    LanguageInfo(code: 'de', name: 'Deutsch', nativeName: '德语'),
-    LanguageInfo(code: 'ja', name: '日本語', nativeName: '日语'),
-    LanguageInfo(code: 'ko', name: '한국어', nativeName: '韩语'),
-    LanguageInfo(code: 'fa', name: 'فارسی', nativeName: '波斯语'),
-    LanguageInfo(code: 'my', name: 'မြန်မာဘာသာ', nativeName: '缅甸语'),
-    LanguageInfo(code: 'ar', name: 'عربي', nativeName: '阿拉伯语'),
-    LanguageInfo(code: 'ru', name: 'Русский', nativeName: '俄语'),
-    LanguageInfo(code: 'zh', name: '繁體中文', nativeName: '繁体中文'),
-    LanguageInfo(code: 'tk', name: 'Türkmençe', nativeName: '土库曼语'),
-    LanguageInfo(
-      code: 'pt',
-      name: 'Português (Brasil)',
-      nativeName: '葡萄牙语 (巴西)',
-    ),
-    LanguageInfo(code: 'vi', name: 'Tiếng Việt', nativeName: '越南语'),
-    LanguageInfo(code: 'id', name: 'Bahasa Indonesia', nativeName: '印尼语'),
-    LanguageInfo(code: 'tl', name: 'Filipino', nativeName: '菲律宾语'),
-    LanguageInfo(code: 'th', name: 'ไทย', nativeName: '泰语'),
-    LanguageInfo(code: 'hi', name: 'हिन्दी', nativeName: '印地语'),
-    LanguageInfo(code: 'tr', name: 'Türkçe', nativeName: '土耳其语'),
+    // LanguageInfo(code: 'es', name: 'Español', nativeName: '西班牙语'),
+    // LanguageInfo(code: 'fr', name: 'Français', nativeName: '法语'),
+    // LanguageInfo(code: 'de', name: 'Deutsch', nativeName: '德语'),
+    // LanguageInfo(code: 'ja', name: '日本語', nativeName: '日语'),
+    // LanguageInfo(code: 'ko', name: '한국어', nativeName: '韩语'),
+    // LanguageInfo(code: 'fa', name: 'فارسی', nativeName: '波斯语'),
+    // LanguageInfo(code: 'my', name: 'မြန်မာဘာသာ', nativeName: '缅甸语'),
+    // LanguageInfo(code: 'ar', name: 'عربي', nativeName: '阿拉伯语'),
+    // LanguageInfo(code: 'ru', name: 'Русский', nativeName: '俄语'),
+    LanguageInfo(code: 'zh_CN', name: '简体中文', nativeName: '简体中文'),
+    // LanguageInfo(code: 'zh_TW', name: '繁體中文', nativeName: '繁体中文'),
+    // LanguageInfo(code: 'tk', name: 'Türkmençe', nativeName: '土库曼语'),
+    // LanguageInfo(
+    //   code: 'pt',
+    //   name: 'Português (Brasil)',
+    //   nativeName: '葡萄牙语 (巴西)',
+    // ),
+    // LanguageInfo(code: 'vi', name: 'Tiếng Việt', nativeName: '越南语'),
+    // LanguageInfo(code: 'id', name: 'Bahasa Indonesia', nativeName: '印尼语'),
+    // LanguageInfo(code: 'tl', name: 'Filipino', nativeName: '菲律宾语'),
+    // LanguageInfo(code: 'th', name: 'ไทย', nativeName: '泰语'),
+    // LanguageInfo(code: 'hi', name: 'हिन्दी', nativeName: '印地语'),
+    // LanguageInfo(code: 'tr', name: 'Türkçe', nativeName: '土耳其语'),
   ];
 
   @override
   void onInit() {
     super.onInit();
-    selectedLanguage.value = LocalizationService.getCurrentLocal().languageCode;
+    final locale = LocalizationService.getCurrentLocal();
+    // 中文需要区分简体和繁体
+    if (locale.languageCode == 'zh') {
+      selectedLanguage.value = locale.countryCode == 'TW' ? 'zh_TW' : 'zh_CN';
+    } else {
+      selectedLanguage.value = locale.languageCode;
+    }
   }
 
   /// 选择语言

+ 1 - 1
lib/app/modules/login/views/login_view.dart

@@ -88,7 +88,7 @@ class LoginView extends BaseView<LoginController> {
                 enabled: controller.isLogin,
                 onPressed: controller.handleSignUp,
               ),
-              10.verticalSpaceFromWidth,
+              20.verticalSpaceFromWidth,
               // 底部注册链接
               Center(
                 child: RichText(

+ 63 - 0
lib/app/modules/notfound/views/notfound_view.dart

@@ -0,0 +1,63 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import '../../../../config/translations/strings_enum.dart';
+import '../../../constants/assets.dart';
+import '../../../widgets/ix_app_bar.dart';
+
+class NotFoundView extends StatelessWidget {
+  const NotFoundView({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      backgroundColor: Get.reactiveTheme.scaffoldBackgroundColor,
+      appBar: IXAppBar(title: '404'),
+      body: Center(
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Image.asset(Assets.oops, width: 200.w, height: 200.w),
+            24.verticalSpace,
+            Text(
+              Strings.oops.tr,
+              style: TextStyle(
+                fontSize: 24.sp,
+                fontWeight: FontWeight.w600,
+                color: Get.reactiveTheme.textTheme.bodyLarge!.color,
+              ),
+            ),
+            16.verticalSpace,
+            Padding(
+              padding: EdgeInsets.symmetric(horizontal: 32.w),
+              child: Text(
+                Strings.pageNotFound.tr,
+                textAlign: TextAlign.center,
+                style: TextStyle(
+                  fontSize: 14.sp,
+                  color: Get.reactiveTheme.hintColor,
+                ),
+              ),
+            ),
+            32.verticalSpace,
+            ElevatedButton(
+              onPressed: () => Get.offAllNamed('/home'),
+              style: ElevatedButton.styleFrom(
+                backgroundColor: Get.reactiveTheme.primaryColor,
+                padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 12.w),
+                shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(8.r),
+                ),
+              ),
+              child: Text(
+                Strings.backToHome.tr,
+                style: TextStyle(fontSize: 14.sp, color: Colors.white),
+              ),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 1 - 1
lib/app/modules/setting/controllers/setting_controller.dart

@@ -35,7 +35,7 @@ class SettingController extends GetxController {
   void onInit() {
     super.onInit();
     initThemeMode();
-    _initPushNotifications();
+    // _initPushNotifications();
     _getVersion();
   }
 

+ 66 - 65
lib/app/modules/setting/views/setting_view.dart

@@ -1,6 +1,5 @@
 import 'dart:io';
 
-import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
@@ -126,40 +125,42 @@ class SettingView extends BaseView<SettingController> {
           ),
           child: Column(
             children: [
-              _buildSettingItem(
-                icon: IconFont.icon29,
-                iconColor: Get.reactiveTheme.shadowColor,
-                title: _getUserAccount().isNotEmpty
-                    ? _getUserAccount()
-                    : Strings.account.tr,
-                trailing: Row(
-                  children: [
-                    IXImage(
-                      source: controller.apiController.userLevel == 3
-                          ? controller.apiController.remainTimeSeconds > 0
-                                ? Assets.premium
-                                : Assets.premiumExpired
-                          : controller.apiController.userLevel == 9999
-                          ? Assets.test
-                          : Assets.free,
-                      width: controller.apiController.userLevel == 3
-                          ? 92.w
-                          : 64.w,
-                      height: 28.w,
-                      sourceType: ImageSourceType.asset,
-                    ),
-                    4.horizontalSpace,
-                    Icon(
-                      IconFont.icon02,
-                      size: 20.w,
-                      color: Get.reactiveTheme.hintColor,
-                    ),
-                  ],
+              if (!controller.apiController.isGuest ||
+                  controller.apiController.isPremium)
+                _buildSettingItem(
+                  icon: IconFont.icon29,
+                  iconColor: Get.reactiveTheme.shadowColor,
+                  title: _getUserAccount().isNotEmpty
+                      ? _getUserAccount()
+                      : Strings.account.tr,
+                  trailing: Row(
+                    children: [
+                      IXImage(
+                        source: controller.apiController.userLevel == 3
+                            ? controller.apiController.remainTimeSeconds > 0
+                                  ? Assets.premium
+                                  : Assets.premiumExpired
+                            : controller.apiController.userLevel == 9999
+                            ? Assets.test
+                            : Assets.free,
+                        width: controller.apiController.userLevel == 3
+                            ? 92.w
+                            : 64.w,
+                        height: 28.w,
+                        sourceType: ImageSourceType.asset,
+                      ),
+                      4.horizontalSpace,
+                      Icon(
+                        IconFont.icon02,
+                        size: 20.w,
+                        color: Get.reactiveTheme.hintColor,
+                      ),
+                    ],
+                  ),
+                  onTap: () {
+                    Get.toNamed(Routes.ACCOUNT);
+                  },
                 ),
-                onTap: () {
-                  Get.toNamed(Routes.ACCOUNT);
-                },
-              ),
               _buildDivider(),
               _buildSettingItem(
                 icon: IconFont.icon14,
@@ -525,37 +526,37 @@ class SettingView extends BaseView<SettingController> {
               },
             ),
             // 桌面版本不显示通知
-            if (!isDesktop) ...[
-              _buildDivider(),
-              _buildSettingItem(
-                svgPath: Assets.pushNotifications,
-                iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
-                iconGradient: LinearGradient(
-                  colors: [
-                    DarkThemeColors.settingAppLinearGradientStartColor,
-                    DarkThemeColors.settingAppLinearGradientEndColor,
-                  ],
-                  begin: Alignment.topCenter,
-                  end: Alignment.bottomCenter,
-                ),
-                title: Strings.pushNotifications.tr,
-                trailing: Obx(
-                  () => CupertinoSwitch(
-                    value: controller.pushNotifications,
-                    onChanged: (value) {
-                      controller.showNotificationConfigPage();
-                    },
-                    activeTrackColor: Get.reactiveTheme.shadowColor,
-                    thumbColor: Colors.white,
-                    inactiveThumbColor: Colors.white,
-                    inactiveTrackColor: Colors.grey,
-                  ),
-                ),
-                onTap: () {
-                  controller.showNotificationConfigPage();
-                },
-              ),
-            ],
+            // if (!isDesktop) ...[
+            //   _buildDivider(),
+            //   _buildSettingItem(
+            //     svgPath: Assets.pushNotifications,
+            //     iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
+            //     iconGradient: LinearGradient(
+            //       colors: [
+            //         DarkThemeColors.settingAppLinearGradientStartColor,
+            //         DarkThemeColors.settingAppLinearGradientEndColor,
+            //       ],
+            //       begin: Alignment.topCenter,
+            //       end: Alignment.bottomCenter,
+            //     ),
+            //     title: Strings.pushNotifications.tr,
+            //     trailing: Obx(
+            //       () => CupertinoSwitch(
+            //         value: controller.pushNotifications,
+            //         onChanged: (value) {
+            //           controller.showNotificationConfigPage();
+            //         },
+            //         activeTrackColor: Get.reactiveTheme.shadowColor,
+            //         thumbColor: Colors.white,
+            //         inactiveThumbColor: Colors.white,
+            //         inactiveTrackColor: Colors.grey,
+            //       ),
+            //     ),
+            //     onTap: () {
+            //       controller.showNotificationConfigPage();
+            //     },
+            //   ),
+            // ],
             _buildDivider(),
             _buildSettingItem(
               icon: IconFont.icon39,

+ 1 - 1
lib/app/modules/signup/views/signup_view.dart

@@ -87,7 +87,7 @@ class SignupView extends BaseView<SignupController> {
                 enabled: controller.isSignup,
                 onPressed: controller.handleSignUp,
               ),
-              10.verticalSpaceFromWidth,
+              20.verticalSpaceFromWidth,
               // 底部注册链接
               Center(
                 child: RichText(

+ 4 - 4
lib/app/modules/subscription/controllers/subscription_controller.dart

@@ -22,7 +22,7 @@ import '../../../dialog/loading/loading_dialog.dart';
 
 class SubscriptionController extends GetxController {
   static const String TAG = 'SubscriptionController';
-  final ApiController _apiController = Get.find<ApiController>();
+  final ApiController apiController = Get.find<ApiController>();
   // 内购工具实例
   final InAppPurchaseUtil _iapUtil = InAppPurchaseUtil.instance;
 
@@ -176,7 +176,7 @@ class SubscriptionController extends GetxController {
   Future<void> _getChannelPlanList() async {
     isLoadingPlans.value = true;
     try {
-      final plans = await _apiController.getChannelPlanList();
+      final plans = await apiController.getChannelPlanList();
       channelPlans.value = plans;
 
       // 设置默认选中项
@@ -204,7 +204,7 @@ class SubscriptionController extends GetxController {
         successText: 'Purchase successful',
         onRequest: () async {
           // 执行你的异步请求
-          await _apiController.subscribe({
+          await apiController.subscribe({
             'channelItemId': selectedPlan?.channelItemId,
           });
         },
@@ -216,7 +216,7 @@ class SubscriptionController extends GetxController {
     } else if (selectedPlan?.payoutType == 'web') {
       SystemHelper.openWebPage(selectedPlan?.payoutData ?? '');
       AllDialog.showSubscriptionForWeb(() {
-        _apiController.refreshLaunch();
+        apiController.refreshLaunch();
       });
     }
   }

+ 232 - 128
lib/app/modules/subscription/views/subscription_view.dart

@@ -1,9 +1,9 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/constants/iconfont/iconfont.dart';
 import 'package:nomo/config/theme/dark_theme_colors.dart';
 import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:shimmer/shimmer.dart';
 import 'package:video_player/video_player.dart';
 import '../../../../config/theme/light_theme_colors.dart';
 import '../../../../config/translations/strings_enum.dart';
@@ -80,9 +80,8 @@ class SubscriptionView extends GetView<SubscriptionController> {
                         24.verticalSpaceFromWidth,
                         _buildPlanOptions(),
                         // 仅 userLevel == 3 时显示套餐变更信息
-                        if (controller.showPlanChangeInfo)
-                          _buildPlanChangeInfo(),
-                        16.verticalSpaceFromWidth,
+                        // if (controller.showPlanChangeInfo)
+                        //   _buildPlanChangeInfo(),
                         _buildPremiumFeatures(),
                         16.verticalSpaceFromWidth,
                       ],
@@ -216,27 +215,45 @@ class SubscriptionView extends GetView<SubscriptionController> {
     return Obx(() {
       // 加载中状态
       if (controller.isLoadingPlans.value) {
-        return Padding(
-          padding: EdgeInsets.symmetric(vertical: 40.w),
-          child: Center(
-            child: CircularProgressIndicator(
-              color: DarkThemeColors.subscriptionColor,
-            ),
-          ),
+        return Column(
+          children: List.generate(3, (index) => _buildPlanShimmer()),
         );
       }
 
       // 空数据状态
       if (controller.planCount == 0) {
         return Padding(
-          padding: EdgeInsets.symmetric(vertical: 40.w),
+          padding: EdgeInsets.all(20.w),
           child: Center(
-            child: Text(
-              '暂无可用套餐',
-              style: TextStyle(
-                fontSize: 14.sp,
-                color: DarkThemeColors.hintTextColor,
-              ),
+            child: Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                Image.asset(Assets.oops, width: 170.w, height: 170.w),
+                10.verticalSpaceFromWidth,
+                Text(
+                  Strings.oops.tr,
+                  style: TextStyle(
+                    fontSize: 22.sp,
+                    fontWeight: FontWeight.w400,
+                    height: 1.3,
+                    color: Get.reactiveTheme.textTheme.bodyLarge!.color,
+                  ),
+                ),
+                4.verticalSpace,
+                Padding(
+                  padding: EdgeInsets.symmetric(horizontal: 32.w),
+                  child: Text(
+                    Strings.connectionIssueDetected.tr,
+                    textAlign: TextAlign.center,
+                    style: TextStyle(
+                      fontSize: 14.sp,
+                      height: 1.4,
+                      color: Get.reactiveTheme.hintColor,
+                    ),
+                  ),
+                ),
+              ],
             ),
           ),
         );
@@ -252,6 +269,68 @@ class SubscriptionView extends GetView<SubscriptionController> {
     });
   }
 
+  Widget _buildPlanShimmer() {
+    final baseColor = ReactiveTheme.isLightTheme
+        ? Colors.grey[300]!
+        : Colors.grey[700]!;
+    final highlightColor = ReactiveTheme.isLightTheme
+        ? Colors.grey[100]!
+        : Colors.grey[600]!;
+
+    return Container(
+      margin: EdgeInsets.only(bottom: 18.w),
+      decoration: BoxDecoration(
+        color: Get.reactiveTheme.cardColor,
+        borderRadius: BorderRadius.circular(12.r),
+        border: Border.all(color: Get.reactiveTheme.dividerColor, width: 2.w),
+      ),
+      child: Shimmer.fromColors(
+        baseColor: baseColor,
+        highlightColor: highlightColor,
+        child: Padding(
+          padding: EdgeInsets.all(10.w),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            children: [
+              // 左侧:模拟价格信息
+              Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Container(
+                    width: 120.w,
+                    height: 18.w,
+                    decoration: BoxDecoration(
+                      color: Colors.white,
+                      borderRadius: BorderRadius.circular(4.r),
+                    ),
+                  ),
+                  8.verticalSpace,
+                  Container(
+                    width: 80.w,
+                    height: 14.w,
+                    decoration: BoxDecoration(
+                      color: Colors.white,
+                      borderRadius: BorderRadius.circular(4.r),
+                    ),
+                  ),
+                ],
+              ),
+              // 右侧:模拟标题
+              Container(
+                width: 60.w,
+                height: 16.w,
+                decoration: BoxDecoration(
+                  color: Colors.white,
+                  borderRadius: BorderRadius.circular(4.r),
+                ),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+
   Widget _buildPlanItem(int index) {
     return Obx(() {
       final isSelected = controller.selectedPlanIndex.value == index;
@@ -270,7 +349,7 @@ class SubscriptionView extends GetView<SubscriptionController> {
             border: Border.all(
               color: isSelected
                   ? DarkThemeColors.subscriptionColor
-                  : Get.reactiveTheme.cardColor,
+                  : Get.reactiveTheme.dividerColor,
               width: 2.w,
             ),
           ),
@@ -320,32 +399,32 @@ class SubscriptionView extends GetView<SubscriptionController> {
                             color: Get.reactiveTheme.textTheme.bodyLarge!.color,
                           ),
                         ),
-                        8.horizontalSpace,
-                        Container(
-                          width: 20.w,
-                          height: 20.w,
-                          decoration: BoxDecoration(
-                            shape: BoxShape.circle,
-                            border: Border.all(
-                              color: isSelected
-                                  ? DarkThemeColors.primaryColor
-                                  : ReactiveTheme.isLightTheme
-                                  ? LightThemeColors.strokes1
-                                  : Colors.white30,
-                              width: 1.5.w,
-                            ),
-                            color: isSelected
-                                ? DarkThemeColors.primaryColor
-                                : Colors.transparent,
-                          ),
-                          child: isSelected
-                              ? Icon(
-                                  Icons.check,
-                                  color: Colors.white,
-                                  size: 12.w,
-                                )
-                              : null,
-                        ),
+                        // 8.horizontalSpace,
+                        // Container(
+                        //   width: 20.w,
+                        //   height: 20.w,
+                        //   decoration: BoxDecoration(
+                        //     shape: BoxShape.circle,
+                        //     border: Border.all(
+                        //       color: isSelected
+                        //           ? DarkThemeColors.primaryColor
+                        //           : ReactiveTheme.isLightTheme
+                        //           ? LightThemeColors.strokes1
+                        //           : Colors.white30,
+                        //       width: 1.5.w,
+                        //     ),
+                        //     color: isSelected
+                        //         ? DarkThemeColors.primaryColor
+                        //         : Colors.transparent,
+                        //   ),
+                        //   child: isSelected
+                        //       ? Icon(
+                        //           Icons.check,
+                        //           color: Colors.white,
+                        //           size: 12.w,
+                        //         )
+                        //       : null,
+                        // ),
                       ],
                     ),
                   ],
@@ -433,25 +512,47 @@ class SubscriptionView extends GetView<SubscriptionController> {
           ),
           child: Column(
             children: [
-              _buildFeatureItem(
-                IconFont.icon60,
-                Strings.unlockAllFreeLocations.tr,
-              ),
-              _buildFeatureItem(IconFont.icon61, Strings.unlockSmartMode.tr),
-              _buildFeatureItem(IconFont.icon62, Strings.unlockMultiHopMode.tr),
               Obx(
                 () => _buildFeatureItem(
-                  IconFont.icon63,
-                  Strings.premiumCanShareXDevices.trParams({
+                  Assets.equity1,
+                  Strings.equity1Title.trParams({
+                    'count': controller.selectedPlanDeviceLimit,
+                  }),
+                  Strings.equity1Desc.trParams({
                     'count': controller.selectedPlanDeviceLimit,
                   }),
                 ),
               ),
+              Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
+              _buildFeatureItem(
+                Assets.equity2,
+                Strings.equity2Title.tr,
+                Strings.equity2Desc.tr,
+              ),
+              Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
+              _buildFeatureItem(
+                Assets.equity3,
+                Strings.equity3Title.tr,
+                Strings.equity3Desc.tr,
+              ),
+              Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
+              _buildFeatureItem(
+                Assets.equity4,
+                Strings.equity4Title.tr,
+                Strings.equity4Desc.tr,
+              ),
+              Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
               _buildFeatureItem(
-                IconFont.icon64,
-                Strings.ownYourOwnPrivateServer.tr,
+                Assets.equity5,
+                Strings.equity5Title.tr,
+                Strings.equity5Desc.tr,
+              ),
+              Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
+              _buildFeatureItem(
+                Assets.equity6,
+                Strings.equity6Title.tr,
+                Strings.equity6Desc.tr,
               ),
-              _buildFeatureItem(IconFont.icon65, Strings.closeAds.tr),
             ],
           ),
         ),
@@ -459,36 +560,35 @@ class SubscriptionView extends GetView<SubscriptionController> {
     );
   }
 
-  Widget _buildFeatureItem(IconData icon, String title) {
-    return SizedBox(
-      height: 44.w,
+  Widget _buildFeatureItem(String imagePath, String title, String subtitle) {
+    return Padding(
+      padding: EdgeInsets.symmetric(vertical: 10.w),
       child: Row(
         children: [
-          Icon(
-            icon,
-            color: ReactiveTheme.isLightTheme
-                ? LightThemeColors.primaryColor
-                : DarkThemeColors.subscriptionColor,
-            size: 24.w,
-          ),
-          12.horizontalSpace,
+          Image.asset(imagePath, width: 24.w, height: 24.w),
+          16.horizontalSpace,
           Expanded(
-            child: Text(
-              title,
-              style: TextStyle(
-                fontSize: 13.sp,
-                color: Get.reactiveTheme.hintColor,
-              ),
-            ),
-          ),
-          Container(
-            width: 20.w,
-            height: 20.w,
-            decoration: BoxDecoration(
-              shape: BoxShape.circle,
-              color: DarkThemeColors.subscriptionSelectColor,
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Text(
+                  title,
+                  style: TextStyle(
+                    fontSize: 14.sp,
+                    fontWeight: FontWeight.w500,
+                    color: Get.reactiveTheme.textTheme.bodyLarge!.color,
+                  ),
+                ),
+                4.verticalSpace,
+                Text(
+                  subtitle,
+                  style: TextStyle(
+                    fontSize: 12.sp,
+                    color: Get.reactiveTheme.hintColor,
+                  ),
+                ),
+              ],
             ),
-            child: Icon(Icons.check, color: Colors.white, size: 12.w),
           ),
         ],
       ),
@@ -532,59 +632,63 @@ class SubscriptionView extends GetView<SubscriptionController> {
             ),
           ),
           14.verticalSpaceFromWidth,
+
           // 底部链接
-          Row(
-            mainAxisAlignment: MainAxisAlignment.center,
-            children: [
-              GestureDetector(
-                onTap: controller.restorePurchases,
-                child: Text(
-                  Strings.restorePurchases.tr,
-                  style: TextStyle(
-                    fontSize: 16.sp,
-                    color: Get.reactiveTheme.textTheme.bodyLarge!.color,
+          if (controller.apiController.fp.channel == 'google' ||
+              controller.apiController.fp.channel == 'apple') ...[
+            Row(
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                GestureDetector(
+                  onTap: controller.restorePurchases,
+                  child: Text(
+                    Strings.restorePurchases.tr,
+                    style: TextStyle(
+                      fontSize: 16.sp,
+                      color: Get.reactiveTheme.textTheme.bodyLarge!.color,
+                    ),
                   ),
                 ),
-              ),
-              Text(
-                '  |  ',
-                style: TextStyle(
-                  fontSize: 16.sp,
-                  color: Get.reactiveTheme.hintColor,
+                // Text(
+                //   '  |  ',
+                //   style: TextStyle(
+                //     fontSize: 16.sp,
+                //     color: Get.reactiveTheme.hintColor,
+                //   ),
+                // ),
+                // GestureDetector(
+                //   onTap: controller.handlePaymentIssue,
+                //   child: Text(
+                //     Strings.paymentIssue.tr,
+                //     style: TextStyle(
+                //       fontSize: 16.sp,
+                //       color: Get.reactiveTheme.textTheme.bodyLarge!.color,
+                //     ),
+                //   ),
+                // ),
+              ],
+            ),
+            14.verticalSpaceFromWidth,
+            Row(
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                IXImage(
+                  source: Assets.subscriptionGreenShield,
+                  width: 20.w,
+                  height: 20.w,
+                  sourceType: ImageSourceType.asset,
                 ),
-              ),
-              GestureDetector(
-                onTap: controller.handlePaymentIssue,
-                child: Text(
-                  Strings.paymentIssue.tr,
+                10.horizontalSpace,
+                Text(
+                  Strings.yearlyAutoRenewCancelAnytime.tr,
                   style: TextStyle(
-                    fontSize: 16.sp,
-                    color: Get.reactiveTheme.textTheme.bodyLarge!.color,
+                    fontSize: 13.sp,
+                    color: Get.reactiveTheme.hintColor,
                   ),
                 ),
-              ),
-            ],
-          ),
-          14.verticalSpaceFromWidth,
-          Row(
-            mainAxisAlignment: MainAxisAlignment.center,
-            children: [
-              IXImage(
-                source: Assets.subscriptionGreenShield,
-                width: 20.w,
-                height: 20.w,
-                sourceType: ImageSourceType.asset,
-              ),
-              10.horizontalSpace,
-              Text(
-                Strings.yearlyAutoRenewCancelAnytime.tr,
-                style: TextStyle(
-                  fontSize: 13.sp,
-                  color: Get.reactiveTheme.hintColor,
-                ),
-              ),
-            ],
-          ),
+              ],
+            ),
+          ],
         ],
       ),
     );

+ 8 - 0
lib/app/routes/app_pages.dart

@@ -4,6 +4,7 @@ import 'package:get/get.dart';
 
 import '../modules/about/bindings/about_binding.dart';
 import '../modules/about/views/about_view.dart';
+import '../modules/notfound/views/notfound_view.dart';
 import '../modules/account/bindings/account_binding.dart';
 import '../modules/account/views/account_view.dart';
 import '../modules/deviceauth/bindings/deviceauth_binding.dart';
@@ -54,6 +55,13 @@ class AppPages {
   /// 初始路由
   static const initial = Routes.SPLASH;
 
+  /// 未知路由(404页面)
+  static final unknownRoute = GetPage(
+    name: '/notfound',
+    page: () => const NotFoundView(),
+    transition: Transition.fade,
+  );
+
   /// 路由页面列表
   static final routes = [
     GetPage(

+ 13 - 11
lib/app/widgets/gradient_circle_header.dart

@@ -2,6 +2,7 @@ import 'dart:async';
 import 'package:flutter/material.dart'
     hide RefreshIndicatorState, RefreshIndicator;
 import 'package:flutter_svg/flutter_svg.dart';
+import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
 import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
 import '../constants/assets.dart';
 
@@ -16,20 +17,13 @@ class GradientCircleHeader extends RefreshIndicator {
   /// failed content
   final Widget? failed;
 
-  /// idle Icon center in circle
-  final Widget idleIcon;
-
-  GradientCircleHeader({
+  const GradientCircleHeader({
     super.key,
     this.refresh,
     this.complete,
     super.completeDuration = const Duration(milliseconds: 600),
     this.failed,
-    Widget? idleIcon,
-  }) : idleIcon =
-           idleIcon ??
-           SvgPicture.asset(Assets.arrowDownCircle, width: 20, height: 20),
-       super(height: 60.0, refreshStyle: RefreshStyle.UnFollow);
+  }) : super(height: 60.0, refreshStyle: RefreshStyle.UnFollow);
 
   @override
   State<StatefulWidget> createState() {
@@ -315,7 +309,9 @@ class _GradientCircleHeaderState
                     child: RotationTransition(
                       turns: _rotateCtl,
                       child: SvgPicture.asset(
-                        Assets.refreshCircle,
+                        ReactiveTheme.isLightTheme
+                            ? Assets.refreshCircleDark
+                            : Assets.refreshCircle,
                         width: 20,
                         height: 20,
                       ),
@@ -486,7 +482,13 @@ class _GradientCircleHeaderState
                 left: 0,
                 right: 0,
                 top: arrowTopPosition,
-                child: widget.idleIcon,
+                child: SvgPicture.asset(
+                  ReactiveTheme.isLightTheme
+                      ? Assets.arrowDownCircleDark
+                      : Assets.arrowDownCircle,
+                  width: 20,
+                  height: 20,
+                ),
               ),
             ],
           ),

+ 14 - 0
lib/config/translations/ar_AR/ar_ar_translation.dart

@@ -467,4 +467,18 @@ final Map<String, String> arAR = {
   Strings.days: 'أيام',
   Strings.day: 'يوم',
   Strings.hour: 'س',
+
+  // مزايا بريميوم
+  Strings.equity1Title: '@count أجهزة متصلة',
+  Strings.equity1Desc: 'اتصال متزامن لجميع الأجهزة',
+  Strings.equity2Title: 'IP ثابت',
+  Strings.equity2Desc: 'أولوية لعناوين IP المستخدمة سابقاً',
+  Strings.equity3Title: 'سرعة بريميوم',
+  Strings.equity3Desc: 'زمن انتقال منخفض للألعاب وبث 4K',
+  Strings.equity4Title: 'فتح البث',
+  Strings.equity4Desc: 'افتح Netflix و Disney+ والمزيد',
+  Strings.equity5Title: 'الحفاظ على الفترة التجريبية',
+  Strings.equity5Desc: 'تبقى أيام التجربة المتبقية صالحة',
+  Strings.equity6Title: 'بدون إعلانات',
+  Strings.equity6Desc: 'إزالة كاملة لجميع الإعلانات',
 };

+ 14 - 0
lib/config/translations/de_DE/de_de_translation.dart

@@ -473,4 +473,18 @@ const Map<String, String> deDE = {
   Strings.days: 'Tage',
   Strings.day: 'Tag',
   Strings.hour: 'Std',
+
+  // Premium-Vorteile
+  Strings.equity1Title: '@count Geräte Online',
+  Strings.equity1Desc: 'Gleichzeitige Verbindung für alle Geräte',
+  Strings.equity2Title: 'IP-Persistenz',
+  Strings.equity2Desc: 'Priorität für zuvor verwendete IP-Adressen',
+  Strings.equity3Title: 'Premium-Geschwindigkeit',
+  Strings.equity3Desc: 'Niedrige Latenz für Gaming & 4K-Streaming',
+  Strings.equity4Title: 'Streaming Entsperren',
+  Strings.equity4Desc: 'Netflix, Disney+ und mehr entsperren',
+  Strings.equity5Title: 'Testzeit Erhalten',
+  Strings.equity5Desc: 'Verbleibende Testtage bleiben gültig',
+  Strings.equity6Title: 'Werbefrei',
+  Strings.equity6Desc: 'Vollständige Entfernung aller Werbung',
 };

+ 60 - 27
lib/config/translations/en_US/en_us_translation.dart

@@ -12,7 +12,9 @@ Map<String, String> enUs = {
 
   Strings.ok: 'OK',
   Strings.cancel: 'Cancel',
-  Strings.oops: 'Oops',
+  Strings.oops: 'Oops!',
+  Strings.connectionIssueDetected:
+      'Connection issue detected. Please verify your internet access and try again.',
   Strings.copied: 'Copied',
   Strings.later: 'Later',
   Strings.noData: 'No data',
@@ -44,13 +46,13 @@ Map<String, String> enUs = {
   Strings.termsAgreementConnector: ' and ',
 
   // Account page
-  Strings.account: 'Account',
+  Strings.account: 'Current Identity',
 
   // Dialog texts
   Strings.processing: 'Processing...',
   Strings.success: 'Success',
   Strings.unknownError: 'Unknown error',
-  Strings.failed: 'Failed',
+  Strings.failed: 'Connection failed',
 
   // exit
   Strings.exit: 'Exit',
@@ -62,7 +64,7 @@ Map<String, String> enUs = {
   Strings.networkSection: 'Network',
   Strings.securitySection: 'Security',
   Strings.myPreCode: 'My Pre Code',
-  Strings.validTerm: 'Valid Term',
+  Strings.validTerm: 'Expiry Date',
   Strings.freeTime: 'Free Time',
   Strings.deviceAuthorization: 'Device Authorization',
   Strings.routingMode: 'Routing Mode',
@@ -78,7 +80,7 @@ Map<String, String> enUs = {
   Strings.disconnected: 'Disconnected',
   Strings.open: 'Open',
   Strings.disconnect: 'Disconnect',
-  Strings.disconnecting: 'Disconnecting...',
+  Strings.disconnecting: 'Disconnecting',
   Strings.connect: 'Connect',
   Strings.opening: 'Opening',
   Strings.connectedSuccessfully: 'Connected successfully',
@@ -99,7 +101,7 @@ Map<String, String> enUs = {
   Strings.customizeYourVPN: 'Customize your VPN',
 
   // subscription page
-  Strings.subscription: 'Subscription',
+  Strings.subscription: 'Subscribe',
   Strings.currentSubscription: 'Current subscription',
   Strings.upgradeToPremium: 'Upgrade to Premium',
   Strings.activatePreCode: 'Activate Pre Code',
@@ -118,13 +120,13 @@ Map<String, String> enUs = {
   Strings.unlockAllFreeLocations: 'Unlock all free locations',
   Strings.unlockSmartMode: 'Unlock smart mode',
   Strings.unlockMultiHopMode: 'Unlock Multi-hop mode',
-  Strings.premiumCanShareXDevices: 'Premium can share @count devices',
+  Strings.premiumCanShareXDevices: 'Use on @count devices simultaneously',
   Strings.ownYourOwnPrivateServer: 'Own your own private server',
   Strings.closeAds: 'Close ads',
-  Strings.confirmChange: 'Confirm Change',
+  Strings.confirmChange: 'Subscribe',
   Strings.restorePurchases: 'Restore Purchases',
   Strings.paymentIssue: 'Payment issue',
-  Strings.yearlyAutoRenewCancelAnytime: 'Yearly auto-renew. Cancel anytime',
+  Strings.yearlyAutoRenewCancelAnytime: 'Auto-renews, cancel anytime',
 
   // home page
   Strings.recent: 'Recent',
@@ -223,12 +225,12 @@ Map<String, String> enUs = {
       'After the email is sent, we recommend you also save this credential to a secure location on your device.',
 
   // Routing Mode
-  Strings.smart: 'Smart',
+  Strings.smart: 'Smart Mode',
   Strings.smartModeDesc:
-      'The local and VPN networks coexist, and the optimal route is selected intelligently.',
-  Strings.global: 'Global',
+      'Only traffic that needs VPN will use the VPN network.',
+  Strings.global: 'Global Mode',
   Strings.globalModeDesc:
-      'All traffic is routed through the VPN server to ensure maximum privacy and security.',
+      'All traffic uses VPN network for maximum privacy and security.',
 
   // Subscription Plans
   Strings.perYear: 'Per year',
@@ -269,11 +271,11 @@ Map<String, String> enUs = {
   Strings.login: 'Log in',
   Strings.loginButton: 'Log In',
   Strings.loginDescription:
-      'After a successful login, your free trial will be applied, and the remaining membership will be synced to your account for use across all linked devices.',
+      'After logging in, your trial time will not be cleared and will be synced to your account.',
   Strings.signup: 'Sign up to NOMO',
   Strings.signupButton: 'Sign Up',
   Strings.signupDescription:
-      'After registration, your free trial will be deducted, and other membership time shifts to your account for multi-device use.',
+      'After signing up, your trial time will not be cleared and will be synced to your account.',
   Strings.username: 'Username',
   Strings.password: 'Password',
   Strings.usernamePasswordRule: '6-20 characters (letters or numbers)',
@@ -319,14 +321,12 @@ Map<String, String> enUs = {
 
   // Split Tunneling
   Strings.onlyOneModeActive: 'Only one mode can be active at a time.',
-  Strings.chooseAppsExcludeDesc:
-      'Choose apps that will connect directly without using the VPN.',
-  Strings.chooseAppsIncludeDesc:
-      'Choose apps that will use the VPN while others connect normally.',
+  Strings.chooseAppsExcludeDesc: 'Choose apps that will not use VPN.',
+  Strings.chooseAppsIncludeDesc: 'Choose apps that will use VPN.',
   Strings.splitTunnelingDesc:
-      'Split tunneling lets you control which apps use the VPN connection and which connect directly. It helps you manage bandwidth and access local or foreign content without turning off the VPN.',
-  Strings.selectAppsExclude: 'Select apps that will not use the VPN',
-  Strings.selectAppsInclude: 'Select apps that will use the VPN',
+      'Smart split tunneling, only use VPN when accessing foreign websites or apps.',
+  Strings.selectAppsExclude: 'Select apps that will not use VPN',
+  Strings.selectAppsInclude: 'Select apps that will use VPN',
   Strings.deselectAll: 'Deselect all',
   Strings.allApps: 'All apps',
 
@@ -426,12 +426,12 @@ Map<String, String> enUs = {
   Strings.deleteAccountConfirmButton: 'Delete',
 
   // Bind email / Member benefits
-  Strings.bindEmailMemberBenefits: 'Bind account/Member benefits',
+  Strings.bindEmailMemberBenefits: 'Bind registered account',
   Strings.bindingAccountEmailProtectsPreRights:
-      'Binding account/email protects your Pre rights.',
-  Strings.associatedInterests: 'Associated interests',
+      'After members bind to the registered account, they can log in on other devices and share member benefits.',
+  Strings.associatedInterests: 'Bind member benefits',
   Strings.associatedInterestsDesc:
-      'Please note the following subscription rules upon login:\n1. Free Account: The account will inherit the current subscription on this device.\n2. Member Account: The app will switch to that account\'s existing plan.\nNote: The purchase on this device will remain valid.',
+      '1. After registering a Nomo account on this device, the member benefits on the current device will be automatically transferred to your registered account.\n2. Your member account can log in on other devices to share member benefits.',
   Strings.notNow: 'Not now',
 
   // VPN Error Messages
@@ -475,8 +475,41 @@ Map<String, String> enUs = {
   Strings.darkMode: 'Dark',
   Strings.lightMode: 'Light',
 
-  // 时间单位
+  // Time units
   Strings.days: 'days',
   Strings.day: 'day',
   Strings.hour: 'h',
+
+  // Membership expired
+  Strings.membershipExpired: 'Membership Expired',
+  Strings.membershipExpiredMessage:
+      'Your free trial has ended.\nSubscribe now to continue enjoying all premium features.',
+  Strings.subscribeNow: 'Subscribe Now',
+
+  // Web subscription hint
+  Strings.subscriptionForWebTitle: 'Warm Reminder',
+  Strings.subscriptionForWebMessage:
+      'If membership is not updated after payment, please pull down to refresh the home page or restart the app to sync.',
+
+  // Simplified Chinese language name
+  Strings.zhCNLang: '简体中文',
+
+  // Premium benefits
+  Strings.equity1Title: '@count Devices Online',
+  Strings.equity1Desc:
+      'The VIP account can be used simultaneously on @count devices.',
+  Strings.equity2Title: 'IP Persistence',
+  Strings.equity2Desc: 'Priority for previously used IP addresses',
+  Strings.equity3Title: 'Premium Speed',
+  Strings.equity3Desc: 'Low latency for gaming & 4K streaming',
+  Strings.equity4Title: 'Unlock Streaming',
+  Strings.equity4Desc: 'Unlock Netflix, Disney+, and more.',
+  Strings.equity5Title: 'Trial Preservation',
+  Strings.equity5Desc: 'Remaining trial days remain valid',
+  Strings.equity6Title: 'Ad-Free',
+  Strings.equity6Desc: 'Total removal of all advertisements',
+
+  // Error page
+  Strings.pageNotFound: 'Page not found or has been removed.',
+  Strings.backToHome: 'Back to Home',
 };

+ 14 - 0
lib/config/translations/es_ES/es_es_translation.dart

@@ -478,4 +478,18 @@ const Map<String, String> esEs = {
   Strings.days: 'días',
   Strings.day: 'día',
   Strings.hour: 'h',
+
+  // Beneficios Premium
+  Strings.equity1Title: '@count Dispositivos',
+  Strings.equity1Desc: 'Conexión simultánea para todos los dispositivos',
+  Strings.equity2Title: 'IP Persistente',
+  Strings.equity2Desc: 'Prioridad para direcciones IP usadas anteriormente',
+  Strings.equity3Title: 'Velocidad Premium',
+  Strings.equity3Desc: 'Baja latencia para juegos y streaming 4K',
+  Strings.equity4Title: 'Desbloquear Streaming',
+  Strings.equity4Desc: 'Desbloquea Netflix, Disney+ y más',
+  Strings.equity5Title: 'Conservar Prueba',
+  Strings.equity5Desc: 'Los días de prueba restantes siguen válidos',
+  Strings.equity6Title: 'Sin Anuncios',
+  Strings.equity6Desc: 'Eliminación total de anuncios',
 };

+ 14 - 0
lib/config/translations/fa_IR/fa_ir_translation.dart

@@ -473,4 +473,18 @@ const Map<String, String> faIR = {
   Strings.days: 'روز',
   Strings.day: 'روز',
   Strings.hour: 'س',
+
+  // مزایای پریمیوم
+  Strings.equity1Title: '@count دستگاه آنلاین',
+  Strings.equity1Desc: 'اتصال همزمان برای همه دستگاه‌ها',
+  Strings.equity2Title: 'IP ثابت',
+  Strings.equity2Desc: 'اولویت برای آدرس‌های IP استفاده شده قبلی',
+  Strings.equity3Title: 'سرعت پریمیوم',
+  Strings.equity3Desc: 'تأخیر کم برای بازی و پخش 4K',
+  Strings.equity4Title: 'باز کردن استریم',
+  Strings.equity4Desc: 'Netflix، Disney+ و موارد دیگر را باز کنید',
+  Strings.equity5Title: 'حفظ دوره آزمایشی',
+  Strings.equity5Desc: 'روزهای آزمایشی باقی‌مانده معتبر می‌مانند',
+  Strings.equity6Title: 'بدون تبلیغات',
+  Strings.equity6Desc: 'حذف کامل تمام تبلیغات',
 };

+ 14 - 0
lib/config/translations/fr_FR/fr_fr_translation.dart

@@ -479,4 +479,18 @@ const Map<String, String> frFR = {
   Strings.days: 'jours',
   Strings.day: 'jour',
   Strings.hour: 'h',
+
+  // Avantages Premium
+  Strings.equity1Title: '@count Appareils',
+  Strings.equity1Desc: 'Connexion simultanée pour tous les appareils',
+  Strings.equity2Title: 'IP Persistante',
+  Strings.equity2Desc: 'Priorité aux adresses IP utilisées précédemment',
+  Strings.equity3Title: 'Vitesse Premium',
+  Strings.equity3Desc: 'Faible latence pour les jeux et le streaming 4K',
+  Strings.equity4Title: 'Débloquer Streaming',
+  Strings.equity4Desc: 'Débloquez Netflix, Disney+ et plus',
+  Strings.equity5Title: 'Conservation Essai',
+  Strings.equity5Desc: 'Les jours d\'essai restants restent valides',
+  Strings.equity6Title: 'Sans Publicité',
+  Strings.equity6Desc: 'Suppression totale de toutes les publicités',
 };

+ 14 - 0
lib/config/translations/hi_IN/hi_in_translation.dart

@@ -342,4 +342,18 @@ Map<String, String> hiIN = {
   Strings.days: 'दिन',
   Strings.day: 'दिन',
   Strings.hour: 'घं',
+
+  // प्रीमियम लाभ
+  Strings.equity1Title: '@count डिवाइस ऑनलाइन',
+  Strings.equity1Desc: 'सभी डिवाइसों के लिए एक साथ कनेक्शन',
+  Strings.equity2Title: 'IP स्थिरता',
+  Strings.equity2Desc: 'पहले उपयोग किए गए IP पतों को प्राथमिकता',
+  Strings.equity3Title: 'प्रीमियम स्पीड',
+  Strings.equity3Desc: 'गेमिंग और 4K स्ट्रीमिंग के लिए कम विलंबता',
+  Strings.equity4Title: 'स्ट्रीमिंग अनलॉक',
+  Strings.equity4Desc: 'Netflix, Disney+ और अधिक अनलॉक करें',
+  Strings.equity5Title: 'ट्रायल संरक्षण',
+  Strings.equity5Desc: 'शेष ट्रायल दिन वैध रहते हैं',
+  Strings.equity6Title: 'विज्ञापन-मुक्त',
+  Strings.equity6Desc: 'सभी विज्ञापनों को पूर्ण रूप से हटाना',
 };

+ 14 - 0
lib/config/translations/id_ID/id_id_translation.dart

@@ -343,4 +343,18 @@ Map<String, String> idID = {
   Strings.days: 'hari',
   Strings.day: 'hari',
   Strings.hour: 'jam',
+
+  // Keuntungan Premium
+  Strings.equity1Title: '@count Perangkat Online',
+  Strings.equity1Desc: 'Koneksi simultan untuk semua perangkat',
+  Strings.equity2Title: 'IP Tetap',
+  Strings.equity2Desc: 'Prioritas untuk alamat IP yang digunakan sebelumnya',
+  Strings.equity3Title: 'Kecepatan Premium',
+  Strings.equity3Desc: 'Latensi rendah untuk gaming & streaming 4K',
+  Strings.equity4Title: 'Buka Streaming',
+  Strings.equity4Desc: 'Buka Netflix, Disney+, dan lainnya',
+  Strings.equity5Title: 'Simpan Masa Uji Coba',
+  Strings.equity5Desc: 'Hari uji coba yang tersisa tetap berlaku',
+  Strings.equity6Title: 'Bebas Iklan',
+  Strings.equity6Desc: 'Penghapusan total semua iklan',
 };

+ 14 - 0
lib/config/translations/ja_JP/ja_jp_translation.dart

@@ -452,4 +452,18 @@ const Map<String, String> jaJP = {
   Strings.days: '日',
   Strings.day: '日',
   Strings.hour: '時間',
+
+  // プレミアム特典
+  Strings.equity1Title: '@count台同時接続',
+  Strings.equity1Desc: '複数デバイスで同時ログイン可能',
+  Strings.equity2Title: 'IP固定優先',
+  Strings.equity2Desc: '過去のIPを優先割り当て、より安定',
+  Strings.equity3Title: '高速専用回線',
+  Strings.equity3Desc: '低遅延、4K動画も即座に再生',
+  Strings.equity4Title: 'ストリーミング解除',
+  Strings.equity4Desc: 'Netflix、Disney+などを視聴可能',
+  Strings.equity5Title: '試用時間引継ぎ',
+  Strings.equity5Desc: '試用期間は失われず、購入後も継続',
+  Strings.equity6Title: '広告なし',
+  Strings.equity6Desc: '広告を完全に削除、快適に使用',
 };

+ 14 - 0
lib/config/translations/ko_KR/ko_kr_translation.dart

@@ -445,4 +445,18 @@ const Map<String, String> koKR = {
   Strings.days: '일',
   Strings.day: '일',
   Strings.hour: '시간',
+
+  // 프리미엄 혜택
+  Strings.equity1Title: '@count대 동시 접속',
+  Strings.equity1Desc: '여러 기기에서 동시 로그인 가능',
+  Strings.equity2Title: 'IP 고정 우선',
+  Strings.equity2Desc: '이전 IP 우선 할당, 더 안정적',
+  Strings.equity3Title: '프리미엄 속도',
+  Strings.equity3Desc: '저지연, 4K 영상 즉시 재생',
+  Strings.equity4Title: '스트리밍 잠금 해제',
+  Strings.equity4Desc: 'Netflix, Disney+ 등 시청 가능',
+  Strings.equity5Title: '체험 시간 유지',
+  Strings.equity5Desc: '체험 기간 유지, 구매 후 계속 사용',
+  Strings.equity6Title: '광고 없음',
+  Strings.equity6Desc: '모든 광고 완전 제거',
 };

+ 96 - 79
lib/config/translations/localization_service.dart

@@ -14,6 +14,7 @@ import 'fr_FR/fr_fr_translation.dart';
 import 'ru_RU/ru_ru_translation.dart';
 import 'ko_KR/ko_kr_translation.dart';
 import 'zh_TW/zh_tw_translation.dart';
+import 'zh_CN/zh_cn_translation.dart';
 import 'tk_TM/tk_tm_translation.dart';
 import 'pt_BR/pt_br_translation.dart';
 import 'vi_VN/vi_vn_translation.dart';
@@ -61,47 +62,50 @@ class LocalizationService extends Translations {
 
   static final all = [
     const Locale('en'), // 英语
-    const Locale('es'), // 西班牙语
-    const Locale('ar'), // 阿拉伯语
-    const Locale('de'), // 德语
-    const Locale('ja'), // 日语
-    const Locale('fr'), // 法语
-    const Locale('ru'), // 俄语
-    const Locale('ko'), // 韩语
-    const Locale('fa'), // 波斯语
-    const Locale('my'), // 缅甸语
-    const Locale('zh', 'TW'), // 繁体中文
-    const Locale('tk'), // 土库曼语
-    const Locale('pt', 'BR'), // 葡萄牙语-巴西
-    const Locale('vi'), // 越南语
-    const Locale('id'), // 印尼语
-    const Locale('tl'), // 菲律宾语
-    const Locale('th'), // 泰语
-    const Locale('hi'), // 印地语
-    const Locale('tr'), // 土耳其语
+    // const Locale('es'), // 西班牙语
+    // const Locale('ar'), // 阿拉伯语
+    // const Locale('de'), // 德语
+    // const Locale('ja'), // 日语
+    // const Locale('fr'), // 法语
+    // const Locale('ru'), // 俄语
+    // const Locale('ko'), // 韩语
+    // const Locale('fa'), // 波斯语
+    // const Locale('my'), // 缅甸语
+    // const Locale('zh', 'TW'), // 繁体中文
+    // const Locale('zh', 'CN'), // 简体中文
+    // const Locale('tk'), // 土库曼语
+    // const Locale('pt', 'BR'), // 葡萄牙语-巴西
+    // const Locale('vi'), // 越南语
+    // const Locale('id'), // 印尼语
+    // const Locale('tl'), // 菲律宾语
+    // const Locale('th'), // 泰语
+    // const Locale('hi'), // 印地语
+    // const Locale('tr'), // 土耳其语
   ];
 
   // supported languages
   static Map<String, Locale> supportedLanguages = {
     'en': const Locale('en', 'US'),
-    'es': const Locale('es', 'ES'),
-    'ar': const Locale('ar', 'AR'),
-    'de': const Locale('de', 'DE'),
-    'ja': const Locale('ja', 'JP'),
-    'fr': const Locale('fr', 'FR'),
-    'ru': const Locale('ru', 'RU'),
-    'ko': const Locale('ko', 'KR'),
-    'fa': const Locale('fa', 'IR'),
-    'my': const Locale('my', 'MM'),
-    'zh': const Locale('zh', 'TW'),
-    'tk': const Locale('tk', 'TM'),
-    'pt': const Locale('pt', 'BR'),
-    'vi': const Locale('vi', 'VN'),
-    'id': const Locale('id', 'ID'),
-    'tl': const Locale('tl', 'PH'),
-    'th': const Locale('th', 'TH'),
-    'hi': const Locale('hi', 'IN'),
-    'tr': const Locale('tr', 'TR'),
+    // 'es': const Locale('es', 'ES'),
+    // 'ar': const Locale('ar', 'AR'),
+    // 'de': const Locale('de', 'DE'),
+    // 'ja': const Locale('ja', 'JP'),
+    // 'fr': const Locale('fr', 'FR'),
+    // 'ru': const Locale('ru', 'RU'),
+    // 'ko': const Locale('ko', 'KR'),
+    // 'fa': const Locale('fa', 'IR'),
+    // 'my': const Locale('my', 'MM'),
+    'zh': const Locale('zh', 'CN'), // 默认简体中文(系统语言检测用)
+    // 'zh_TW': const Locale('zh', 'TW'), // 繁体中文
+    'zh_CN': const Locale('zh', 'CN'), // 简体中文(语言选择器用)
+    // 'tk': const Locale('tk', 'TM'),
+    // 'pt': const Locale('pt', 'BR'),
+    // 'vi': const Locale('vi', 'VN'),
+    // 'id': const Locale('id', 'ID'),
+    // 'tl': const Locale('tl', 'PH'),
+    // 'th': const Locale('th', 'TH'),
+    // 'hi': const Locale('hi', 'IN'),
+    // 'tr': const Locale('tr', 'TR'),
   };
 
   // supported languages fonts family (must be in assets & pubspec yaml) or you can use google fonts
@@ -112,47 +116,50 @@ class LocalizationService extends Translations {
     // 'fa': GoogleFonts.vazirmatn(),
     // 'my': GoogleFonts.notoSansMyanmar(),
     'en': const TextStyle(fontFamily: 'Inter'),
-    'es': const TextStyle(fontFamily: 'FiraSans'),
-    'ar': const TextStyle(fontFamily: 'Vazirmatn'),
-    'de': const TextStyle(fontFamily: 'FiraSans'),
-    'ja': const TextStyle(fontFamily: 'FiraSans'),
-    'fr': const TextStyle(fontFamily: 'FiraSans'),
-    'ru': const TextStyle(fontFamily: 'FiraSans'),
-    'ko': const TextStyle(fontFamily: 'FiraSans'),
-    'fa': const TextStyle(fontFamily: 'Vazirmatn'),
-    'my': const TextStyle(fontFamily: 'NotoSansMyanmar'),
+    // 'es': const TextStyle(fontFamily: 'FiraSans'),
+    // 'ar': const TextStyle(fontFamily: 'Vazirmatn'),
+    // 'de': const TextStyle(fontFamily: 'FiraSans'),
+    // 'ja': const TextStyle(fontFamily: 'FiraSans'),
+    // 'fr': const TextStyle(fontFamily: 'FiraSans'),
+    // 'ru': const TextStyle(fontFamily: 'FiraSans'),
+    // 'ko': const TextStyle(fontFamily: 'FiraSans'),
+    // 'fa': const TextStyle(fontFamily: 'Vazirmatn'),
+    // 'my': const TextStyle(fontFamily: 'NotoSansMyanmar'),
     'zh': const TextStyle(fontFamily: 'FiraSans'),
-    'tk': const TextStyle(fontFamily: 'FiraSans'),
-    'pt': const TextStyle(fontFamily: 'FiraSans'),
-    'vi': const TextStyle(fontFamily: 'FiraSans'),
-    'id': const TextStyle(fontFamily: 'FiraSans'),
-    'tl': const TextStyle(fontFamily: 'FiraSans'),
-    'th': const TextStyle(fontFamily: 'FiraSans'),
-    'hi': const TextStyle(fontFamily: 'FiraSans'),
-    'tr': const TextStyle(fontFamily: 'FiraSans'),
+    // 'zh_TW': const TextStyle(fontFamily: 'FiraSans'),
+    'zh_CN': const TextStyle(fontFamily: 'FiraSans'),
+    // 'tk': const TextStyle(fontFamily: 'FiraSans'),
+    // 'pt': const TextStyle(fontFamily: 'FiraSans'),
+    // 'vi': const TextStyle(fontFamily: 'FiraSans'),
+    // 'id': const TextStyle(fontFamily: 'FiraSans'),
+    // 'tl': const TextStyle(fontFamily: 'FiraSans'),
+    // 'th': const TextStyle(fontFamily: 'FiraSans'),
+    // 'hi': const TextStyle(fontFamily: 'FiraSans'),
+    // 'tr': const TextStyle(fontFamily: 'FiraSans'),
   };
 
   @override
   Map<String, Map<String, String>> get keys => {
     'en_US': enUs,
-    'es_ES': esEs,
-    'ar_AR': arAR,
-    'de_DE': deDE,
-    'ja_JP': jaJP,
-    'fr_FR': frFR,
-    'ru_RU': ruRU,
-    'ko_KR': koKR,
-    'fa_IR': faIR,
-    'my_MM': myMM,
-    'zh_TW': zhTW,
-    'tk_TM': tkTM,
-    'pt_BR': ptBR,
-    'vi_VN': viVN,
-    'id_ID': idID,
-    'tl_PH': tlPH,
-    'th_TH': thTH,
-    'hi_IN': hiIN,
-    'tr_TR': trTR,
+    // 'es_ES': esEs,
+    // 'ar_AR': arAR,
+    // 'de_DE': deDE,
+    // 'ja_JP': jaJP,
+    // 'fr_FR': frFR,
+    // 'ru_RU': ruRU,
+    // 'ko_KR': koKR,
+    // 'fa_IR': faIR,
+    // 'my_MM': myMM,
+    // 'zh_TW': zhTW,
+    'zh_CN': zhCN,
+    // 'tk_TM': tkTM,
+    // 'pt_BR': ptBR,
+    // 'vi_VN': viVN,
+    // 'id_ID': idID,
+    // 'tl_PH': tlPH,
+    // 'th_TH': thTH,
+    // 'hi_IN': hiIN,
+    // 'tr_TR': trTR,
   };
 
   /// check if the language is supported
@@ -191,8 +198,15 @@ class LocalizationService extends Translations {
 
   /// 获取本地化配置[locale]中的语言简称
   static String getGlobalLanguageTitle({Locale? locale}) {
-    final languageCode = (locale ?? getCurrentLocal()).languageCode
-        .toLowerCase();
+    final currentLocale = locale ?? getCurrentLocal();
+    final languageCode = currentLocale.languageCode.toLowerCase();
+    final countryCode = currentLocale.countryCode?.toUpperCase() ?? '';
+
+    // 中文需要区分简体和繁体
+    if (languageCode == 'zh') {
+      return countryCode == 'TW' ? Strings.zhTWLang.tr : Strings.zhCNLang.tr;
+    }
+
     switch (languageCode) {
       case 'en':
         return Strings.enLang.tr;
@@ -214,8 +228,6 @@ class LocalizationService extends Translations {
         return Strings.faLang.tr;
       case 'my':
         return Strings.myLang.tr;
-      case 'zh':
-        return Strings.zhTWLang.tr;
       case 'tk':
         return Strings.tkLang.tr;
       case 'pt':
@@ -239,8 +251,15 @@ class LocalizationService extends Translations {
 
   /// 获取本地化配置[locale]中的语言全称
   static String getGlobalLanguageName({Locale? locale}) {
-    final languageCode = (locale ?? getCurrentLocal()).languageCode
-        .toLowerCase();
+    final currentLocale = locale ?? getCurrentLocal();
+    final languageCode = currentLocale.languageCode.toLowerCase();
+    final countryCode = currentLocale.countryCode?.toUpperCase() ?? '';
+
+    // 中文需要区分简体和繁体
+    if (languageCode == 'zh') {
+      return countryCode == 'TW' ? '繁體中文' : '简体中文';
+    }
+
     switch (languageCode) {
       case 'en':
         return 'English';
@@ -276,8 +295,6 @@ class LocalizationService extends Translations {
         return 'हिन्दी';
       case 'ar':
         return 'عربي';
-      case 'zh':
-        return '繁體中文';
       case 'my':
         return 'မြန်မာဘာသာ';
       case 'tk':

+ 14 - 0
lib/config/translations/my_MM/my_mm_translation.dart

@@ -481,4 +481,18 @@ const Map<String, String> myMM = {
   Strings.days: 'ရက်',
   Strings.day: 'ရက်',
   Strings.hour: 'နာရီ',
+
+  // Premium benefits
+  Strings.equity1Title: '@count Devices Online',
+  Strings.equity1Desc: 'Simultaneous connection for all devices',
+  Strings.equity2Title: 'IP Persistence',
+  Strings.equity2Desc: 'Priority for previously used IP addresses',
+  Strings.equity3Title: 'Premium Speed',
+  Strings.equity3Desc: 'Low latency for gaming & 4K streaming',
+  Strings.equity4Title: 'Unlock Streaming',
+  Strings.equity4Desc: 'Unlock Netflix, Disney+, and more.',
+  Strings.equity5Title: 'Trial Preservation',
+  Strings.equity5Desc: 'Remaining trial days remain valid',
+  Strings.equity6Title: 'Ad-Free',
+  Strings.equity6Desc: 'Total removal of all advertisements',
 };

+ 14 - 0
lib/config/translations/pt_BR/pt_br_translation.dart

@@ -473,4 +473,18 @@ Map<String, String> ptBR = {
   Strings.days: 'dias',
   Strings.day: 'dia',
   Strings.hour: 'h',
+
+  // Benefícios Premium
+  Strings.equity1Title: '@count Dispositivos Online',
+  Strings.equity1Desc: 'Conexão simultânea para todos os dispositivos',
+  Strings.equity2Title: 'IP Persistente',
+  Strings.equity2Desc: 'Prioridade para endereços IP usados anteriormente',
+  Strings.equity3Title: 'Velocidade Premium',
+  Strings.equity3Desc: 'Baixa latência para jogos e streaming 4K',
+  Strings.equity4Title: 'Desbloquear Streaming',
+  Strings.equity4Desc: 'Desbloqueie Netflix, Disney+ e mais',
+  Strings.equity5Title: 'Preservar Teste',
+  Strings.equity5Desc: 'Os dias de teste restantes permanecem válidos',
+  Strings.equity6Title: 'Sem Anúncios',
+  Strings.equity6Desc: 'Remoção total de todos os anúncios',
 };

+ 14 - 0
lib/config/translations/ru_RU/ru_ru_translation.dart

@@ -478,4 +478,18 @@ const Map<String, String> ruRU = {
   Strings.days: 'дней',
   Strings.day: 'день',
   Strings.hour: 'ч',
+
+  // Премиум преимущества
+  Strings.equity1Title: '@count Устройства',
+  Strings.equity1Desc: 'Одновременное подключение для всех устройств',
+  Strings.equity2Title: 'Постоянный IP',
+  Strings.equity2Desc: 'Приоритет ранее использованным IP-адресам',
+  Strings.equity3Title: 'Премиум Скорость',
+  Strings.equity3Desc: 'Низкая задержка для игр и 4K стриминга',
+  Strings.equity4Title: 'Разблокировка Стриминга',
+  Strings.equity4Desc: 'Разблокируйте Netflix, Disney+ и другие',
+  Strings.equity5Title: 'Сохранение Пробного Периода',
+  Strings.equity5Desc: 'Оставшиеся пробные дни остаются действительными',
+  Strings.equity6Title: 'Без Рекламы',
+  Strings.equity6Desc: 'Полное удаление всей рекламы',
 };

+ 20 - 0
lib/config/translations/strings_enum.dart

@@ -10,6 +10,7 @@ class Strings {
   static const String ok = 'ok';
   static const String cancel = 'cancel';
   static const String oops = 'oops';
+  static const String connectionIssueDetected = 'connectionIssueDetected';
   static const String copied = 'copied';
   static const String later = 'later';
   static const String noData = 'no data';
@@ -153,6 +154,7 @@ class Strings {
   static const String arLang = 'عربي';
   static const String ruLang = 'Русский';
   static const String zhTWLang = '繁體中文';
+  static const String zhCNLang = '简体中文';
   static const String tkLang = 'Türkmençe';
   static const String ptBRLang = 'Português (Brasil)';
   static const String viLang = 'Tiếng Việt';
@@ -495,4 +497,22 @@ class Strings {
   static const String days = 'days';
   static const String day = 'day';
   static const String hour = 'h';
+
+  // 会员权益
+  static const String equity1Title = 'equity1Title';
+  static const String equity1Desc = 'equity1Desc';
+  static const String equity2Title = 'equity2Title';
+  static const String equity2Desc = 'equity2Desc';
+  static const String equity3Title = 'equity3Title';
+  static const String equity3Desc = 'equity3Desc';
+  static const String equity4Title = 'equity4Title';
+  static const String equity4Desc = 'equity4Desc';
+  static const String equity5Title = 'equity5Title';
+  static const String equity5Desc = 'equity5Desc';
+  static const String equity6Title = 'equity6Title';
+  static const String equity6Desc = 'equity6Desc';
+
+  // 错误页面
+  static const String pageNotFound = 'pageNotFound';
+  static const String backToHome = 'backToHome';
 }

+ 14 - 0
lib/config/translations/th_TH/th_th_translation.dart

@@ -342,4 +342,18 @@ Map<String, String> thTH = {
   Strings.days: 'วัน',
   Strings.day: 'วัน',
   Strings.hour: 'ชม.',
+
+  // สิทธิประโยชน์ Premium
+  Strings.equity1Title: '@count อุปกรณ์ออนไลน์',
+  Strings.equity1Desc: 'เชื่อมต่อพร้อมกันสำหรับทุกอุปกรณ์',
+  Strings.equity2Title: 'IP คงที่',
+  Strings.equity2Desc: 'ให้ความสำคัญกับที่อยู่ IP ที่ใช้ก่อนหน้า',
+  Strings.equity3Title: 'ความเร็ว Premium',
+  Strings.equity3Desc: 'เวลาแฝงต่ำสำหรับเกมและสตรีมมิ่ง 4K',
+  Strings.equity4Title: 'ปลดล็อคสตรีมมิ่ง',
+  Strings.equity4Desc: 'ปลดล็อค Netflix, Disney+ และอื่นๆ',
+  Strings.equity5Title: 'รักษาระยะทดลอง',
+  Strings.equity5Desc: 'วันทดลองใช้ที่เหลือยังคงใช้ได้',
+  Strings.equity6Title: 'ไม่มีโฆษณา',
+  Strings.equity6Desc: 'ลบโฆษณาทั้งหมดออกหมด',
 };

+ 14 - 0
lib/config/translations/tk_TM/tk_tm_translation.dart

@@ -469,4 +469,18 @@ Map<String, String> tkTM = {
   Strings.days: 'gün',
   Strings.day: 'gün',
   Strings.hour: 'sag',
+
+  // Premium benefits
+  Strings.equity1Title: '@count Devices Online',
+  Strings.equity1Desc: 'Simultaneous connection for all devices',
+  Strings.equity2Title: 'IP Persistence',
+  Strings.equity2Desc: 'Priority for previously used IP addresses',
+  Strings.equity3Title: 'Premium Speed',
+  Strings.equity3Desc: 'Low latency for gaming & 4K streaming',
+  Strings.equity4Title: 'Unlock Streaming',
+  Strings.equity4Desc: 'Unlock Netflix, Disney+, and more.',
+  Strings.equity5Title: 'Trial Preservation',
+  Strings.equity5Desc: 'Remaining trial days remain valid',
+  Strings.equity6Title: 'Ad-Free',
+  Strings.equity6Desc: 'Total removal of all advertisements',
 };

+ 14 - 0
lib/config/translations/tl_PH/tl_ph_translation.dart

@@ -343,4 +343,18 @@ Map<String, String> tlPH = {
   Strings.days: 'araw',
   Strings.day: 'araw',
   Strings.hour: 'oras',
+
+  // Premium benefits
+  Strings.equity1Title: '@count Devices Online',
+  Strings.equity1Desc: 'Sabay-sabay na koneksyon para sa lahat ng device',
+  Strings.equity2Title: 'IP Persistence',
+  Strings.equity2Desc: 'Prioridad para sa dating ginamit na IP address',
+  Strings.equity3Title: 'Premium Speed',
+  Strings.equity3Desc: 'Mababang latency para sa gaming at 4K streaming',
+  Strings.equity4Title: 'Unlock Streaming',
+  Strings.equity4Desc: 'I-unlock ang Netflix, Disney+, at iba pa',
+  Strings.equity5Title: 'Trial Preservation',
+  Strings.equity5Desc: 'Ang natitirang trial days ay mananatiling valid',
+  Strings.equity6Title: 'Ad-Free',
+  Strings.equity6Desc: 'Kumpletong pag-alis ng lahat ng advertisement',
 };

+ 14 - 0
lib/config/translations/tr_TR/tr_tr_translation.dart

@@ -343,4 +343,18 @@ Map<String, String> trTR = {
   Strings.days: 'gün',
   Strings.day: 'gün',
   Strings.hour: 'sa',
+
+  // Premium Avantajları
+  Strings.equity1Title: '@count Cihaz Çevrimiçi',
+  Strings.equity1Desc: 'Tüm cihazlar için eşzamanlı bağlantı',
+  Strings.equity2Title: 'IP Kalıcılığı',
+  Strings.equity2Desc: 'Daha önce kullanılan IP adreslerine öncelik',
+  Strings.equity3Title: 'Premium Hız',
+  Strings.equity3Desc: 'Oyun ve 4K streaming için düşük gecikme',
+  Strings.equity4Title: 'Streaming Kilidi Aç',
+  Strings.equity4Desc: 'Netflix, Disney+ ve daha fazlasının kilidini açın',
+  Strings.equity5Title: 'Deneme Süresi Korunması',
+  Strings.equity5Desc: 'Kalan deneme günleri geçerli kalır',
+  Strings.equity6Title: 'Reklamsız',
+  Strings.equity6Desc: 'Tüm reklamların tamamen kaldırılması',
 };

+ 14 - 0
lib/config/translations/vi_VN/vi_vn_translation.dart

@@ -383,4 +383,18 @@ Map<String, String> viVN = {
   Strings.days: 'ngày',
   Strings.day: 'ngày',
   Strings.hour: 'giờ',
+
+  // Quyền lợi Premium
+  Strings.equity1Title: '@count Thiết Bị Online',
+  Strings.equity1Desc: 'Kết nối đồng thời cho tất cả thiết bị',
+  Strings.equity2Title: 'IP Cố Định',
+  Strings.equity2Desc: 'Ưu tiên địa chỉ IP đã sử dụng trước đó',
+  Strings.equity3Title: 'Tốc Độ Premium',
+  Strings.equity3Desc: 'Độ trễ thấp cho game và streaming 4K',
+  Strings.equity4Title: 'Mở Khóa Streaming',
+  Strings.equity4Desc: 'Mở khóa Netflix, Disney+ và nhiều hơn nữa',
+  Strings.equity5Title: 'Bảo Lưu Dùng Thử',
+  Strings.equity5Desc: 'Số ngày dùng thử còn lại vẫn có hiệu lực',
+  Strings.equity6Title: 'Không Quảng Cáo',
+  Strings.equity6Desc: 'Loại bỏ hoàn toàn tất cả quảng cáo',
 };

+ 476 - 0
lib/config/translations/zh_CN/zh_cn_translation.dart

@@ -0,0 +1,476 @@
+import '../strings_enum.dart';
+
+Map<String, String> zhCN = {
+  Strings.someThingWentWorng: '出现错误',
+  Strings.retry: '重试',
+  //profile
+  Strings.settings: '设置',
+  Strings.language: '语言',
+  Strings.termsOfService: '服务条款',
+  Strings.privacyPolicy: '隐私政策',
+  Strings.version: '版本',
+
+  Strings.ok: '确定',
+  Strings.cancel: '取消',
+  Strings.oops: '糟糕',
+  Strings.connectionIssueDetected: '检测到连接问题,请检查您的网络连接后重试。',
+  Strings.copied: '已复制',
+  Strings.later: '稍后',
+  Strings.noData: '无数据',
+
+  //empty error update
+  Strings.refresh: '重新加载',
+  Strings.unableToConnectNetwork: '请检查您的网络连接',
+  Strings.unableToConnectServer: '服务器暂时不可用,请稍后再试',
+  Strings.regionRestricted: '由于当地法律法规限制,Nomo 服务在您所在地区不可用',
+  Strings.updateNow: '立即更新',
+  Strings.newVersionAvailable: '新版本可用',
+
+  // util error
+  Strings.eUtilOpenEmail: '打开邮件时发生错误',
+  Strings.eUtilOpenBrowser: '打开浏览器时发生错误',
+  Strings.eUtilOpenGooglePlay: '打开 Google Play 时出现错误',
+
+  Strings.error: '错误',
+
+  // Privacy policy
+  Strings.terms: '条款',
+  Strings.privacy: '隐私',
+  Strings.termsAgreementPrefix: '注册或继续即表示您同意我们的',
+  Strings.termsAgreementConnector: '和',
+
+  // Account page
+  Strings.account: '当前身份',
+
+  // Dialog texts
+  Strings.processing: '处理中...',
+  Strings.success: '成功',
+  Strings.unknownError: '未知错误',
+  Strings.failed: '连接失败',
+
+  // exit
+  Strings.exit: '退出',
+
+  // feedback
+  Strings.feedback: '意见反馈',
+
+  // setting page
+  Strings.networkSection: '网络',
+  Strings.securitySection: '安全',
+  Strings.myPreCode: '我的 Pre Code',
+  Strings.validTerm: '到期时间',
+  Strings.freeTime: '免费时长',
+  Strings.deviceAuthorization: '设备授权',
+  Strings.routingMode: '路由模式',
+  Strings.splitTunneling: 'VPN分流',
+  Strings.autoReconnect: '自动重连',
+  Strings.restoreDefault: '恢复预设',
+  Strings.deleteAccount: '删除账号',
+  Strings.logout: '退出登录',
+
+  // media location page
+  Strings.connecting: '连接中...',
+  Strings.connected: '已连接',
+  Strings.disconnected: '未连接',
+  Strings.open: '开启',
+  Strings.disconnect: '断开连接',
+  Strings.connect: '连接',
+  Strings.opening: '连接中',
+  Strings.connectedSuccessfully: '连接成功',
+  Strings.willOpenSoon: '即将打开',
+  Strings.netflix: 'Netflix',
+  Strings.youtube: 'YouTube',
+  Strings.amazon: 'Amazon',
+  Strings.hulu: 'hulu',
+  Strings.niftyStreaming: 'Nifty 串流',
+  Strings.youtubeStreaming: 'YouTube 串流',
+  Strings.amazonStreaming: 'Amazon 串流',
+  Strings.huluStreaming: 'hulu 串流',
+
+  // split tunneling page
+  Strings.excludeSelectedAppsFromVPN: '选定的APP不使用VPN',
+  Strings.useVPNForSelectedAppsOnly: '仅对选定的App使用VPN',
+  Strings.selectApps: '选择 App',
+  Strings.customizeYourVPN: '自定义您的 VPN',
+
+  // subscription page
+  Strings.subscription: '购买/订阅',
+  Strings.currentSubscription: '当前订阅',
+  Strings.upgradeToPremium: '升级至会员',
+  Strings.activatePreCode: '启用 Pre Code',
+  Strings.preCodeHint: '如果您有 Pre code,请输入以领取您的 Pre 权益',
+  Strings.planChangeInfo: '套餐变更说明',
+  Strings.whenItStarts: '何时开始',
+  Strings.whatHappensToYourBalance: '您的余额会怎样',
+  Strings.extraTime: '额外时长',
+  Strings.yourNewPlanBeginsRightAway: '您的新套餐将立即开启',
+  Strings.anyUnusedAmountFromYourOldPlan: '您的旧套餐中未使用的金额将添加到新套餐中',
+  Strings.youllGetExtraDays: '将根据您的剩余余额折算为额外时长',
+  Strings.premiumsIncluded: 'Premium 权益',
+  Strings.unlockAllFreeLocations: '解锁所有免费节点',
+  Strings.unlockSmartMode: '解锁智能模式',
+  Strings.unlockMultiHopMode: '解锁多跳模式',
+  Strings.premiumCanShareXDevices: '会员账号可在 @count 台设备同时使用',
+  Strings.ownYourOwnPrivateServer: '拥有您自己的私人节点',
+  Strings.closeAds: '关闭广告',
+  Strings.confirmChange: '购买/订阅',
+  Strings.restorePurchases: '恢复购买',
+  Strings.paymentIssue: '付款问题',
+  Strings.yearlyAutoRenewCancelAnytime: '套餐将自动续订,可随时取消',
+
+  // home page
+  Strings.recent: '最近',
+  Strings.moviesAndTV: '电影和电视',
+  Strings.social: '社交',
+  Strings.support: '帮助',
+  Strings.sport: '体育',
+  Strings.music: '音乐',
+  Strings.game: '游戏',
+
+  // country restricted
+  Strings.sorry: '抱歉',
+  Strings.unableToLoadData: '无法加载数据',
+  Strings.dueLawsAndRegulations: '由于当地法律法规,\nNOMOVPN 服务在您目前所在地区\n不可用。',
+
+  // more pages
+  Strings.sendPreCodeToEmail: '将 Pre Code 发送至电子邮件',
+  Strings.selectServer: '选择节点服务器',
+
+  // Dialog messages
+  Strings.premiumActivated: '会员购买成功!',
+  Strings.premiumActivatedMessage: '您已升级至会员,享受所有会员权益和增强的连接体验。',
+  Strings.gotIt: '知道了',
+  Strings.emailSent: '电子邮件发送成功',
+  Strings.emailSentMessage: '您的 Pre Code 已发送至您的电子邮件。\n请检查您的收件箱(和垃圾邮件箱)。',
+  Strings.noInternetConnection: '无网络连接',
+  Strings.noInternetMessage: '您的连接已断开,请检查您的网络连接,然后重试。',
+  Strings.logOut: '退出登录',
+  Strings.logOutConfirmMessage: '退出后您需要重新登录才能使用会员功能。',
+  Strings.thankYouFeedback: '感谢您的意见反馈!',
+  Strings.feedbackMessage: '很抱歉使您的使用体验不佳,我们会尽快改进。',
+  Strings.done: '完成',
+  Strings.whatIsUid: '什么是 UID?',
+  Strings.uidMessage:
+      '设备 ID (UID) 这是您的设备唯一标识码,提供此 ID 可帮助我们的支持团队验证您的设备并更快解决您的问题。',
+  Strings.confirm: '确认',
+
+  // Device Authorization
+  Strings.copy: '复制',
+  Strings.pleaseKeepPageOpen: '请不要关闭该页面',
+  Strings.authorizationCode: '授权码',
+  Strings.authorizationCodeDesc:
+      '在另一台设备上输入此 6 位授权码,对应设备即可登录该 VIP 账号,每 15 分钟刷新一次。',
+  Strings.shareWithPreUser: '与 Pre 用户分享',
+  Strings.shareWithPreUserDesc: '将此授权码告知给其他设备用户,以便在其他设备上登录该账号',
+  Strings.waitingForAuthorization: '等待授权',
+  Strings.waitingForAuthorizationDesc: '请保持此页面开启。\n一旦获得批准,您的账户将自动升级并重新连接。',
+  Strings.enterCode: '输入代码',
+  Strings.enterCodeDesc: '输入其他设备(免费用户)上显示的 6 位数代码。此代码每 15 分钟刷新一次。',
+  Strings.verifyDevice: '验证设备',
+  Strings.verifyDeviceDesc: '我们将检查输入的代码是否与等待授权的活跃设备匹配。',
+  Strings.authorizationSuccessful: '授权成功',
+  Strings.authorizationSuccessfulDesc: '确认后,该设备将自动升级并连接到您的账户。',
+  Strings.deviceLimitReached: '已达设备限制',
+  Strings.deviceLimitMessage: '您最多只能授权',
+  Strings.devices: '台设备',
+  Strings.deviceAuthorized: '设备已授权',
+  Strings.deviceAuthorizedMessage: '新设备已成功授权',
+  Strings.relieveDevice: '解绑设备',
+  Strings.relieveDeviceMessage: '您确定要解绑',
+  Strings.relieveDeviceLoseAccess: '此设备将失去 Premium 访问权限。',
+  Strings.deviceRelieved: '设备已解绑',
+  Strings.deviceRelievedMessage: '已从已授权设备中移除',
+  Strings.currentDevice: '当前设备',
+  Strings.androidDevices: 'Android 设备',
+  Strings.authCodeCopied: '授权码已复制到剪贴板',
+  Strings.invalidAuthorizationCode: '无效的授权码',
+  Strings.invalidAuthorizationCodeMessage:
+      '您输入的代码不正确或已过期。\n请检查其他设备上的 6 位代码,然后重试。',
+  Strings.invalidAuthorizationCodeButton: '重试',
+
+  // Pre Code Email
+  Strings.codeBackedUpMessage: '您的代码将备份到此电子邮件。',
+  Strings.enterYourEmail: '输入您的电子邮件',
+  Strings.sendYourEmail: '发送您的电子邮件',
+  Strings.yourPreCredential: '您的 Pre 凭证',
+  Strings.yourPreCredentialDesc: '这是您的 VIP 凭证。请妥善保管,不要与任何人分享。',
+  Strings.secureEmailBackup: '安全电子邮件备份',
+  Strings.secureEmailBackupDesc: '我们将发送一封包含此凭证的电子邮件到您指定的电子邮件地址以妥善保管。',
+  Strings.sendAndSave: '发送并保存',
+  Strings.sendAndSaveDesc: '电子邮件发送后,我们建议您也将此凭证保存到设备上的安全位置。',
+
+  // Routing Mode
+  Strings.smart: '智能模式',
+  Strings.smartModeDesc: '只有需要翻墙的流量才会使用VPN网络',
+  Strings.global: '全局模式',
+  Strings.globalModeDesc: '所有流量都使用VPN网络,以确保最大的隐私和安全',
+
+  // Subscription Plans                      nomo暂未使用
+  Strings.perYear: '每年',
+  Strings.yearlyPlan: '年度方案',
+  Strings.mostlyChoose: '最多选择',
+  Strings.once: '一次性',
+  Strings.lifeTime: '终身',
+  Strings.monthPlan: '月度方案',
+  Strings.perWeek: '每周',
+  Strings.weekPlan: '周方案',
+  Strings.limitedTime: '限时',
+  Strings.subscriptionChanged: '订阅方案变更成功',
+  Strings.restoringPurchases: '恢复购买中...',
+  Strings.openingPaymentSupport: '开启付款支持...',
+  Strings.info: '信息',
+
+  // Other messages                         nomo暂未使用
+  Strings.vpnConnectionError: 'VPN连接错误',
+  Strings.vpnServiceDisconnected: 'VPN连接意外断开',
+  Strings.failedCaptureScreenshot: '截屏失败',
+  Strings.imageSavedToAlbum: '图片已保存到您的本地相册',
+  Strings.failedSaveImage: '保存图片到相册失败',
+  Strings.failedToSave: '保存失败',
+  Strings.failedSendEmail: '发送电子邮件失败',
+
+  // Connection status                     nomo暂未使用
+  Strings.activeTime: '已连接时间',
+  Strings.yearPlanPrice: '年度方案 每年 @price',
+
+  // Connecting status carousel texts
+  Strings.securingData: '正在保护数据…',
+  Strings.encryptingTraffic: '正在加密流量…',
+  Strings.protectingPrivacy: '正在保护隐私…',
+  Strings.safeConnection: '安全连接中…',
+  Strings.yourDataIsSafe: '您的数据是安全的…',
+
+  // Login & Signup
+  Strings.login: '登录',
+  Strings.loginButton: '登录',
+  Strings.loginDescription: '登录后,您的试用时长不会被清除,将同步到您的注册账号中',
+  Strings.signup: '注册 NOMO',
+  Strings.signupButton: '注册',
+  Strings.signupDescription: '注册后,您的试用时长不会被清除,将同步到您的注册账号中',
+  Strings.username: '用户名',
+  Strings.password: '密码',
+  Strings.usernamePasswordRule: '6-20 个字符(字母或数字)',
+  Strings.noAccount: '没有账号?',
+  Strings.registerNow: '立即注册',
+  Strings.alreadyHaveAccount: '已有账号?',
+  Strings.loginNow: '立即登录',
+
+  // Feedback
+  Strings.feedbackPlaceholder: '描述您的问题或建议...',
+  Strings.emailAddressForReply: '• 您的电子邮件地址(用于我们的回复)',
+  Strings.send: '发送',
+
+  // Account page additions
+  Strings.changeSubscription: '购买/订阅',
+  Strings.awaitingActivation: '等待启用',
+  Strings.relieve: '解除',
+  Strings.configureAuthorizedDevices: '配置已授权设备...',
+  Strings.authorizeUpTo4DevicesAsPremium:
+      '最多授权 @max 台设备为 Premium(@current/@max)',
+  Strings.youCanAuthorizeOtherDevices: '您可以授权其他设备为 Premium 用户(@current/@max)',
+
+  // Pre Code page
+  Strings.preCodeInfoMessage: 'Pre Code 是您的高级用户凭证。\n使用它来启用权益或在其他设备上\n同步您的账户。',
+  Strings.pleaseStoreSecurely: '请妥善保管!',
+  Strings.sendPreCodeEmailDesc: '将您的 Pre Code 发送到您的注册电子邮件地址',
+  Strings.storeLocalCopyDesc: '在此设备上保存您的 Pre Code 副本',
+  Strings.preview: '预览',
+  Strings.hide: '隐藏',
+  Strings.sendToEmail: '发送到电子邮件',
+  Strings.saveLocalCopy: '保存本地副本',
+
+  // Splash page
+  Strings.secureYourConnection: '保护您的连接',
+  Strings.secureYourConnectionDesc: '您可以登录或注册账户,以在不同设备之间共享会员资格。',
+
+  // Pre Code Save Dialog
+  Strings.save: '保存',
+
+  // Split Tunneling
+  Strings.onlyOneModeActive: '同时只能启用一种模式',
+  Strings.chooseAppsExcludeDesc: '选择不使用VPN的程序',
+  Strings.chooseAppsIncludeDesc: '选择需要使用VPN的程序',
+  Strings.splitTunnelingDesc: '智能分流,仅访问国外网站或软件时使用VPN网络',
+  Strings.selectAppsExclude: '选择不使用VPN的应用程序',
+  Strings.selectAppsInclude: '选择使用VPN的应用程序',
+  Strings.deselectAll: '取消全选',
+  Strings.allApps: '选择所有应用程序',
+
+  // Feedback Bottom Sheet
+  Strings.howExperience: '到目前为止\n您的体验如何?',
+  Strings.wedLoveToKnow: '我们很想知道~',
+
+  // Feedback Tags - Bad 😡
+  Strings.vpnConnectionFailed: 'VPN 连接失败',
+  Strings.internetTooSlow: '网速太慢',
+  Strings.keepsDisconnecting: '经常自动断开连接',
+  Strings.appCrashes: '应用程序崩溃或闪退',
+  Strings.otherIssues: '其它问题',
+
+  // Feedback Tags - Poor 😥
+  Strings.connectionUnstable: '连接不稳定',
+  Strings.speedNotExpected: '速度未达预期',
+  Strings.hardToUse: '难以使用/界面混乱',
+
+  // Feedback Tags - Okay 🤭
+  Strings.worksFineNotFast: '运行正常但不够快',
+  Strings.limitedFreeServers: '免费服务器有限',
+  Strings.appCouldBeSimpler: '应用程序可以更简单',
+  Strings.sometimesDisconnects: '有时会断开连接',
+  Strings.nothingSpecial: '没什么特别',
+
+  // Feedback Tags - Good 😏
+  Strings.easyToUse: '易于使用',
+  Strings.fastConnection: '连接快速',
+  Strings.stablePerformance: '性能稳定',
+  Strings.usefulFreeVersion: '免费版本实用',
+  Strings.satisfiedOverall: '整体满意',
+
+  // Feedback Tags - Excellent 🥰
+  Strings.fastAndStable: '连接快速稳定',
+  Strings.greatUserExperience: '优秀的用户体验',
+  Strings.excellentPremiumFeatures: '出色的高级功能',
+  Strings.worthRecommending: '值得推荐',
+  Strings.loveTheDesign: '我喜欢这个设计',
+
+  // Change Password
+  Strings.changePassword: '修改密码',
+  Strings.changePasswordDescription: '您可以随时修改密码以确保安全,密码修改次数无限制',
+  Strings.enterNewPassword: '输入新密码',
+  Strings.enterConfirmPassword: '再次输入新密码',
+  Strings.confirmPasswordMustBeTheSame: '两次输入的密码不一致,请重新输入',
+  Strings.yes: '是',
+
+  // Signup
+  Strings.signingUp: '注册中...',
+  Strings.signUpSuccessful: '注册成功',
+
+  // login
+  Strings.loggingIn: '登录中...',
+  Strings.loginSuccessful: '登录成功',
+
+  // logout
+  Strings.loggingOut: '正在退出登录...',
+  Strings.logoutSuccessful: '已退出登录',
+
+  // change password
+  Strings.changingPassword: '修改密码中...',
+  Strings.changePasswordSuccessful: '密码修改成功',
+
+  // delete account
+  Strings.deletingAccount: '正在删除账户...',
+  Strings.deleteAccountSuccessful: '账号删除成功',
+  Strings.deleteAccountConfirmMessage: '将永久移除您的所有数据和帐户信息,此操作无法撤销',
+  Strings.deleteAccountConfirmButton: '删除',
+
+  // Push Notifications
+  Strings.pushNotifications: '推送通知',
+  Strings.upgradeNow: '立即升级',
+
+  // 语言
+  Strings.enLang: 'English',
+  Strings.jaLang: '日本語',
+  Strings.faLang: 'فارسی',
+  Strings.myLang: 'မြန်မာဘာသာ',
+  Strings.zhTWLang: '繁體中文',
+
+  // Bind email / Member benefits
+  Strings.bindEmailMemberBenefits: '绑定注册帐号',
+  Strings.bindingAccountEmailProtectsPreRights: '会员绑定到注册账号后,可在其它设备上登录并共享会员权益',
+  Strings.associatedInterests: '绑定会员权益',
+  Strings.associatedInterestsDesc:
+      '1. 在该设备上新注册Nomo帐号后,当前设备上的会员权益,将自动转移到您的注册帐号\n2. 您的会员帐号,可在其它设备上登录共享会员权益',
+  Strings.notNow: '暂不',
+
+  // VPN Error Messages
+  Strings.vpnConnectionTimeoutError: '连接超时,请重试或者切换连接节点',
+  Strings.vpnNoNodeError: '无可用节点',
+  Strings.vpnInitError: 'VPN服务初始化失败',
+  Strings.vpnKillError: 'VPN服务已被终止',
+  Strings.vpnRevokeError: 'VPN 连接已断开,请重新连接',
+  Strings.vpnServiceEmptyError: 'VPN 服务不可用',
+  Strings.vpnRouterError: 'VPN路由配置错误',
+  Strings.vpnPermissionDeniedError: 'VPN 权限被拒绝',
+
+  // Remain time
+  Strings.remainTime: '剩余时长',
+  Strings.remainTimeEnded: '您的可用时长已结束',
+  Strings.expired: '已过期',
+
+  // Enable Notifications
+  Strings.enableNotifications: '启用通知',
+  Strings.enableNotificationsDesc: '启用通知以接收重要更新和消息。',
+  Strings.enable: '启用',
+
+  // Windows tray icon hints
+  Strings.showWindow: '显示窗口',
+  Strings.quitApp: '退出',
+  Strings.vpnConnected: 'VPN 已连接',
+  Strings.vpnConnecting: 'VPN 连接中',
+  Strings.vpnDisconnected: 'VPN 未连接',
+
+  // Feedback validation
+  Strings.pleaseEnterFeedback: '请输入意见反馈内容',
+  Strings.pleaseEnterEmail: '请输入电子邮件地址',
+  Strings.pleaseEnterValidEmail: '请输入有效的电子邮件地址',
+  Strings.feedbackSubmitted: '意见反馈已提交,我们会尽快回复您',
+  Strings.feedbackSubmitFailed: '提交失败,请稍后再试',
+
+  // 主题
+  Strings.theme: '主题',
+  Strings.followSystem: '跟随系统',
+  Strings.darkMode: '深色',
+  Strings.lightMode: '浅色',
+
+  // 会员过期
+  Strings.membershipExpired: '会员已过期',
+  Strings.membershipExpiredMessage: '您的免费试用已结束。\n立即订阅以继续享受所有高级功能。',
+  Strings.subscribeNow: '立即订阅',
+
+  // Web 订阅提示
+  Strings.subscriptionForWebTitle: '温馨提示',
+  Strings.subscriptionForWebMessage: '如果付款后会员期限未更新,请下拉首页刷新或重启客户端同步。',
+
+  // 时间单位
+  Strings.days: '天',
+  Strings.day: '天',
+  Strings.hour: '小时',
+
+  // 断开中
+  Strings.disconnecting: '断开中',
+
+  // 其他语言名称
+  Strings.esLang: 'Español',
+  Strings.frLang: 'Français',
+  Strings.deLang: 'Deutsch',
+  Strings.koLang: '한국어',
+  Strings.arLang: 'عربي',
+  Strings.ruLang: 'Русский',
+  Strings.tkLang: 'Türkmençe',
+  Strings.ptBRLang: 'Português (Brasil)',
+  Strings.viLang: 'Tiếng Việt',
+  Strings.idLang: 'Bahasa Indonesia',
+  Strings.tlLang: 'Filipino',
+  Strings.thLang: 'ไทย',
+  Strings.hiLang: 'हिन्दी',
+  Strings.trLang: 'Türkçe',
+  Strings.zhCNLang: '简体中文',
+
+  // 会员权益
+  Strings.equity1Title: '支持绑定@count个设备',
+  Strings.equity1Desc: 'VIP帐号可以在@count台设备上同时使用',
+  Strings.equity2Title: '固定IP',
+  Strings.equity2Desc: '连接到相同节点时,优先分配历史相同IP',
+  Strings.equity3Title: '极速专线',
+  Strings.equity3Desc: '低延迟,4K 视频秒开',
+  Strings.equity4Title: '解锁流媒体',
+  Strings.equity4Desc: '畅看 Netflix, Disney+ 等',
+  Strings.equity5Title: '时长自动累加',
+  Strings.equity5Desc: '剩余试用时长将继续保留',
+  Strings.equity6Title: '纯净无广告',
+  Strings.equity6Desc: '移除干扰,清爽使用',
+
+  // 错误页面
+  Strings.pageNotFound: '页面不存在或已被移除',
+  Strings.backToHome: '返回首页',
+};

+ 14 - 0
lib/config/translations/zh_TW/zh_tw_translation.dart

@@ -440,4 +440,18 @@ Map<String, String> zhTW = {
   Strings.days: '天',
   Strings.day: '天',
   Strings.hour: '小時',
+
+  // 會員權益
+  Strings.equity1Title: '@count 設備並發',
+  Strings.equity1Desc: '多端登入,互不干擾',
+  Strings.equity2Title: '固定 IP 偏好',
+  Strings.equity2Desc: '優先分配歷史 IP,登入更穩定',
+  Strings.equity3Title: '極速專線',
+  Strings.equity3Desc: '低延遲,4K 影片秒開',
+  Strings.equity4Title: '解鎖流媒體',
+  Strings.equity4Desc: '暢看 Netflix, Disney+ 等',
+  Strings.equity5Title: '時長自動累加',
+  Strings.equity5Desc: '試用期不下線,購後繼續用',
+  Strings.equity6Title: '純淨無廣告',
+  Strings.equity6Desc: '移除干擾,清爽使用',
 };

+ 3 - 0
lib/main.dart

@@ -7,6 +7,7 @@ import 'package:get/get.dart';
 
 import 'app/app.dart';
 import 'app/constants/api_domains.dart';
+import 'app/constants/environment.dart';
 import 'app/controllers/api_controller.dart';
 import 'app/controllers/core_controller.dart';
 import 'app/data/sp/ix_sp.dart';
@@ -19,6 +20,8 @@ import 'config/theme/theme_extensions/theme_extension.dart';
 Future<void> main() async {
   runZonedGuarded(
     () async {
+      // 初始化环境
+      Environment.initialize();
       await _initializeApp();
       runApp(const App());
     },

+ 17 - 16
lib/utils/api_statistics.dart

@@ -499,25 +499,26 @@ class ApiStatistics {
     _isInitialized = false;
   }
 
-  /// App 进入后台时调用
-  Future<void> onAppPaused() async {
-    await _saveToFile();
+  /// App 进入后台时调用(不阻塞,fire-and-forget)
+  void onAppPaused() {
+    // 异步保存,不等待结果
+    _saveToFile();
   }
 
-  /// App 进入前台时调用
-  Future<void> onAppResumed() async {
+  /// App 进入前台时调用(不阻塞,fire-and-forget)
+  Future<List<Map<String, dynamic>>> onAppResumed() async {
     await _loadFromFile();
-    await _uploadAndClear();
+    return await _uploadAndClear();
   }
 
   /// 上传统计数据并清空
-  Future<void> _uploadAndClear() async {
+  Future<List<Map<String, dynamic>>> _uploadAndClear() async {
     try {
       // 先更新禁用模块列表
       updateDisabledModules();
 
       final records = getRecords();
-      if (records.isEmpty) return;
+      if (records.isEmpty) return [];
 
       // 检查模块是否禁用
       final isLaunchDisabled = _disabledModules.contains(
@@ -540,14 +541,6 @@ class ApiStatistics {
           return !isOtherDisabled;
         }
       }).toList();
-
-      // 合并上传(一次接口调用)
-      if (enabledRecords.isNotEmpty) {
-        final apiController = Get.find<ApiController>();
-        final logs = _formatLogsForUpload(enabledRecords);
-        await apiController.uploadApiStatisticsLog(logs);
-      }
-
       // 移除已上传的记录,保留上传过程中新增的记录(如上传接口本身的记录)
       await _removeUploadedRecords(records);
       log(
@@ -555,8 +548,16 @@ class ApiStatistics {
         'ApiStatistics uploaded ${enabledRecords.length}/${records.length} records '
         '(launch disabled: $isLaunchDisabled, router disabled: $isRouterDisabled)',
       );
+      // 合并上传(一次接口调用)
+      if (enabledRecords.isNotEmpty) {
+        final logs = _formatLogsForUpload(enabledRecords);
+        log(TAG, 'ApiStatistics upload ${logs.length} records');
+        return logs;
+      }
+      return [];
     } catch (e) {
       log(TAG, 'ApiStatistics upload error: $e');
+      return [];
     }
   }
 

+ 8 - 5
lib/utils/log/log_manager.dart

@@ -192,16 +192,18 @@ class LogManager {
   /// 清理过期日志文件
   Future<void> _cleanupOldLogs() async {
     try {
-      final cutoffDate =
-          DateTime.now().subtract(const Duration(days: _retentionDays));
+      final cutoffDate = DateTime.now().subtract(
+        const Duration(days: _retentionDays),
+      );
       final cutoffDateKey = _getDateKey(cutoffDate);
 
       final files = await _logDirectory.list().toList();
       for (final file in files) {
         if (file is File && file.path.contains('log_')) {
           final fileName = file.path.split('/').last;
-          final dateStr =
-              fileName.replaceAll('log_', '').replaceAll('.txt', '');
+          final dateStr = fileName
+              .replaceAll('log_', '')
+              .replaceAll('.txt', '');
 
           if (dateStr.compareTo(cutoffDateKey) < 0) {
             await file.delete();
@@ -248,7 +250,8 @@ class LogManager {
         final dateLogs = await readLogsForDate(date);
         if (dateLogs.isNotEmpty) {
           allLogs.add(
-              '=== ${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')} ===\n$dateLogs');
+            '=== ${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')} ===\n$dateLogs',
+          );
         }
       }