ソースを参照

feat: 更新包名

BaiLuoYan 7 時間 前
コミット
2a266147c6
100 ファイル変更849 行追加1054 行削除
  1. 4 3
      README.md
  2. 10 8
      android/app/build.gradle.kts
  3. 30 71
      android/app/src/main/AndroidManifest.xml
  4. 0 8
      android/app/src/main/kotlin/app/xixi/nomo/Broadcasts.kt
  5. 0 114
      android/app/src/main/kotlin/app/xixi/nomo/MainActivity.kt
  6. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/Actions.kt
  7. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/App.kt
  8. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/AppLogger.kt
  9. 8 0
      android/app/src/main/kotlin/com/flashlink/vpn/Broadcasts.kt
  10. 12 12
      android/app/src/main/kotlin/com/flashlink/vpn/CoreApi.g.kt
  11. 3 3
      android/app/src/main/kotlin/com/flashlink/vpn/CoreApiImpl.kt
  12. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/CoreLogger.kt
  13. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/CryptoUtils.kt
  14. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/ErrorCode.kt
  15. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/LifecycleVpnService.kt
  16. 5 5
      android/app/src/main/kotlin/com/flashlink/vpn/NetworkReporter.kt
  17. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/NotificationUtils.kt
  18. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/ServiceStatus.kt
  19. 2 2
      android/app/src/main/kotlin/com/flashlink/vpn/TProxyService.kt
  20. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/VLog.kt
  21. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/XRayApi.kt
  22. 15 15
      android/app/src/main/kotlin/com/flashlink/vpn/XRayService.kt
  23. 1 1
      android/app/src/main/kotlin/com/flashlink/vpn/XrayConfig.kt
  24. 1 1
      android/app/src/main/res/values/strings.xml
  25. 4 0
      android/gradle.properties
  26. 465 438
      assets/html/test_jsbridge.html
  27. BIN
      assets/images/flashlink.png
  28. BIN
      assets/images/flashlink_logo.png
  29. BIN
      assets/images/nomo.png
  30. BIN
      assets/images/nomo_logo.png
  31. 12 12
      assets/md/privacy.md
  32. 14 14
      assets/md/terms.md
  33. 6 6
      deploy/windows/setup.iss
  34. 14 14
      deploy/windows/terms.rtf
  35. 3 1
      ios/Podfile
  36. 1 90
      ios/Podfile.lock
  37. 6 6
      ios/Runner.xcodeproj/project.pbxproj
  38. 3 0
      ios/Runner.xcworkspace/contents.xcworkspacedata
  39. 12 12
      ios/Runner/CoreApi.g.swift
  40. 65 67
      ios/Runner/Info.plist
  41. 1 1
      lib/app/api/base/base_api.dart
  42. 2 2
      lib/app/api/core/api_core.dart
  43. 1 1
      lib/app/api/file/api_file.dart
  44. 1 1
      lib/app/api/log/api_log.dart
  45. 1 1
      lib/app/api/router/api_router.dart
  46. 3 3
      lib/app/app.dart
  47. 1 1
      lib/app/components/country_restricted_overlay.dart
  48. 1 1
      lib/app/components/ix_snackbar.dart
  49. 5 5
      lib/app/components/protocol_overlay.dart
  50. 4 4
      lib/app/constants/api_domains.dart
  51. 3 3
      lib/app/constants/assets.dart
  52. 6 6
      lib/app/constants/configs.dart
  53. 3 3
      lib/app/controllers/api_controller.dart
  54. 1 1
      lib/app/controllers/base_core_api.dart
  55. 3 3
      lib/app/controllers/core_controller.dart
  56. 1 1
      lib/app/controllers/mobile_core_api.dart
  57. 1 1
      lib/app/controllers/windows/tray_controller.dart
  58. 1 1
      lib/app/controllers/windows/vpn_service.dart
  59. 1 1
      lib/app/controllers/windows/window_controller.dart
  60. 7 5
      lib/app/controllers/windows_core_api.dart
  61. 3 3
      lib/app/dialog/all_dialog.dart
  62. 2 2
      lib/app/dialog/custom_dialog.dart
  63. 1 1
      lib/app/dialog/error_dialog.dart
  64. 1 1
      lib/app/dialog/feedback_bottom_sheet.dart
  65. 1 1
      lib/app/dialog/loading/loading_dialog.dart
  66. 1 1
      lib/app/dialog/loading/simple_loading_dialog.dart
  67. 1 1
      lib/app/dialog/update_dailog.dart
  68. 5 5
      lib/app/modules/account/views/account_view.dart
  69. 1 1
      lib/app/modules/deviceauth/controllers/deviceauth_controller.dart
  70. 4 4
      lib/app/modules/deviceauth/views/deviceauth_view.dart
  71. 2 2
      lib/app/modules/deviceauth/widgets/device_card.dart
  72. 1 1
      lib/app/modules/feedback/controllers/feedback_controller.dart
  73. 4 4
      lib/app/modules/feedback/views/feedback_view.dart
  74. 1 1
      lib/app/modules/forgotpwd/views/forgotpwd_view.dart
  75. 2 2
      lib/app/modules/home/controllers/home_controller.dart
  76. 4 4
      lib/app/modules/home/views/home_view.dart
  77. 1 1
      lib/app/modules/home/widgets/connection_button.dart
  78. 1 1
      lib/app/modules/home/widgets/connection_round_button.dart
  79. 2 2
      lib/app/modules/home/widgets/connection_theme_button.dart
  80. 4 4
      lib/app/modules/language/views/language_view.dart
  81. 3 3
      lib/app/modules/login/views/login_view.dart
  82. 1 1
      lib/app/modules/markdown/views/markdown_view.dart
  83. 1 1
      lib/app/modules/medialocation/views/medialocation_view.dart
  84. 2 2
      lib/app/modules/node/views/node_view.dart
  85. 2 2
      lib/app/modules/node/widgets/node_list.dart
  86. 1 1
      lib/app/modules/notfound/views/notfound_view.dart
  87. 1 1
      lib/app/modules/precode/controllers/precode_controller.dart
  88. 1 1
      lib/app/modules/precode/sendemail/controllers/precode_sendemail_controller.dart
  89. 3 3
      lib/app/modules/precode/sendemail/views/precode_sendemail_view.dart
  90. 4 4
      lib/app/modules/precode/views/precode_view.dart
  91. 2 2
      lib/app/modules/precode/widgets/precode_save_dialog.dart
  92. 2 2
      lib/app/modules/routingmode/controllers/routingmode_controller.dart
  93. 4 4
      lib/app/modules/routingmode/views/routingmode_view.dart
  94. 8 8
      lib/app/modules/setting/views/setting_view.dart
  95. 1 1
      lib/app/modules/signup/views/signup_view.dart
  96. 1 1
      lib/app/modules/splash/controllers/splash_controller.dart
  97. 4 4
      lib/app/modules/splash/views/splash_view.dart
  98. 2 2
      lib/app/modules/splittunneling/controllers/splittunneling_controller.dart
  99. 5 5
      lib/app/modules/splittunneling/selectapp/controllers/splittunneling_selectapp_controller.dart
  100. 5 5
      lib/app/modules/splittunneling/selectapp/views/splittunneling_selectapp_view.dart

+ 4 - 3
README.md

@@ -1,8 +1,9 @@
-# ixVPN - Flutter VPN 应用
+# FlashLink VPN - Flutter VPN 应用
 
-ixVPN 是一个基于 Flutter 开发的跨平台 VPN 应用,支持 Android、iOS、macOS、Windows 和 Linux 平台。
+FlashLink VPN 是一个基于 Flutter 开发的跨平台 VPN 应用,支持 Android、iOS、macOS、Windows 和 Linux 平台。
 ## build command
-1. 请先确保`util/constants.dart`中`debug[*]`相关配置项的值为`false`
+
+1. 请先确保`lib/app/constants/configs.dart`中`Configs.debug`的值为`false`
 2. 确认pubspec.yaml 文件中[version]版本号
 3. 执行对应平台的编译命令
 

+ 10 - 8
android/app/build.gradle.kts

@@ -16,7 +16,7 @@ if (keystorePropertiesFile.exists()) {
 }
 
 android {
-    namespace = "app.xixi.nomo"
+    namespace = "com.flashlink.vpn"
     compileSdk = flutter.compileSdkVersion
     ndkVersion = flutter.ndkVersion
 
@@ -31,7 +31,7 @@ android {
 
     defaultConfig {
         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
-        applicationId = "app.xixi.nomo"
+        applicationId = "com.flashlink.vpn"
         // You can update the following values to match your application needs.
         // For more information, see: https://flutter.dev/to/review-gradle-config.
         minSdk = flutter.minSdkVersion
@@ -51,13 +51,13 @@ android {
         create("googleDev") {
             dimension = "env"
            applicationIdSuffix = ".dev"
-            resValue("string", "app_name", "NOMO Dev")
+            resValue("string", "app_name", "flashlink Dev")
             manifestPlaceholders["CHANNEL"] = "google"
         }
         create("universalDev") {
             dimension = "env"
            applicationIdSuffix = ".dev"
-            resValue("string", "app_name", "NOMO Dev")
+            resValue("string", "app_name", "flashlink Dev")
             manifestPlaceholders["CHANNEL"] = "universal"
         }
         create("googleProd") {
@@ -109,14 +109,16 @@ android {
 
     buildTypes {
         release {
-            // TODO: Add your own signing config for the release build.
-            // Signing with the debug keys for now, so `flutter run --release` works.
-            signingConfig = signingConfigs.getByName("release")
+            if (keystorePropertiesFile.exists()) {
+                signingConfig = signingConfigs.getByName("release")
+            } else {
+                signingConfig = signingConfigs.getByName("debug")
+            }
             isShrinkResources = false
             isMinifyEnabled = false
         }
         debug {
-            signingConfig = signingConfigs.getByName("release")
+            // 使用默认 debug 签名
         }
     }
 }

+ 30 - 71
android/app/src/main/AndroidManifest.xml

@@ -1,105 +1,64 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
 
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
     <!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
-    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
-    <uses-permission android:name="android:activate_vpn" />
-    <uses-permission
-        android:name="android.permission.PACKAGE_USAGE_STATS"
-        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
+    <uses-permission android:name="android:activate_vpn"/>
+    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions"/>
 
     <!-- 仅在 Android 10 及以下版本需要存储权限 -->
-    <uses-permission
-        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
-        android:maxSdkVersion="29" />
-    <uses-permission
-        android:name="android.permission.READ_EXTERNAL_STORAGE"
-        android:maxSdkVersion="29" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
 
     <queries>
         <intent>
-            <action android:name="android.intent.action.VIEW" />
-            <data android:scheme="https" />
+            <action android:name="android.intent.action.VIEW"/>
+            <data android:scheme="https"/>
         </intent>
     </queries>
 
     <queries>
         <intent>
-            <action android:name="android.intent.action.MAIN" />
-            <category android:name="android.intent.category.LAUNCHER" />
+            <action android:name="android.intent.action.MAIN"/>
+            <category android:name="android.intent.category.LAUNCHER"/>
         </intent>
     </queries>
 
     <queries>
         <intent>
-            <action android:name="android.intent.action.MAIN" />
-            <category android:name="android.intent.category.APP_BROWSER" />
+            <action android:name="android.intent.action.MAIN"/>
+            <category android:name="android.intent.category.APP_BROWSER"/>
         </intent>
     </queries>
 
-    <application
-        android:name=".App"
-        android:allowBackup="false"
-        android:enableOnBackInvokedCallback="false"
-        android:fullBackupContent="false"
-        android:hardwareAccelerated="true"
-        android:icon="@mipmap/launcher_icon"
-        android:label="@string/app_name"
-        android:requestLegacyExternalStorage="true"
-        android:usesCleartextTraffic="true"
-        tools:targetApi="tiramisu">
-        <activity
-            android:name=".MainActivity"
-            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
-            android:exported="true"
-            android:hardwareAccelerated="true"
-            android:launchMode="singleTop"
-            android:theme="@style/LaunchTheme"
-            android:windowSoftInputMode="adjustResize">
+    <application android:name=".App" android:allowBackup="false" android:enableOnBackInvokedCallback="false" android:fullBackupContent="false" android:hardwareAccelerated="true" android:icon="@mipmap/launcher_icon" android:label="FlashLink VPN" android:requestLegacyExternalStorage="true" android:usesCleartextTraffic="true" tools:targetApi="tiramisu">
+        <activity android:name=".MainActivity" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:exported="true" android:hardwareAccelerated="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:windowSoftInputMode="adjustResize">
             <!-- Specifies an Android theme to apply to this Activity as soon as
                  the Android process has started. This theme is visible to the user
                  while the Flutter UI initializes. After that, this theme continues
                  to determine the Window background behind the Flutter UI. -->
-            <meta-data
-                android:name="io.flutter.embedding.android.NormalTheme"
-                android:resource="@style/NormalTheme" />
+            <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme"/>
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
 
-        <service
-            android:name=".XRayService"
-            android:directBootAware="true"
-            android:exported="false"
-            android:foregroundServiceType="specialUse"
-            android:label="@string/app_name"
-            android:permission="android.permission.BIND_VPN_SERVICE"
-            android:process=":vpn_service">
+        <service android:name=".XRayService" android:directBootAware="true" android:exported="false" android:foregroundServiceType="specialUse" android:label="@string/app_name" android:permission="android.permission.BIND_VPN_SERVICE" android:process=":vpn_service">
             <intent-filter>
-                <action android:name="android.net.VpnService" />
+                <action android:name="android.net.VpnService"/>
             </intent-filter>
-            <meta-data
-                android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
-                android:value="false" />
-            <property
-                android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
-                android:value="vpn" />
+            <meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON" android:value="false"/>
+            <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="vpn"/>
         </service>
         <!-- Don't delete the meta-data below.
              This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
-        <meta-data
-            android:name="flutterEmbedding"
-            android:value="2" />
-        <meta-data
-            android:name="channel"
-            android:value="${CHANNEL}" />
+        <meta-data android:name="flutterEmbedding" android:value="2"/>
+        <meta-data android:name="channel" android:value="${CHANNEL}"/>
     </application>
     <!-- Required to query activities that can process text, see:
          https://developer.android.com/training/package-visibility and
@@ -108,8 +67,8 @@
          In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
     <queries>
         <intent>
-            <action android:name="android.intent.action.PROCESS_TEXT" />
-            <data android:mimeType="text/plain" />
+            <action android:name="android.intent.action.PROCESS_TEXT"/>
+            <data android:mimeType="text/plain"/>
         </intent>
     </queries>
 </manifest>

+ 0 - 8
android/app/src/main/kotlin/app/xixi/nomo/Broadcasts.kt

@@ -1,8 +0,0 @@
-package app.xixi.nomo
-
-const val STATUS_BROADCAST = "app.xixi.nomo.STATUS"
-const val TIMER_BROADCAST = "app.xixi.nomo.TIMER"
-
-const val APP_FOREGROUND_BROADCAST = "app.xixi.nomo.APP_FOREGROUND"
-
-const val BOOST_RESULT_BROADCAST = "app.xixi.nomo.BOOST_RESULT"

+ 0 - 114
android/app/src/main/kotlin/app/xixi/nomo/MainActivity.kt

@@ -1,114 +0,0 @@
-package app.xixi.nomo
-
-import android.app.ComponentCaller
-import android.content.Intent
-import android.graphics.Color
-import io.flutter.embedding.android.FlutterActivity
-import io.flutter.embedding.engine.FlutterEngine
-import android.util.Log
-import androidx.core.view.WindowCompat
-
-class MainActivity: FlutterActivity() {
-
-    private lateinit var coreApiImpl: CoreApiImpl
-    companion object {
-        private const val TAG = "MainActivity"
-    }
-    
-//    override fun provideFlutterEngine(context: android.content.Context): FlutterEngine? {
-//        // 使用预初始化的Flutter引擎
-//        val engine = App.getFlutterEngine()
-//        if (engine != null) {
-//            // 确保引擎状态正确
-//            engine.lifecycleChannel.appIsResumed()
-//            Log.d(TAG, "使用预初始化的Flutter引擎")
-//        } else {
-//            Log.w(TAG, "预初始化的Flutter引擎未找到,将创建新引擎")
-//        }
-//        return engine
-//    }
-    
-    override fun onCreate(savedInstanceState: android.os.Bundle?) {
-        super.onCreate(savedInstanceState)
-        VLog.init(this, "client")
-        // 1. Edge-to-Edge 布局(内容延伸到状态栏和导航栏)
-        WindowCompat.setDecorFitsSystemWindows(window, false)
-
-        // 2. 针对Android 14+的系统导航栏透明处理
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
-            // Android 14+ 使用新的API
-            window.isNavigationBarContrastEnforced = false
-            window.navigationBarColor = Color.TRANSPARENT
-            window.statusBarColor = Color.TRANSPARENT
-        } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
-            // Android 11+ 使用WindowInsetsController
-            window.insetsController?.let { controller ->
-                controller.systemBarsBehavior = 
-                    android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
-                controller.setSystemBarsAppearance(
-                    android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS,
-                    android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
-                )
-            }
-            window.navigationBarColor = Color.TRANSPARENT
-            window.statusBarColor = Color.TRANSPARENT
-        } else {
-            // Android 10及以下使用传统方法
-            window.decorView.systemUiVisibility = (
-                android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
-                android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
-                android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-            )
-            window.navigationBarColor = Color.TRANSPARENT
-            window.statusBarColor = Color.TRANSPARENT
-        }
-
-        Log.d(TAG, "MainActivity onCreate - 进程ID: ${android.os.Process.myPid()}")
-    }
-
-    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
-        super.configureFlutterEngine(flutterEngine)
-        val messenger = flutterEngine.dartExecutor.binaryMessenger
-        
-        // 创建 CoreApiImpl 实例
-        coreApiImpl = CoreApiImpl(this)
-
-        // 初始化 XrayApi
-        coreApiImpl.initXrayApi();
-        
-        // 设置 XRayApi 状态监听
-        coreApiImpl.setVpnServiceEventListener()
-        
-        // 设置 CoreApi
-        CoreApi.setUp(messenger, coreApiImpl)
-        
-        // 注册事件流处理器
-        coreApiImpl.registerEventStreamHandler(messenger)
-        
-        Log.d(TAG, "CoreApi 和事件流处理器已配置完成")
-    }
-
-//    override fun onResume() {
-//        super.onResume()
-//        coreApiImpl.xrayInit()
-//    }
-//
-//    override fun onPause() {
-//        super.onPause()
-//        coreApiImpl.xrayUnInit()
-//    }
-
-    override fun onActivityResult(
-        requestCode: Int,
-        resultCode: Int,
-        data: Intent?
-    ) {
-        super.onActivityResult(requestCode, resultCode, data)
-        coreApiImpl.onActivityResult(requestCode, resultCode, data)
-    }
-
-    override fun onDestroy() {
-        coreApiImpl.unInitXrayApi()
-        super.onDestroy()
-    }
-}

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/Actions.kt → android/app/src/main/kotlin/com/flashlink/vpn/Actions.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 const val START_ACTION = "start"
 const val STOP_ACTION = "stop"

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/App.kt → android/app/src/main/kotlin/com/flashlink/vpn/App.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.app.Application
 import android.content.Context

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/AppLogger.kt → android/app/src/main/kotlin/com/flashlink/vpn/AppLogger.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.annotation.SuppressLint
 import android.content.Context

+ 8 - 0
android/app/src/main/kotlin/com/flashlink/vpn/Broadcasts.kt

@@ -0,0 +1,8 @@
+package com.flashlink.vpn
+
+const val STATUS_BROADCAST = "com.flashlink.vpn.STATUS"
+const val TIMER_BROADCAST = "com.flashlink.vpn.TIMER"
+
+const val APP_FOREGROUND_BROADCAST = "com.flashlink.vpn.APP_FOREGROUND"
+
+const val BOOST_RESULT_BROADCAST = "com.flashlink.vpn.BOOST_RESULT"

+ 12 - 12
android/app/src/main/kotlin/app/xixi/nomo/CoreApi.g.kt → android/app/src/main/kotlin/com/flashlink/vpn/CoreApi.g.kt

@@ -82,7 +82,7 @@ interface CoreApi {
     fun setUp(binaryMessenger: BinaryMessenger, api: CoreApi?, messageChannelSuffix: String = "") {
       val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getApps$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getApps$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             api.getApps{ result: Result<String?> ->
@@ -100,7 +100,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getSystemLocale$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getSystemLocale$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             val wrapped: List<Any?> = try {
@@ -115,7 +115,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.connect$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.connect$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             val args = message as List<Any?>
@@ -147,7 +147,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.disconnect$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.disconnect$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             val wrapped: List<Any?> = try {
@@ -162,7 +162,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getRemoteIp$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getRemoteIp$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             val wrapped: List<Any?> = try {
@@ -177,7 +177,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getAdvertisingId$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getAdvertisingId$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             val wrapped: List<Any?> = try {
@@ -192,7 +192,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.moveTaskToBack$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.moveTaskToBack$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             val wrapped: List<Any?> = try {
@@ -207,7 +207,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.isConnected$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.isConnected$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             val wrapped: List<Any?> = try {
@@ -222,7 +222,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getSimInfo$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getSimInfo$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             val wrapped: List<Any?> = try {
@@ -237,7 +237,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getChannel$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getChannel$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             val wrapped: List<Any?> = try {
@@ -252,7 +252,7 @@ interface CoreApi {
         }
       }
       run {
-        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.openPackage$separatedMessageChannelSuffix", codec)
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.openPackage$separatedMessageChannelSuffix", codec)
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             val args = message as List<Any?>
@@ -312,7 +312,7 @@ class PigeonEventSink<T>(private val sink: EventChannel.EventSink) {
 abstract class OnEventChangeStreamHandler : CoreApiPigeonEventChannelWrapper<String> {
   companion object {
     fun register(messenger: BinaryMessenger, streamHandler: OnEventChangeStreamHandler, instanceName: String = "") {
-      var channelName: String = "dev.flutter.pigeon.app.xixi.nomo.CoreChangeEventApi.onEventChange"
+      var channelName: String = "dev.flutter.pigeon.com.flashlink.vpn.CoreChangeEventApi.onEventChange"
       if (instanceName.isNotEmpty()) {
         channelName += ".$instanceName"
       }

+ 3 - 3
android/app/src/main/kotlin/app/xixi/nomo/CoreApiImpl.kt → android/app/src/main/kotlin/com/flashlink/vpn/CoreApiImpl.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import CoreApi
 import FlutterError
@@ -18,8 +18,8 @@ import android.telephony.TelephonyManager
 import android.util.Base64
 import android.util.Log
 import androidx.core.graphics.createBitmap
-import app.xixi.nomo.XRayApi.Companion.VPN_STATE_ERROR
-import app.xixi.nomo.XRayApi.OnVpnServiceEvent
+import com.flashlink.vpn.XRayApi.Companion.VPN_STATE_ERROR
+import com.flashlink.vpn.XRayApi.OnVpnServiceEvent
 import com.google.gson.Gson
 import com.google.gson.JsonArray
 import com.google.gson.JsonElement

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/CoreLogger.kt → android/app/src/main/kotlin/com/flashlink/vpn/CoreLogger.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.annotation.SuppressLint
 import android.content.Context

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/CryptoUtils.kt → android/app/src/main/kotlin/com/flashlink/vpn/CryptoUtils.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.util.Base64
 import java.io.ByteArrayInputStream

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/ErrorCode.kt → android/app/src/main/kotlin/com/flashlink/vpn/ErrorCode.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 const val ERROR_INIT = 1100L // vpn初始化失败
 const val ERROR_KILL = 1101L // 服务异常kill

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/LifecycleVpnService.kt → android/app/src/main/kotlin/com/flashlink/vpn/LifecycleVpnService.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.content.Intent
 import android.net.VpnService

+ 5 - 5
android/app/src/main/kotlin/app/xixi/nomo/NetworkReporter.kt → android/app/src/main/kotlin/com/flashlink/vpn/NetworkReporter.kt

@@ -1,8 +1,8 @@
 package win.fkey.netboost.service
 
-import app.xixi.nomo.CryptoUtils
-import app.xixi.nomo.VLog
-import app.xixi.nomo.XrayConfig
+import com.flashlink.vpn.CryptoUtils
+import com.flashlink.vpn.VLog
+import com.flashlink.vpn.XrayConfig
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
@@ -69,7 +69,7 @@ class NetworkReporter private constructor() {
 
     data class ItemsParamConfig(
         val module: String,
-        var category: String = "nomo",
+        var category: String = "flashlink",
         var level: String = "info",
         val defaultFields: MutableMap<String, Any> = HashMap(),
         var useDynamicFields: Boolean = false
@@ -319,7 +319,7 @@ class NetworkReporter private constructor() {
 
             connection.requestMethod = "POST"
             connection.setRequestProperty("Content-Type", "application/json")
-            connection.setRequestProperty("X-NL-Product-Code", "nomo")
+            connection.setRequestProperty("X-NL-Product-Code", "flashlink")
             connection.setRequestProperty("X-NL-Content-Encoding", "gzip")
 
             token?.takeIf { it.isNotEmpty() }?.let {

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/NotificationUtils.kt → android/app/src/main/kotlin/com/flashlink/vpn/NotificationUtils.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.app.Notification
 import android.app.NotificationChannel

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/ServiceStatus.kt → android/app/src/main/kotlin/com/flashlink/vpn/ServiceStatus.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 enum class ServiceStatus {
     Disconnected,

+ 2 - 2
android/app/src/main/kotlin/app/xixi/nomo/TProxyService.kt → android/app/src/main/kotlin/com/flashlink/vpn/TProxyService.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.content.Context
 import android.util.Log
@@ -11,7 +11,7 @@ internal class TProxyService {
     external fun TProxyGetStats(): LongArray
 
     companion object {
-        private const val TAG = "ixvpn"
+        private const val TAG = "flashlink"
 
         init {
             try {

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/VLog.kt → android/app/src/main/kotlin/com/flashlink/vpn/VLog.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.content.Context
 import android.util.Log

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/XRayApi.kt → android/app/src/main/kotlin/com/flashlink/vpn/XRayApi.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.app.ActivityManager
 import android.content.BroadcastReceiver

+ 15 - 15
android/app/src/main/kotlin/app/xixi/nomo/XRayService.kt → android/app/src/main/kotlin/com/flashlink/vpn/XRayService.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import android.app.Notification
 import android.content.BroadcastReceiver
@@ -13,14 +13,14 @@ import android.os.PowerManager
 import android.os.SystemClock
 import androidx.core.content.ContextCompat
 import androidx.lifecycle.lifecycleScope
-import app.xixi.nomo.App.Companion.EXTRA_IS_FOREGROUND
-import app.xixi.nomo.XRayApi.Companion.VPN_STATE_CONNECTED
-import app.xixi.nomo.XRayApi.Companion.VPN_STATE_ERROR
-import app.xixi.nomo.XRayApi.Companion.VPN_STATE_IDLE
+import com.flashlink.vpn.App.Companion.EXTRA_IS_FOREGROUND
+import com.flashlink.vpn.XRayApi.Companion.VPN_STATE_CONNECTED
+import com.flashlink.vpn.XRayApi.Companion.VPN_STATE_ERROR
+import com.flashlink.vpn.XRayApi.Companion.VPN_STATE_IDLE
 import com.google.gson.Gson
 import go.Seq
-import ixvpn_mobile.Ixvpn_mobile
-import ixvpn_mobile.ProxyConnectorHandler
+import flashlink_mobile.FlashLink_mobile
+import flashlink_mobile.ProxyConnectorHandler
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.isActive
@@ -67,7 +67,7 @@ class XRayService : LifecycleVpnService() {
         private val TAG: String = XRayService::class.java.simpleName
 
         private const val FOREGROUND_SERVICE_ID: Int = 1
-        private const val NOTIFICATION_CHANNEL_ID: String = "NOMO"
+        private const val NOTIFICATION_CHANNEL_ID: String = "flashlink"
 
         // 计时模式常量
         const val TIMER_MODE_NORMAL = 0  // 普通计时(正计时)
@@ -88,7 +88,7 @@ class XRayService : LifecycleVpnService() {
         VLog.i(TAG, "XRayService onCreate")
 
         Seq.setContext(applicationContext)
-        Ixvpn_mobile.initProxyConnector(0, getXrayLog())
+        FlashLink_mobile.initProxyConnector(0, getXrayLog())
         registerNotificationChannel(
             this,
             NOTIFICATION_CHANNEL_ID,
@@ -240,7 +240,7 @@ class XRayService : LifecycleVpnService() {
 
         // 清理资源
         try {
-            Ixvpn_mobile.freeProxyConnector()
+            FlashLink_mobile.freeProxyConnector()
         } catch (e: Exception) {
             VLog.e(TAG, "freeProxyConnector 失败", e)
         }
@@ -325,7 +325,7 @@ class XRayService : LifecycleVpnService() {
         tunFd?.let { tfd ->
             VLog.i(TAG, "VPN tunnel established, fd: ${tfd.fd}")
             tunnelService.startTunnel(this, config.socksPort, config.tunnelConfig, tfd.fd)
-            Ixvpn_mobile.proxyConnectorStart(config.sessionId, config.startOptions, vpnHandler)
+            FlashLink_mobile.proxyConnectorStart(config.sessionId, config.startOptions, vpnHandler)
             VLog.i(TAG, "XRay proxy started successfully")
         } ?: run {
             VLog.e(TAG, "Failed to establish VPN tunnel")
@@ -407,7 +407,7 @@ class XRayService : LifecycleVpnService() {
      */
     private fun queryStats(vararg types: Byte): String? {
         return try {
-            Ixvpn_mobile.proxyConnectorQueryStats(types)
+            FlashLink_mobile.proxyConnectorQueryStats(types)
         } catch (e: Exception) {
             VLog.e(TAG, "queryStats error: ${e.message}")
             null
@@ -498,7 +498,7 @@ class XRayService : LifecycleVpnService() {
 
     private fun stopProxyConnector() {
         try {
-            Ixvpn_mobile.proxyConnectorStop()
+            FlashLink_mobile.proxyConnectorStop()
             VLog.i(TAG, "Proxy connector stopped")
         } catch (e: Exception) {
             VLog.e(TAG, "停止 proxy connector 失败", e)
@@ -527,7 +527,7 @@ class XRayService : LifecycleVpnService() {
         createConnectionNotification(
             this,
             NOTIFICATION_CHANNEL_ID,
-            "NOMO VPN",
+            "FlashLink VPN",
             "Service is running",
         )
 
@@ -612,7 +612,7 @@ class XRayService : LifecycleVpnService() {
      */
     private fun dealStat() {
         val stats = queryStats(1, 2, 3) // 连接历史、带宽、最大速度
-        val version = Ixvpn_mobile.proxyConnectorVersion()
+        val version = FlashLink_mobile.proxyConnectorVersion()
         VLog.i(TAG, "stats = $stats")
 
         // 将 stats 和 version 写入 core.json 日志文件

+ 1 - 1
android/app/src/main/kotlin/app/xixi/nomo/XrayConfig.kt → android/app/src/main/kotlin/com/flashlink/vpn/XrayConfig.kt

@@ -1,4 +1,4 @@
-package app.xixi.nomo
+package com.flashlink.vpn
 
 import com.google.gson.Gson
 

+ 1 - 1
android/app/src/main/res/values/strings.xml

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <string name="app_name">NOMO</string>
+    <string name="app_name">flashlink</string>
 </resources>

+ 4 - 0
android/gradle.properties

@@ -1,3 +1,7 @@
 org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
 android.useAndroidX=true
 android.enableJetifier=true
+# This builtInKotlin flag was added automatically by Flutter migrator
+android.builtInKotlin=false
+# This newDsl flag was added automatically by Flutter migrator
+android.newDsl=false

+ 465 - 438
assets/html/test_jsbridge.html

@@ -1,455 +1,482 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="zh-CN">
-<head>
-  <meta charset="UTF-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>NOMO JS Bridge 测试</title>
-  <style>
-    * {
-      margin: 0;
-      padding: 0;
-      box-sizing: border-box;
-    }
-    
-    body {
-      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
-      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-      color: #333;
-      /* 使用原生属性设置安全边距 */
-      padding-top: calc(var(--status-bar-height, 0px) + 10px);
-      padding-bottom: calc(var(--bottom-bar-height, 0px) + 10px);
-      min-height: 100vh;
-    }
-    
-    .container {
-      max-width: 600px;
-      margin: 0 auto;
-      padding: 15px;
-    }
-    
-    .header {
-      background: white;
-      border-radius: 15px;
-      padding: 20px;
-      margin-bottom: 15px;
-      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
-    }
-    
-    .header h1 {
-      font-size: 24px;
-      margin-bottom: 15px;
-      color: #667eea;
-    }
-    
-    .info-grid {
-      display: grid;
-      grid-template-columns: 1fr 1fr;
-      gap: 10px;
-      font-size: 13px;
-    }
-    
-    .info-item {
-      background: #f8f9fa;
-      padding: 10px;
-      border-radius: 8px;
-    }
-    
-    .info-label {
-      color: #666;
-      font-size: 11px;
-      margin-bottom: 5px;
-    }
-    
-    .info-value {
-      color: #333;
-      font-weight: 600;
-      word-break: break-all;
-    }
-    
-    .card {
-      background: white;
-      border-radius: 15px;
-      padding: 20px;
-      margin-bottom: 15px;
-      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
-    }
-    
-    .card h2 {
-      font-size: 18px;
-      margin-bottom: 15px;
-      color: #667eea;
-    }
-    
-    .vpn-status {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      padding: 15px;
-      background: #f8f9fa;
-      border-radius: 10px;
-      margin-bottom: 15px;
-    }
-    
-    .status-indicator {
-      display: flex;
-      align-items: center;
-      gap: 10px;
-    }
-    
-    .status-dot {
-      width: 12px;
-      height: 12px;
-      border-radius: 50%;
-      background-color: #ccc;
-      animation: pulse 2s infinite;
-    }
-    
-    .status-dot.connected {
-      background-color: #10b981;
-    }
-    
-    .status-dot.connecting {
-      background-color: #f59e0b;
-    }
-    
-    .status-dot.disconnected {
-      background-color: #ef4444;
-    }
-    
-    @keyframes pulse {
-      0%, 100% { opacity: 1; }
-      50% { opacity: 0.5; }
-    }
-    
-    .btn-grid {
-      display: grid;
-      grid-template-columns: 1fr 1fr;
-      gap: 10px;
-    }
-    
-    .btn {
-      padding: 12px 20px;
-      border: none;
-      border-radius: 10px;
-      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-      color: white;
-      font-size: 14px;
-      font-weight: 600;
-      cursor: pointer;
-      transition: transform 0.2s, box-shadow 0.2s;
-    }
-    
-    .btn:active {
-      transform: scale(0.95);
-    }
-    
-    .btn-full {
-      grid-column: 1 / -1;
-    }
-    
-    .btn-danger {
-      background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
-    }
-    
-    .btn-success {
-      background: linear-gradient(135deg, #10b981 0%, #059669 100%);
-    }
-    
-    .log {
-      background: #1e293b;
-      color: #94a3b8;
-      border-radius: 10px;
-      padding: 15px;
-      max-height: 300px;
-      overflow-y: auto;
-      font-size: 12px;
-      font-family: 'Courier New', monospace;
-    }
-    
-    .log-item {
-      margin-bottom: 8px;
-      line-height: 1.5;
-    }
-    
-    .log-time {
-      color: #64748b;
-    }
-    
-    .log-success {
-      color: #10b981;
-    }
-    
-    .log-error {
-      color: #ef4444;
-    }
-    
-    .log-info {
-      color: #3b82f6;
-    }
-  </style>
-</head>
-<body>
-  <div class="container">
-    <!-- 设备信息 -->
-    <div class="header">
-      <h1>🚀 NOMO JS Bridge</h1>
-      <div class="info-grid">
-        <div class="info-item">
-          <div class="info-label">状态栏高度</div>
-          <div class="info-value" id="statusBarHeight">-</div>
-        </div>
-        <div class="info-item">
-          <div class="info-label">底部安全区</div>
-          <div class="info-value" id="bottomBarHeight">-</div>
-        </div>
-        <div class="info-item">
-          <div class="info-label">平台</div>
-          <div class="info-value" id="platform">-</div>
-        </div>
-        <div class="info-item">
-          <div class="info-label">版本</div>
-          <div class="info-value" id="version">-</div>
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>FlashLink JS Bridge 测试</title>
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+        box-sizing: border-box;
+      }
+
+      body {
+        font-family:
+          -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
+          "Helvetica Neue", Arial, sans-serif;
+        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+        color: #333;
+        /* 使用原生属性设置安全边距 */
+        padding-top: calc(var(--status-bar-height, 0px) + 10px);
+        padding-bottom: calc(var(--bottom-bar-height, 0px) + 10px);
+        min-height: 100vh;
+      }
+
+      .container {
+        max-width: 600px;
+        margin: 0 auto;
+        padding: 15px;
+      }
+
+      .header {
+        background: white;
+        border-radius: 15px;
+        padding: 20px;
+        margin-bottom: 15px;
+        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+      }
+
+      .header h1 {
+        font-size: 24px;
+        margin-bottom: 15px;
+        color: #667eea;
+      }
+
+      .info-grid {
+        display: grid;
+        grid-template-columns: 1fr 1fr;
+        gap: 10px;
+        font-size: 13px;
+      }
+
+      .info-item {
+        background: #f8f9fa;
+        padding: 10px;
+        border-radius: 8px;
+      }
+
+      .info-label {
+        color: #666;
+        font-size: 11px;
+        margin-bottom: 5px;
+      }
+
+      .info-value {
+        color: #333;
+        font-weight: 600;
+        word-break: break-all;
+      }
+
+      .card {
+        background: white;
+        border-radius: 15px;
+        padding: 20px;
+        margin-bottom: 15px;
+        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+      }
+
+      .card h2 {
+        font-size: 18px;
+        margin-bottom: 15px;
+        color: #667eea;
+      }
+
+      .vpn-status {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        padding: 15px;
+        background: #f8f9fa;
+        border-radius: 10px;
+        margin-bottom: 15px;
+      }
+
+      .status-indicator {
+        display: flex;
+        align-items: center;
+        gap: 10px;
+      }
+
+      .status-dot {
+        width: 12px;
+        height: 12px;
+        border-radius: 50%;
+        background-color: #ccc;
+        animation: pulse 2s infinite;
+      }
+
+      .status-dot.connected {
+        background-color: #10b981;
+      }
+
+      .status-dot.connecting {
+        background-color: #f59e0b;
+      }
+
+      .status-dot.disconnected {
+        background-color: #ef4444;
+      }
+
+      @keyframes pulse {
+        0%,
+        100% {
+          opacity: 1;
+        }
+        50% {
+          opacity: 0.5;
+        }
+      }
+
+      .btn-grid {
+        display: grid;
+        grid-template-columns: 1fr 1fr;
+        gap: 10px;
+      }
+
+      .btn {
+        padding: 12px 20px;
+        border: none;
+        border-radius: 10px;
+        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+        color: white;
+        font-size: 14px;
+        font-weight: 600;
+        cursor: pointer;
+        transition:
+          transform 0.2s,
+          box-shadow 0.2s;
+      }
+
+      .btn:active {
+        transform: scale(0.95);
+      }
+
+      .btn-full {
+        grid-column: 1 / -1;
+      }
+
+      .btn-danger {
+        background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
+      }
+
+      .btn-success {
+        background: linear-gradient(135deg, #10b981 0%, #059669 100%);
+      }
+
+      .log {
+        background: #1e293b;
+        color: #94a3b8;
+        border-radius: 10px;
+        padding: 15px;
+        max-height: 300px;
+        overflow-y: auto;
+        font-size: 12px;
+        font-family: "Courier New", monospace;
+      }
+
+      .log-item {
+        margin-bottom: 8px;
+        line-height: 1.5;
+      }
+
+      .log-time {
+        color: #64748b;
+      }
+
+      .log-success {
+        color: #10b981;
+      }
+
+      .log-error {
+        color: #ef4444;
+      }
+
+      .log-info {
+        color: #3b82f6;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="container">
+      <!-- 设备信息 -->
+      <div class="header">
+        <h1>🚀 FlashLink JS Bridge</h1>
+        <div class="info-grid">
+          <div class="info-item">
+            <div class="info-label">状态栏高度</div>
+            <div class="info-value" id="statusBarHeight">-</div>
+          </div>
+          <div class="info-item">
+            <div class="info-label">底部安全区</div>
+            <div class="info-value" id="bottomBarHeight">-</div>
+          </div>
+          <div class="info-item">
+            <div class="info-label">平台</div>
+            <div class="info-value" id="platform">-</div>
+          </div>
+          <div class="info-item">
+            <div class="info-label">版本</div>
+            <div class="info-value" id="version">-</div>
+          </div>
         </div>
       </div>
-    </div>
-    
-    <!-- VPN 控制 -->
-    <div class="card">
-      <h2>🔐 VPN 控制</h2>
-      <div class="vpn-status">
-        <div class="status-indicator">
-          <div class="status-dot" id="statusDot"></div>
-          <div>
-            <div style="font-weight: 600;" id="vpnStatus">未知</div>
-            <div style="font-size: 12px; color: #666;" id="vpnTimer">00:00:00</div>
+
+      <!-- VPN 控制 -->
+      <div class="card">
+        <h2>🔐 VPN 控制</h2>
+        <div class="vpn-status">
+          <div class="status-indicator">
+            <div class="status-dot" id="statusDot"></div>
+            <div>
+              <div style="font-weight: 600" id="vpnStatus">未知</div>
+              <div style="font-size: 12px; color: #666" id="vpnTimer">
+                00:00:00
+              </div>
+            </div>
           </div>
         </div>
+        <div class="btn-grid">
+          <button class="btn btn-success" onclick="handleConnectVPN()">
+            ⚡ 连接
+          </button>
+          <button class="btn btn-danger" onclick="handleDisconnectVPN()">
+            ⏸️ 断开
+          </button>
+          <button class="btn btn-full" onclick="handleGetVPNStatus()">
+            🔍 查询状态
+          </button>
+        </div>
       </div>
-      <div class="btn-grid">
-        <button class="btn btn-success" onclick="handleConnectVPN()">
-          ⚡ 连接
-        </button>
-        <button class="btn btn-danger" onclick="handleDisconnectVPN()">
-          ⏸️ 断开
-        </button>
-        <button class="btn btn-full" onclick="handleGetVPNStatus()">
-          🔍 查询状态
-        </button>
+
+      <!-- 其他功能 -->
+      <div class="card">
+        <h2>🛠️ 其他功能</h2>
+        <div class="btn-grid">
+          <button class="btn" onclick="handleSetStatusBarColor()">
+            🎨 切换状态栏
+          </button>
+          <button class="btn" onclick="handleOpenApp()">📱 打开微信</button>
+          <button class="btn btn-danger btn-full" onclick="handleExit()">
+            ❌ 退出 WebView
+          </button>
+        </div>
       </div>
-    </div>
-    
-    <!-- 其他功能 -->
-    <div class="card">
-      <h2>🛠️ 其他功能</h2>
-      <div class="btn-grid">
-        <button class="btn" onclick="handleSetStatusBarColor()">
-          🎨 切换状态栏
-        </button>
-        <button class="btn" onclick="handleOpenApp()">
-          📱 打开微信
-        </button>
-        <button class="btn btn-danger btn-full" onclick="handleExit()">
-          ❌ 退出 WebView
-        </button>
+
+      <!-- 日志 -->
+      <div class="card">
+        <h2>📋 日志</h2>
+        <div class="log" id="logContainer"></div>
       </div>
     </div>
-    
-    <!-- 日志 -->
-    <div class="card">
-      <h2>📋 日志</h2>
-      <div class="log" id="logContainer"></div>
-    </div>
-  </div>
-  
-  <script>
-    let logCount = 0;
-    const maxLogs = 50;
-    
-    // 日志函数
-    function addLog(message, type = 'info') {
-      const logContainer = document.getElementById('logContainer');
-      const time = new Date().toLocaleTimeString('zh-CN', { hour12: false });
-      const logClass = `log-${type}`;
-      
-      const logItem = document.createElement('div');
-      logItem.className = 'log-item';
-      logItem.innerHTML = `<span class="log-time">[${time}]</span> <span class="${logClass}">${message}</span>`;
-      
-      logContainer.insertBefore(logItem, logContainer.firstChild);
-      
-      logCount++;
-      if (logCount > maxLogs) {
-        logContainer.removeChild(logContainer.lastChild);
-        logCount--;
-      }
-    }
-    
-    // 更新 VPN 状态显示
-    function updateVPNStatusUI(status) {
-      const statusDot = document.getElementById('statusDot');
-      const statusText = document.getElementById('vpnStatus');
-      
-      statusDot.className = 'status-dot ' + status;
-      
-      const statusMap = {
-        'connected': '已连接',
-        'connecting': '连接中',
-        'disconnected': '未连接',
-        'unknown': '未知'
-      };
-      
-      statusText.textContent = statusMap[status] || status;
-    }
-    
-    // 页面加载完成后初始化
-    window.onload = function() {
-      addLog('页面加载完成,等待原生注入...', 'info');
-      setTimeout(initNativeAttrs, 200);
-    };
-    
-    // 初始化原生属性
-    function initNativeAttrs() {
-      if (window.nativeAttrs) {
-        document.getElementById('statusBarHeight').textContent = window.nativeAttrs.statusBarHeight + 'px';
-        document.getElementById('bottomBarHeight').textContent = window.nativeAttrs.bottomBarHeight + 'px';
-        document.getElementById('platform').textContent = window.nativeAttrs.platform;
-        document.getElementById('version').textContent = window.nativeAttrs.version;
-        
-        // 设置 CSS 变量
-        document.documentElement.style.setProperty('--status-bar-height', window.nativeAttrs.statusBarHeight + 'px');
-        document.documentElement.style.setProperty('--bottom-bar-height', window.nativeAttrs.bottomBarHeight + 'px');
-        
-        addLog('✅ 原生属性注入成功', 'success');
-        addLog(`📱 平台: ${window.nativeAttrs.platform}, 版本: ${window.nativeAttrs.version}`, 'info');
-        
-        // 初始化 VPN 状态
-        handleGetVPNStatus();
-      } else {
-        addLog('❌ 原生属性注入失败', 'error');
-      }
-    }
-    
-    // 设置 VPN 状态回调
-    window.nativeCallbacks = {
-      onVPNStatusChanged: function(status) {
-        addLog(`📡 VPN 状态变化: ${status}`, 'info');
-        updateVPNStatusUI(status);
-      },
-      
-      onVPNConnected: function() {
-        addLog('✅ VPN 连接成功!', 'success');
-        updateVPNStatusUI('connected');
-      },
-      
-      onVPNConnecting: function() {
-        addLog('⏳ VPN 连接中...', 'info');
-        updateVPNStatusUI('connecting');
-      },
-      
-      onVPNDisconnected: function() {
-        addLog('⏸️ VPN 已断开', 'info');
-        updateVPNStatusUI('disconnected');
-      }
-    };
-    
-    // 功能函数
-    async function handleConnectVPN() {
-      try {
-        addLog('🚀 正在连接 VPN...', 'info');
-        const result = await window.native.connectVPN(26, 'ca');
-        if (result.success) {
-          addLog('✅ VPN 连接请求已发送', 'success');
-        } else {
-          addLog(`❌ 连接失败: ${result.error}`, 'error');
+
+    <script>
+      let logCount = 0;
+      const maxLogs = 50;
+
+      // 日志函数
+      function addLog(message, type = "info") {
+        const logContainer = document.getElementById("logContainer");
+        const time = new Date().toLocaleTimeString("zh-CN", { hour12: false });
+        const logClass = `log-${type}`;
+
+        const logItem = document.createElement("div");
+        logItem.className = "log-item";
+        logItem.innerHTML = `<span class="log-time">[${time}]</span> <span class="${logClass}">${message}</span>`;
+
+        logContainer.insertBefore(logItem, logContainer.firstChild);
+
+        logCount++;
+        if (logCount > maxLogs) {
+          logContainer.removeChild(logContainer.lastChild);
+          logCount--;
         }
-      } catch (error) {
-        addLog(`❌ 发生错误: ${error}`, 'error');
-      }
-    }
-    
-    async function handleDisconnectVPN() {
-      try {
-        addLog('⏸️ 正在断开 VPN...', 'info');
-        const result = await window.native.disconnectVPN();
-        if (result.success) {
-          addLog('✅ VPN 断开请求已发送', 'success');
+      }
+
+      // 更新 VPN 状态显示
+      function updateVPNStatusUI(status) {
+        const statusDot = document.getElementById("statusDot");
+        const statusText = document.getElementById("vpnStatus");
+
+        statusDot.className = "status-dot " + status;
+
+        const statusMap = {
+          connected: "已连接",
+          connecting: "连接中",
+          disconnected: "未连接",
+          unknown: "未知",
+        };
+
+        statusText.textContent = statusMap[status] || status;
+      }
+
+      // 页面加载完成后初始化
+      window.onload = function () {
+        addLog("页面加载完成,等待原生注入...", "info");
+        setTimeout(initNativeAttrs, 200);
+      };
+
+      // 初始化原生属性
+      function initNativeAttrs() {
+        if (window.nativeAttrs) {
+          document.getElementById("statusBarHeight").textContent =
+            window.nativeAttrs.statusBarHeight + "px";
+          document.getElementById("bottomBarHeight").textContent =
+            window.nativeAttrs.bottomBarHeight + "px";
+          document.getElementById("platform").textContent =
+            window.nativeAttrs.platform;
+          document.getElementById("version").textContent =
+            window.nativeAttrs.version;
+
+          // 设置 CSS 变量
+          document.documentElement.style.setProperty(
+            "--status-bar-height",
+            window.nativeAttrs.statusBarHeight + "px",
+          );
+          document.documentElement.style.setProperty(
+            "--bottom-bar-height",
+            window.nativeAttrs.bottomBarHeight + "px",
+          );
+
+          addLog("✅ 原生属性注入成功", "success");
+          addLog(
+            `📱 平台: ${window.nativeAttrs.platform}, 版本: ${window.nativeAttrs.version}`,
+            "info",
+          );
+
+          // 初始化 VPN 状态
+          handleGetVPNStatus();
         } else {
-          addLog(`❌ 断开失败: ${result.error}`, 'error');
+          addLog("❌ 原生属性注入失败", "error");
         }
-      } catch (error) {
-        addLog(`❌ 发生错误: ${error}`, 'error');
-      }
-    }
-    
-    async function handleGetVPNStatus() {
-      try {
-        const result = await window.native.getVPNStatus();
-        if (result.success) {
-          const status = result.data.status;
-          const timer = result.data.timer;
-          
-          document.getElementById('vpnTimer').textContent = timer;
+      }
+
+      // 设置 VPN 状态回调
+      window.nativeCallbacks = {
+        onVPNStatusChanged: function (status) {
+          addLog(`📡 VPN 状态变化: ${status}`, "info");
           updateVPNStatusUI(status);
-          
-          addLog(`📊 VPN 状态: ${status}, 时长: ${timer}`, 'info');
-        } else {
-          addLog(`❌ 查询失败: ${result.error}`, 'error');
+        },
+
+        onVPNConnected: function () {
+          addLog("✅ VPN 连接成功!", "success");
+          updateVPNStatusUI("connected");
+        },
+
+        onVPNConnecting: function () {
+          addLog("⏳ VPN 连接中...", "info");
+          updateVPNStatusUI("connecting");
+        },
+
+        onVPNDisconnected: function () {
+          addLog("⏸️ VPN 已断开", "info");
+          updateVPNStatusUI("disconnected");
+        },
+      };
+
+      // 功能函数
+      async function handleConnectVPN() {
+        try {
+          addLog("🚀 正在连接 VPN...", "info");
+          const result = await window.native.connectVPN(26, "ca");
+          if (result.success) {
+            addLog("✅ VPN 连接请求已发送", "success");
+          } else {
+            addLog(`❌ 连接失败: ${result.error}`, "error");
+          }
+        } catch (error) {
+          addLog(`❌ 发生错误: ${error}`, "error");
         }
-      } catch (error) {
-        addLog(`❌ 发生错误: ${error}`, 'error');
-      }
-    }
-    
-    async function handleSetStatusBarColor() {
-      // 只支持 dark 和 light 两种模式
-      const currentMode = document.body.dataset.statusBarMode || 'light';
-      const newMode = currentMode === 'dark' ? 'light' : 'dark';
-      
-      try {
-        addLog(`🎨 切换状态栏模式: ${currentMode} -> ${newMode}`, 'info');
-        const result = await window.native.setStatusBarColor(newMode);
-        if (result.success) {
-          document.body.dataset.statusBarMode = newMode;
-          addLog(`✅ 状态栏模式切换成功: ${newMode} (${newMode === 'dark' ? '白色图标' : '黑色图标'})`, 'success');
-        } else {
-          addLog(`❌ 设置失败: ${result.error}`, 'error');
+      }
+
+      async function handleDisconnectVPN() {
+        try {
+          addLog("⏸️ 正在断开 VPN...", "info");
+          const result = await window.native.disconnectVPN();
+          if (result.success) {
+            addLog("✅ VPN 断开请求已发送", "success");
+          } else {
+            addLog(`❌ 断开失败: ${result.error}`, "error");
+          }
+        } catch (error) {
+          addLog(`❌ 发生错误: ${error}`, "error");
         }
-      } catch (error) {
-        addLog(`❌ 发生错误: ${error}`, 'error');
-      }
-    }
-    
-    async function handleOpenApp() {
-      try {
-        addLog('📱 正在打开微信...', 'info');
-        const result = await window.native.openApp('com.tencent.mm', 'weixin://');
-        if (result.success) {
-          addLog('✅ 应用已打开', 'success');
-        } else {
-          addLog(`❌ 打开失败: ${result.error}`, 'error');
+      }
+
+      async function handleGetVPNStatus() {
+        try {
+          const result = await window.native.getVPNStatus();
+          if (result.success) {
+            const status = result.data.status;
+            const timer = result.data.timer;
+
+            document.getElementById("vpnTimer").textContent = timer;
+            updateVPNStatusUI(status);
+
+            addLog(`📊 VPN 状态: ${status}, 时长: ${timer}`, "info");
+          } else {
+            addLog(`❌ 查询失败: ${result.error}`, "error");
+          }
+        } catch (error) {
+          addLog(`❌ 发生错误: ${error}`, "error");
         }
-      } catch (error) {
-        addLog(`❌ 发生错误: ${error}`, 'error');
-      }
-    }
-    
-    async function handleExit() {
-      try {
-        addLog('👋 正在退出 WebView...', 'info');
-        await window.native.exit();
-      } catch (error) {
-        addLog(`❌ 退出失败: ${error}`, 'error');
-      }
-    }
-    
-    // 监听 VPN 状态变化事件
-    window.addEventListener('vpnStatusChanged', function(event) {
-      console.log('收到 VPN 状态变化事件:', event.detail.status);
-    });
-    
-    // 初始日志
-    addLog('🎉 欢迎使用 NOMO JS Bridge 测试页面', 'success');
-  </script>
-</body>
-</html>
+      }
+
+      async function handleSetStatusBarColor() {
+        // 只支持 dark 和 light 两种模式
+        const currentMode = document.body.dataset.statusBarMode || "light";
+        const newMode = currentMode === "dark" ? "light" : "dark";
 
+        try {
+          addLog(`🎨 切换状态栏模式: ${currentMode} -> ${newMode}`, "info");
+          const result = await window.native.setStatusBarColor(newMode);
+          if (result.success) {
+            document.body.dataset.statusBarMode = newMode;
+            addLog(
+              `✅ 状态栏模式切换成功: ${newMode} (${newMode === "dark" ? "白色图标" : "黑色图标"})`,
+              "success",
+            );
+          } else {
+            addLog(`❌ 设置失败: ${result.error}`, "error");
+          }
+        } catch (error) {
+          addLog(`❌ 发生错误: ${error}`, "error");
+        }
+      }
+
+      async function handleOpenApp() {
+        try {
+          addLog("📱 正在打开微信...", "info");
+          const result = await window.native.openApp(
+            "com.tencent.mm",
+            "weixin://",
+          );
+          if (result.success) {
+            addLog("✅ 应用已打开", "success");
+          } else {
+            addLog(`❌ 打开失败: ${result.error}`, "error");
+          }
+        } catch (error) {
+          addLog(`❌ 发生错误: ${error}`, "error");
+        }
+      }
+
+      async function handleExit() {
+        try {
+          addLog("👋 正在退出 WebView...", "info");
+          await window.native.exit();
+        } catch (error) {
+          addLog(`❌ 退出失败: ${error}`, "error");
+        }
+      }
+
+      // 监听 VPN 状态变化事件
+      window.addEventListener("vpnStatusChanged", function (event) {
+        console.log("收到 VPN 状态变化事件:", event.detail.status);
+      });
+
+      // 初始日志
+      addLog("🎉 欢迎使用 FlashLink JS Bridge 测试页面", "success");
+    </script>
+  </body>
+</html>

BIN
assets/images/flashlink.png


BIN
assets/images/flashlink_logo.png


BIN
assets/images/nomo.png


BIN
assets/images/nomo_logo.png


+ 12 - 12
assets/md/privacy.md

@@ -4,21 +4,21 @@ Last updated on: 2026-01-28
 
 ## Introduction
 
-By using NOMO VPN, you agree to be bound by the terms and conditions hereinafter set forth and applicable laws and regulations. The terms and conditions herein shall take effect upon your use of NOMO VPN. If you do not agree to any of the following terms and conditions, please stop using NOMO VPN immediately.
+By using FlashLink VPN, you agree to be bound by the terms and conditions hereinafter set forth and applicable laws and regulations. The terms and conditions herein shall take effect upon your use of FlashLink VPN. If you do not agree to any of the following terms and conditions, please stop using FlashLink VPN immediately.
 
-NOMO VPN is committed to protecting your privacy. This Privacy Policy explains how we collect, use, and safeguard your information when you use our VPN application and services.
+FlashLink VPN is committed to protecting your privacy. This Privacy Policy explains how we collect, use, and safeguard your information when you use our VPN application and services.
 
 ### 1. General Information
 
-In this Privacy Policy document, we address the information collected and processed during the use of the NOMO VPN application and related services.
+In this Privacy Policy document, we address the information collected and processed during the use of the FlashLink VPN application and related services.
 
-If you have questions or concerns about the use of your personal data, or for privacy-specific inquiries, please contact us at support@nomovpn.com.
+If you have questions or concerns about the use of your personal data, or for privacy-specific inquiries, please contact us at support@flashlink.me.
 
 This Privacy Policy applies globally, though specific provisions may vary to comply with local regulations in your jurisdiction.
 
 ### 2. About the Collected Data and Its Use
 
-NOMO VPN prioritizes user privacy. We follow a strict "No-Logs" policy regarding your online activities. We do not track, store, or share your browsing history, destination IPs, or DNS queries.
+FlashLink VPN prioritizes user privacy. We follow a strict "No-Logs" policy regarding your online activities. We do not track, store, or share your browsing history, destination IPs, or DNS queries.
 
 To operate our service effectively, we collect limited data as follows:
 
@@ -30,15 +30,15 @@ To operate our service effectively, we collect limited data as follows:
 
 4. **Contact Data**: If you contact our support team, we will use your email address to communicate with you regarding your inquiry.
 
-**Payment Information**: As NOMO VPN is currently provided free of charge, we do not collect payment details or credit card information. We do not currently display third-party advertisements.
+**Payment Information**: As FlashLink VPN is currently provided free of charge, we do not collect payment details or credit card information. We do not currently display third-party advertisements.
 
 ### 3. Data Security and Storage
 
-We implement robust technical and organizational measures to protect the data collected by NOMO VPN.
+We implement robust technical and organizational measures to protect the data collected by FlashLink VPN.
 
 1. **Data Storage**: The minimal data we collect is stored securely and retained only for as long as necessary to provide and improve our services.
 2. **Encryption**: All traffic between your device and our VPN servers is encrypted to protect your online activities from prying eyes.
-3. **Data Deletion**: You can request the deletion of your account and associated personal data by contacting our support team via support@nomovpn.com. We will respond to and process your request within 30 days.
+3. **Data Deletion**: You can request the deletion of your account and associated personal data by contacting our support team via support@flashlink.me. We will respond to and process your request within 30 days.
 
 ### 4. Legal Bases for Data Processing
 
@@ -69,16 +69,16 @@ As a data subject, you have the right to:
 4. Withdraw consent where processing is based on consent.
 5. Lodge a complaint with a data protection authority.
 
-To exercise these rights, please contact our Support Team via support@nomovpn.com.
+To exercise these rights, please contact our Support Team via support@flashlink.me.
 
 ### 7. Minors' Data Protection
 
-NOMO VPN does not knowingly collect personal information from individuals under the age of 16. If we become aware that we have inadvertently collected personal data from a minor, we will take steps to delete such information immediately.
+FlashLink VPN does not knowingly collect personal information from individuals under the age of 16. If we become aware that we have inadvertently collected personal data from a minor, we will take steps to delete such information immediately.
 
 ### 8. Updates and Amendments
 
-We may update this Privacy Policy to reflect changes in our services (such as the introduction of new features) or legal requirements. Any updates will be posted within the NOMO VPN application. Your continued use of NOMO VPN constitutes your acceptance of the updated policy.
+We may update this Privacy Policy to reflect changes in our services (such as the introduction of new features) or legal requirements. Any updates will be posted within the FlashLink VPN application. Your continued use of FlashLink VPN constitutes your acceptance of the updated policy.
 
 ### 9. Contact Information
 
-If you have any questions about this Privacy Policy, please contact us at support@nomovpn.com.
+If you have any questions about this Privacy Policy, please contact us at support@flashlink.me.

+ 14 - 14
assets/md/terms.md

@@ -2,19 +2,19 @@
 
 Last updated on: 2026-01-28
 
-By using the services provided by NOMO VPN ("Service"), you agree to be bound by the terms and conditions hereinafter set forth. This Agreement shall take effect upon your download, installation, or use of NOMO VPN. If you do not agree to any of the following terms, you must immediately uninstall and cease using NOMO VPN.
+By using the services provided by FlashLink VPN ("Service"), you agree to be bound by the terms and conditions hereinafter set forth. This Agreement shall take effect upon your download, installation, or use of FlashLink VPN. If you do not agree to any of the following terms, you must immediately uninstall and cease using FlashLink VPN.
 
 ### 1. General Information
 
-This legally binding Agreement governs the access and use of NOMO VPN, a service designed to provide secure, encrypted internet connectivity and privacy protection.
+This legally binding Agreement governs the access and use of FlashLink VPN, a service designed to provide secure, encrypted internet connectivity and privacy protection.
 
-NOMO VPN allows users to route their data traffic through our servers to secure their connection and mask their IP address.
+FlashLink VPN allows users to route their data traffic through our servers to secure their connection and mask their IP address.
 
-By using NOMO VPN, you agree to comply with all applicable local, state, national, and international laws and regulations.
+By using FlashLink VPN, you agree to comply with all applicable local, state, national, and international laws and regulations.
 
 ### 2. Allowable Use and Prohibited Activities
 
-NOMO VPN allows you to browse the internet securely and privately. However, you must use the Service responsibly.
+FlashLink VPN allows you to browse the internet securely and privately. However, you must use the Service responsibly.
 
 **Prohibited activities include but are not limited to:**
 
@@ -28,7 +28,7 @@ We reserve the right to terminate your account or restrict access to the Service
 
 ### 3. Service Availability and Billing
 
-**Current Status**: NOMO VPN is currently provided free of charge. We do not currently display third-party ads.
+**Current Status**: FlashLink VPN is currently provided free of charge. We do not currently display third-party ads.
 
 **Future Changes**: We reserve the right to introduce subscription fees, premium features, or advertisements in future versions of the Service. Any such changes will be communicated clearly to users.
 
@@ -36,17 +36,17 @@ We reserve the right to terminate your account or restrict access to the Service
 
 ### 4. Errors and Updates
 
-The NOMO VPN software and related information may contain technical errors or inaccuracies. We reserve the right to correct such errors and update the software to add features, fix bugs, or improve security without prior notice. By using NOMO VPN, you consent to receive such updates.
+The FlashLink VPN software and related information may contain technical errors or inaccuracies. We reserve the right to correct such errors and update the software to add features, fix bugs, or improve security without prior notice. By using FlashLink VPN, you consent to receive such updates.
 
 ### 5. External Links
 
-NOMO VPN may contain links to external websites. We are not responsible for the content, privacy policies, or practices of any third-party websites. Accessing external links is at your own risk.
+FlashLink VPN may contain links to external websites. We are not responsible for the content, privacy policies, or practices of any third-party websites. Accessing external links is at your own risk.
 
 ### 6. Disclaimers and Limitations of Liability
 
-NOMO VPN is provided on an "AS IS" and "AS AVAILABLE" basis without warranties of any kind, either express or implied.
+FlashLink VPN is provided on an "AS IS" and "AS AVAILABLE" basis without warranties of any kind, either express or implied.
 
-To the maximum extent permitted by applicable law, NOMO VPN and its operators shall not be liable for:
+To the maximum extent permitted by applicable law, FlashLink VPN and its operators shall not be liable for:
 
 1. Any indirect, incidental, special, consequential, or punitive damages.
 2. Loss of data, profits, or business opportunities.
@@ -65,16 +65,16 @@ You are responsible for:
 
 ### 8. Privacy Policy
 
-Your use of NOMO VPN is also governed by our Privacy Policy, which outlines how we collect and process data. By using the Service, you consent to the practices described in the Privacy Policy.
+Your use of FlashLink VPN is also governed by our Privacy Policy, which outlines how we collect and process data. By using the Service, you consent to the practices described in the Privacy Policy.
 
 ### 9. Dispute Resolution
 
-Any disputes arising from this Agreement shall be resolved through good-faith negotiations. If a resolution cannot be reached, the dispute shall be submitted to the competent courts in the jurisdiction where NOMO VPN's operators are headquartered.
+Any disputes arising from this Agreement shall be resolved through good-faith negotiations. If a resolution cannot be reached, the dispute shall be submitted to the competent courts in the jurisdiction where FlashLink VPN's operators are headquartered.
 
 ### 10. Updates to this Agreement
 
-We may update this Agreement from time to time. The most current version will always be available within the application or on our official website. Your continued use of NOMO VPN after any changes constitutes your acceptance of the new Terms.
+We may update this Agreement from time to time. The most current version will always be available within the application or on our official website. Your continued use of FlashLink VPN after any changes constitutes your acceptance of the new Terms.
 
 ### 11. Contact Information
 
-If you have any questions regarding this Agreement, please contact us at support@nomovpn.com.
+If you have any questions regarding this Agreement, please contact us at support@flashlink.me.

+ 6 - 6
deploy/windows/setup.iss

@@ -1,15 +1,15 @@
 ; Script generated by the Inno Setup Script Wizard.
 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
 
-#define MyAppName "Nomo VPN"
+#define MyAppName "FlashLink VPN"
 #define MyAppVersion "1.0.0"
-#define MyAppPublisher "Nomo VPN"
-#define MyAppURL "https://nomovpn.io/"
-#define MyAppExeName "ixvpn.exe"
-#define MyAppSetupName "nomo_vpn_1.0.0_1"
+#define MyAppPublisher "FlashLink VPN"
+#define MyAppURL "https://flashlink.me/"
+#define MyAppExeName "FlashLink.exe"
+#define MyAppSetupName "flashlink_vpn_1.0.0_1"
 
 #ifndef MyWorkingDir
-#define MyWorkingDir "D:\Workspace\nomo\deploy\windows"
+#define MyWorkingDir "D:\Workspace\FlashLink\deploy\windows"
 #endif
 
 [Setup]

+ 14 - 14
deploy/windows/terms.rtf

@@ -5,13 +5,13 @@
 \par
 Thank you for choosing us. Before starting, please read these General Terms of Service carefully.\par
 \par
-The Services are provided by Nomo ("we," "us," "our," or "Nomo"). Please note that the Terms constitute a binding legal agreement between you and Nomo. By visiting our websites, installing, and/or using the Services, you acknowledge that you have read the Terms, understand them, and agree to be bound by these Terms. If you are using the Services on behalf of an organization, you are agreeing to these Terms for that organization and acknowledging that you have the authority to act on behalf of that organization and commit to these Terms on behalf of that organization. If you do not agree with these Terms or any provisions hereof, please do not install and do not use our Services.\par
+The Services are provided by FlashLink ("we," "us," "our," or "FlashLink"). Please note that the Terms constitute a binding legal agreement between you and FlashLink. By visiting our websites, installing, and/or using the Services, you acknowledge that you have read the Terms, understand them, and agree to be bound by these Terms. If you are using the Services on behalf of an organization, you are agreeing to these Terms for that organization and acknowledging that you have the authority to act on behalf of that organization and commit to these Terms on behalf of that organization. If you do not agree with these Terms or any provisions hereof, please do not install and do not use our Services.\par
 \par
-By agreeing to these Terms, you are also agreeing to the Privacy Policy: {{\field{\*\fldinst{HYPERLINK https://nomo.io/privacy }}{\fldrslt{https://nomo.io/privacy\ul0\cf0}}}}\f0\fs22\par
+By agreeing to these Terms, you are also agreeing to the Privacy Policy: {{\field{\*\fldinst{HYPERLINK https://flashlink.me/privacy }}{\fldrslt{https://flashlink.me/privacy\ul0\cf0}}}}\f0\fs22\par
 \par
-\b\fs28 1. Your Agreement with Nomo\fs22\par
+\b\fs28 1. Your Agreement with FlashLink\fs22\par
 \b0\par
-Binding Legal Agreement. Please note that the Terms constitute a binding legal agreement between you or those you legally represent ("you") and Nomo. You agree and accept to be bound by these Terms by either:\par
+Binding Legal Agreement. Please note that the Terms constitute a binding legal agreement between you or those you legally represent ("you") and FlashLink. You agree and accept to be bound by these Terms by either:\par
 \par
 * Downloading Software or accessing/using its Services and Websites;\par
 * Otherwise electronically agreeing to be bound by these Terms. If you are using the Services on behalf of an organization, you are agreeing to these Terms for that organization and acknowledging that you have the authority to act on behalf of that organization and commit to these Terms on behalf of that organization.\par
@@ -34,7 +34,7 @@ To use any of our services, you must take full responsibility for your actions d
 \par
 You are responsible for maintaining any information generated during your use and the equipment that uses the service, and you agree to be responsible for all activities occurring during your use of the service, whether or not you are authorized.\par
 \par
-Your use of the service is at your own risk. Services may be modified, updated, interrupted, or suspended at any time without prior notice or liability. We do not assume any responsibility for any harm or other adverse consequences caused to you. Nomo, its owner, employees, agents and others related to the service shall not be liable for any type of damage caused by the use of the service in any way or form.\par
+Your use of the service is at your own risk. Services may be modified, updated, interrupted, or suspended at any time without prior notice or liability. We do not assume any responsibility for any harm or other adverse consequences caused to you. FlashLink, its owner, employees, agents and others related to the service shall not be liable for any type of damage caused by the use of the service in any way or form.\par
 \par
 \b\fs28 3. License Terms\par
 \b0\fs22\par
@@ -68,13 +68,13 @@ Your access to and use of the Services and Websites is subject to the Terms and
 \par
 * exploit children in any way, including audio, video, photography, digital content, etc.;\par
 \par
-* violate, infringe, or misappropriate Nomo, our licensors and/or any other third parties' copyright, other intellectual property rights, privacy, or other legal rights;\par
+* violate, infringe, or misappropriate FlashLink, our licensors and/or any other third parties' copyright, other intellectual property rights, privacy, or other legal rights;\par
 \par
 * communicate, transmit, store, make available, share anything that is illegal, abusive, harassing, or otherwise objectionable;\par
 \par
 * transmit any viruses or other computer codes, files, programs, instructions, or technological means that disrupt, damage, or interfere with the use of computers or related systems;\par
 \par
-* attempt to circumvent any technological measure and/or arrangement implemented by Nomo and/or its licensors, or by the owner of the resource or the source of the material that the technological measure protects;\par
+* attempt to circumvent any technological measure and/or arrangement implemented by FlashLink and/or its licensors, or by the owner of the resource or the source of the material that the technological measure protects;\par
 \par
 * interfere with or disrupt the integrity or performance of the Service/Websites;\par
 \par
@@ -96,7 +96,7 @@ Your access to and use of the Services and Websites is subject to the Terms and
 \par
 * use the Services/Websites for anything other than lawful purposes;\par
 \par
-* consistently demonstrate unrespectful, threatening, offensive, and/or malicious behavior when communicating with Nomo customer support and/or other employees;\par
+* consistently demonstrate unrespectful, threatening, offensive, and/or malicious behavior when communicating with FlashLink customer support and/or other employees;\par
 \par
 * access and use the Services if you have been or are prohibited to access the Services, or if your Account has been suspended or terminated due to any reason;\par
 \par
@@ -118,21 +118,21 @@ The services and websites are provided "as is" and with all faults. we make no r
 \par
 \b\fs28 7. limitation of liabilities\par
 \b0\fs22\par
-There are inherent risks in relying upon, using, transmitting, or retrieving any data and/or content on the internet, and we urge you to make sure you understand these risks before using the Services. Nomo disclaims all responsibility for the behavior of its users and/or visitors when they access or use the Services/Websites.\par
+There are inherent risks in relying upon, using, transmitting, or retrieving any data and/or content on the internet, and we urge you to make sure you understand these risks before using the Services. FlashLink disclaims all responsibility for the behavior of its users and/or visitors when they access or use the Services/Websites.\par
 \par
-Our use of the services and websites is at your own risk. neither Nomo, nor any of its parents, subsidiaries or affiliates, nor any of their employees, officers or directors, shall be liable for any direct, indirect, punitive, incidental, special, consequential, or other damages (including, without limitation, loss of data or information of any kind, loss of business, lost profits, interruption of business, cost of cover or any other damages) arising out of or in any way related to these terms or the use or inability to use the services or websites, whether based on contract, tort, strict liability or otherwise, even if we have been advised of the possibility of such damages.\par
+Our use of the services and websites is at your own risk. neither FlashLink, nor any of its parents, subsidiaries or affiliates, nor any of their employees, officers or directors, shall be liable for any direct, indirect, punitive, incidental, special, consequential, or other damages (including, without limitation, loss of data or information of any kind, loss of business, lost profits, interruption of business, cost of cover or any other damages) arising out of or in any way related to these terms or the use or inability to use the services or websites, whether based on contract, tort, strict liability or otherwise, even if we have been advised of the possibility of such damages.\par
 \par
-Some jurisdictions restrict or do not allow the limitation of liability in contracts (e.g., limitation of liability for death or personal injury caused by other party's negligence, fraud, or fraudulent misrepresentation, willful misconduct, or gross negligence). as a result, respective provisions of this section may not apply to you. in cases where such restrictions on the limitation of liability apply, the liability of Nomo shall be limited to the fullest extent permitted by certain applicable law.\par
+Some jurisdictions restrict or do not allow the limitation of liability in contracts (e.g., limitation of liability for death or personal injury caused by other party's negligence, fraud, or fraudulent misrepresentation, willful misconduct, or gross negligence). as a result, respective provisions of this section may not apply to you. in cases where such restrictions on the limitation of liability apply, the liability of FlashLink shall be limited to the fullest extent permitted by certain applicable law.\par
 \par
-Please also note, that Nomo has implemented security measures aimed at securing the services and websites; nevertheless, the internet is not a secure network and system reliability could be impaired independently of Nomo's efforts and will. in addition, Nomo cannot be held liable for unpredictable events such as cyber attacks, security breaches regarding the transmission of data or for performance guarantees regarding the volume and speed of data transmissions. users are responsible for taking all appropriate measures to protect their own data, software, equipment, and systems, particularly from contamination by any viruses circulating on the internet.\par
+Please also note, that FlashLink has implemented security measures aimed at securing the services and websites; nevertheless, the internet is not a secure network and system reliability could be impaired independently of FlashLink's efforts and will. in addition, FlashLink cannot be held liable for unpredictable events such as cyber attacks, security breaches regarding the transmission of data or for performance guarantees regarding the volume and speed of data transmissions. users are responsible for taking all appropriate measures to protect their own data, software, equipment, and systems, particularly from contamination by any viruses circulating on the internet.\par
 \par
 \par
 \b\fs28 8. contact us\par
 \b0\fs22\par
-If you have questions regarding the Terms, please contact us at <support@nomo.io>\par
+If you have questions regarding the Terms, please contact us at <support@flashlink.me>\par
 For the contact regarding allegations of abuse, please see the Service Specific Terms of each of our Services.\par
 \par
-The final right of interpretation belongs to the Nomo.\par
+The final right of interpretation belongs to the FlashLink.\par
 \par
 }
  

+ 3 - 1
ios/Podfile

@@ -1,5 +1,5 @@
 # Uncomment this line to define a global platform for your project
-# platform :ios, '13.0'
+platform :ios, '13.0'
 
 # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
 ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@@ -43,6 +43,8 @@ post_install do |installer|
     target.build_configurations.each do |config|
       # 强制设置所有Pod的iOS部署目标为13.0
       config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
+      config.build_settings['ENABLE_BITCODE'] = 'NO'
+      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = '$(inherited)'
     end
   end
 end

+ 1 - 90
ios/Podfile.lock

@@ -1,16 +1,8 @@
 PODS:
-  - app_links (6.4.1):
-    - Flutter
   - awesome_notifications (0.10.0):
     - Flutter
     - IosAwnCore (~> 0.10.0)
-  - connectivity_plus (0.0.1):
-    - Flutter
-  - device_info_plus (0.0.1):
-    - Flutter
   - Flutter (1.0.0)
-  - flutter_custom_tabs_ios (2.4.0):
-    - Flutter
   - flutter_inappwebview_ios (0.0.1):
     - Flutter
     - flutter_inappwebview_ios/Core (= 0.0.1)
@@ -18,61 +10,22 @@ PODS:
   - flutter_inappwebview_ios/Core (0.0.1):
     - Flutter
     - OrderedSet (~> 6.0.3)
-  - flutter_native_splash (2.4.3):
-    - Flutter
   - flutter_secure_storage (6.0.0):
     - Flutter
   - image_gallery_saver_plus (0.0.1):
     - Flutter
-  - in_app_purchase_storekit (0.0.1):
-    - Flutter
-    - FlutterMacOS
   - IosAwnCore (0.10.0)
-  - network_info_plus (0.0.1):
-    - Flutter
   - OrderedSet (6.0.3)
-  - package_info_plus (0.4.5):
-    - Flutter
-  - path_provider_foundation (0.0.1):
-    - Flutter
-    - FlutterMacOS
   - permission_handler_apple (9.3.0):
     - Flutter
-  - share_plus (0.0.1):
-    - Flutter
-  - shared_preferences_foundation (0.0.1):
-    - Flutter
-    - FlutterMacOS
-  - sqflite_darwin (0.0.4):
-    - Flutter
-    - FlutterMacOS
-  - url_launcher_ios (0.0.1):
-    - Flutter
-  - video_player_avfoundation (0.0.1):
-    - Flutter
-    - FlutterMacOS
 
 DEPENDENCIES:
-  - app_links (from `.symlinks/plugins/app_links/ios`)
   - awesome_notifications (from `.symlinks/plugins/awesome_notifications/ios`)
-  - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
-  - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
   - Flutter (from `Flutter`)
-  - flutter_custom_tabs_ios (from `.symlinks/plugins/flutter_custom_tabs_ios/ios`)
   - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
-  - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
   - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
   - image_gallery_saver_plus (from `.symlinks/plugins/image_gallery_saver_plus/ios`)
-  - in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
-  - network_info_plus (from `.symlinks/plugins/network_info_plus/ios`)
-  - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
-  - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
   - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
-  - share_plus (from `.symlinks/plugins/share_plus/ios`)
-  - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
-  - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
-  - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
-  - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
 
 SPEC REPOS:
   trunk:
@@ -80,71 +33,29 @@ SPEC REPOS:
     - OrderedSet
 
 EXTERNAL SOURCES:
-  app_links:
-    :path: ".symlinks/plugins/app_links/ios"
   awesome_notifications:
     :path: ".symlinks/plugins/awesome_notifications/ios"
-  connectivity_plus:
-    :path: ".symlinks/plugins/connectivity_plus/ios"
-  device_info_plus:
-    :path: ".symlinks/plugins/device_info_plus/ios"
   Flutter:
     :path: Flutter
-  flutter_custom_tabs_ios:
-    :path: ".symlinks/plugins/flutter_custom_tabs_ios/ios"
   flutter_inappwebview_ios:
     :path: ".symlinks/plugins/flutter_inappwebview_ios/ios"
-  flutter_native_splash:
-    :path: ".symlinks/plugins/flutter_native_splash/ios"
   flutter_secure_storage:
     :path: ".symlinks/plugins/flutter_secure_storage/ios"
   image_gallery_saver_plus:
     :path: ".symlinks/plugins/image_gallery_saver_plus/ios"
-  in_app_purchase_storekit:
-    :path: ".symlinks/plugins/in_app_purchase_storekit/darwin"
-  network_info_plus:
-    :path: ".symlinks/plugins/network_info_plus/ios"
-  package_info_plus:
-    :path: ".symlinks/plugins/package_info_plus/ios"
-  path_provider_foundation:
-    :path: ".symlinks/plugins/path_provider_foundation/darwin"
   permission_handler_apple:
     :path: ".symlinks/plugins/permission_handler_apple/ios"
-  share_plus:
-    :path: ".symlinks/plugins/share_plus/ios"
-  shared_preferences_foundation:
-    :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
-  sqflite_darwin:
-    :path: ".symlinks/plugins/sqflite_darwin/darwin"
-  url_launcher_ios:
-    :path: ".symlinks/plugins/url_launcher_ios/ios"
-  video_player_avfoundation:
-    :path: ".symlinks/plugins/video_player_avfoundation/darwin"
 
 SPEC CHECKSUMS:
-  app_links: 3dbc685f76b1693c66a6d9dd1e9ab6f73d97dc0a
   awesome_notifications: 0f432b28098d193920b11a44cfa9d2d9313a3888
-  connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
-  device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
   Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
-  flutter_custom_tabs_ios: 87333f36c33a5971502766aca2f6ff4823b09bda
   flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
-  flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
   flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
   image_gallery_saver_plus: e597bf65a7846979417a3eae0763b71b6dfec6c3
-  in_app_purchase_storekit: 22cca7d08eebca9babdf4d07d0baccb73325d3c8
   IosAwnCore: 653786a911089012092ce831f2945cd339855a89
-  network_info_plus: cf61925ab5205dce05a4f0895989afdb6aade5fc
   OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
-  package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
-  path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
   permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
-  share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
-  shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
-  sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
-  url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
-  video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
 
-PODFILE CHECKSUM: b52bb60937f8c5a794d2d528df0bacde988c6b6a
+PODFILE CHECKSUM: 38b88cd7dc5fa58dbf0493772c73efdc8c6d8a8f
 
 COCOAPODS: 1.16.2

+ 6 - 6
ios/Runner.xcodeproj/project.pbxproj

@@ -504,7 +504,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				PRODUCT_BUNDLE_IDENTIFIER = app.xixi.nomo;
+				PRODUCT_BUNDLE_IDENTIFIER = com.flashlink.vpn;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
 				SWIFT_VERSION = 5.0;
@@ -521,7 +521,7 @@
 				CURRENT_PROJECT_VERSION = 1;
 				GENERATE_INFOPLIST_FILE = YES;
 				MARKETING_VERSION = 1.0;
-				PRODUCT_BUNDLE_IDENTIFIER = app.xixi.nomo.RunnerTests;
+				PRODUCT_BUNDLE_IDENTIFIER = com.flashlink.vpn.RunnerTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -539,7 +539,7 @@
 				CURRENT_PROJECT_VERSION = 1;
 				GENERATE_INFOPLIST_FILE = YES;
 				MARKETING_VERSION = 1.0;
-				PRODUCT_BUNDLE_IDENTIFIER = app.xixi.nomo.RunnerTests;
+				PRODUCT_BUNDLE_IDENTIFIER = com.flashlink.vpn.RunnerTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_VERSION = 5.0;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -555,7 +555,7 @@
 				CURRENT_PROJECT_VERSION = 1;
 				GENERATE_INFOPLIST_FILE = YES;
 				MARKETING_VERSION = 1.0;
-				PRODUCT_BUNDLE_IDENTIFIER = app.xixi.nomo.RunnerTests;
+				PRODUCT_BUNDLE_IDENTIFIER = com.flashlink.vpn.RunnerTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_VERSION = 5.0;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -688,7 +688,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				PRODUCT_BUNDLE_IDENTIFIER = app.xixi.nomo;
+				PRODUCT_BUNDLE_IDENTIFIER = com.flashlink.vpn;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -712,7 +712,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				PRODUCT_BUNDLE_IDENTIFIER = app.xixi.nomo;
+				PRODUCT_BUNDLE_IDENTIFIER = com.flashlink.vpn;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
 				SWIFT_VERSION = 5.0;

+ 3 - 0
ios/Runner.xcworkspace/contents.xcworkspacedata

@@ -4,4 +4,7 @@
    <FileRef
       location = "group:Runner.xcodeproj">
    </FileRef>
+   <FileRef
+      location = "group:Pods/Pods.xcodeproj">
+   </FileRef>
 </Workspace>

+ 12 - 12
ios/Runner/CoreApi.g.swift

@@ -109,7 +109,7 @@ class CoreApiSetup {
   /// Sets up an instance of `CoreApi` to handle messages through the `binaryMessenger`.
   static func setUp(binaryMessenger: FlutterBinaryMessenger, api: CoreApi?, messageChannelSuffix: String = "") {
     let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : ""
-    let getAppsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getApps\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let getAppsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getApps\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       getAppsChannel.setMessageHandler { _, reply in
         api.getApps { result in
@@ -124,7 +124,7 @@ class CoreApiSetup {
     } else {
       getAppsChannel.setMessageHandler(nil)
     }
-    let getSystemLocaleChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getSystemLocale\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let getSystemLocaleChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getSystemLocale\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       getSystemLocaleChannel.setMessageHandler { _, reply in
         do {
@@ -137,7 +137,7 @@ class CoreApiSetup {
     } else {
       getSystemLocaleChannel.setMessageHandler(nil)
     }
-    let connectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.connect\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let connectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.connect\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       connectChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
@@ -167,7 +167,7 @@ class CoreApiSetup {
     } else {
       connectChannel.setMessageHandler(nil)
     }
-    let disconnectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.disconnect\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let disconnectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.disconnect\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       disconnectChannel.setMessageHandler { _, reply in
         do {
@@ -180,7 +180,7 @@ class CoreApiSetup {
     } else {
       disconnectChannel.setMessageHandler(nil)
     }
-    let getRemoteIpChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getRemoteIp\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let getRemoteIpChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getRemoteIp\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       getRemoteIpChannel.setMessageHandler { _, reply in
         do {
@@ -193,7 +193,7 @@ class CoreApiSetup {
     } else {
       getRemoteIpChannel.setMessageHandler(nil)
     }
-    let getAdvertisingIdChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getAdvertisingId\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let getAdvertisingIdChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getAdvertisingId\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       getAdvertisingIdChannel.setMessageHandler { _, reply in
         do {
@@ -206,7 +206,7 @@ class CoreApiSetup {
     } else {
       getAdvertisingIdChannel.setMessageHandler(nil)
     }
-    let moveTaskToBackChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.moveTaskToBack\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let moveTaskToBackChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.moveTaskToBack\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       moveTaskToBackChannel.setMessageHandler { _, reply in
         do {
@@ -219,7 +219,7 @@ class CoreApiSetup {
     } else {
       moveTaskToBackChannel.setMessageHandler(nil)
     }
-    let isConnectedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.isConnected\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let isConnectedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.isConnected\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       isConnectedChannel.setMessageHandler { _, reply in
         do {
@@ -232,7 +232,7 @@ class CoreApiSetup {
     } else {
       isConnectedChannel.setMessageHandler(nil)
     }
-    let getSimInfoChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getSimInfo\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let getSimInfoChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getSimInfo\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       getSimInfoChannel.setMessageHandler { _, reply in
         do {
@@ -245,7 +245,7 @@ class CoreApiSetup {
     } else {
       getSimInfoChannel.setMessageHandler(nil)
     }
-    let getChannelChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.getChannel\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let getChannelChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.getChannel\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       getChannelChannel.setMessageHandler { _, reply in
         do {
@@ -258,7 +258,7 @@ class CoreApiSetup {
     } else {
       getChannelChannel.setMessageHandler(nil)
     }
-    let openPackageChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.openPackage\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    let openPackageChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.com.flashlink.vpn.CoreApi.openPackage\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       openPackageChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
@@ -329,7 +329,7 @@ class OnEventChangeStreamHandler: PigeonEventChannelWrapper<String> {
   static func register(with messenger: FlutterBinaryMessenger,
                       instanceName: String = "",
                       streamHandler: OnEventChangeStreamHandler) {
-    var channelName = "dev.flutter.pigeon.app.xixi.nomo.CoreChangeEventApi.onEventChange"
+    var channelName = "dev.flutter.pigeon.com.flashlink.vpn.CoreChangeEventApi.onEventChange"
     if !instanceName.isEmpty {
       channelName += ".\(instanceName)"
     }

+ 65 - 67
ios/Runner/Info.plist

@@ -1,70 +1,68 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
-	<dict>
-		<key>CFBundleDevelopmentRegion</key>
-		<string>$(DEVELOPMENT_LANGUAGE)</string>
-		<key>CFBundleDisplayName</key>
-		<string>NoMo</string>
-		<key>CFBundleExecutable</key>
-		<string>$(EXECUTABLE_NAME)</string>
-		<key>CFBundleIdentifier</key>
-		<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-		<key>CFBundleInfoDictionaryVersion</key>
-		<string>6.0</string>
-		<key>CFBundleName</key>
-		<string>NoMo</string>
-		<key>CFBundlePackageType</key>
-		<string>APPL</string>
-		<key>CFBundleShortVersionString</key>
-		<string>$(FLUTTER_BUILD_NAME)</string>
-		<key>CFBundleSignature</key>
-		<string>????</string>
-		<key>CFBundleVersion</key>
-		<string>$(FLUTTER_BUILD_NUMBER)</string>
-		<key>LSRequiresIPhoneOS</key>
-		<true/>
-		<key>UILaunchStoryboardName</key>
-		<string>LaunchScreen</string>
-		<key>UIMainStoryboardFile</key>
-		<string>Main</string>
-		<key>UISupportedInterfaceOrientations</key>
-		<array>
-			<string>UIInterfaceOrientationPortrait</string>
-			<string>UIInterfaceOrientationLandscapeLeft</string>
-			<string>UIInterfaceOrientationLandscapeRight</string>
-		</array>
-		<key>UISupportedInterfaceOrientations~ipad</key>
-		<array>
-			<string>UIInterfaceOrientationPortrait</string>
-			<string>UIInterfaceOrientationPortraitUpsideDown</string>
-			<string>UIInterfaceOrientationLandscapeLeft</string>
-			<string>UIInterfaceOrientationLandscapeRight</string>
-		</array>
-		<key>CADisableMinimumFrameDurationOnPhone</key>
-		<true/>
-		<key>UIApplicationSupportsIndirectInputEvents</key>
-		<true/>
-	<key>UIStatusBarHidden</key>
-	<false/>
-	<key>NSPhotoLibraryAddUsageDescription</key>
-	<string>We need access to save your Pre Code image to your photo library.</string>
-	<key>NSPhotoLibraryUsageDescription</key>
-	<string>We need access to save your Pre Code image to your photo library.</string>
-	
-	<!-- WebView 相关配置 -->
-	<key>NSAppTransportSecurity</key>
-	<dict>
-		<key>NSAllowsArbitraryLoads</key>
-		<true/>
-		<key>NSAllowsLocalNetworking</key>
-		<true/>
-	</dict>
-	
-	<!-- WebView 可能需要的相机和麦克风权限 -->
-	<key>NSCameraUsageDescription</key>
-	<string>This app needs camera access to use camera features in web pages.</string>
-	<key>NSMicrophoneUsageDescription</key>
-	<string>This app needs microphone access to use audio features in web pages.</string>
-</dict>
-</plist>
+  <dict>
+    <key>CFBundleDevelopmentRegion</key>
+    <string>$(DEVELOPMENT_LANGUAGE)</string>
+    <key>CFBundleDisplayName</key>
+    <string>FlashLink VPN</string>
+    <key>CFBundleExecutable</key>
+    <string>$(EXECUTABLE_NAME)</string>
+    <key>CFBundleIdentifier</key>
+    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+    <key>CFBundleInfoDictionaryVersion</key>
+    <string>6.0</string>
+    <key>CFBundleName</key>
+    <string>FlashLink VPN</string>
+    <key>CFBundlePackageType</key>
+    <string>APPL</string>
+    <key>CFBundleShortVersionString</key>
+    <string>$(FLUTTER_BUILD_NAME)</string>
+    <key>CFBundleSignature</key>
+    <string>????</string>
+    <key>CFBundleVersion</key>
+    <string>$(FLUTTER_BUILD_NUMBER)</string>
+    <key>LSRequiresIPhoneOS</key>
+    <true/>
+    <key>UILaunchStoryboardName</key>
+    <string>LaunchScreen</string>
+    <key>UIMainStoryboardFile</key>
+    <string>Main</string>
+    <key>UISupportedInterfaceOrientations</key>
+    <array>
+      <string>UIInterfaceOrientationPortrait</string>
+      <string>UIInterfaceOrientationLandscapeLeft</string>
+      <string>UIInterfaceOrientationLandscapeRight</string>
+    </array>
+    <key>UISupportedInterfaceOrientations~ipad</key>
+    <array>
+      <string>UIInterfaceOrientationPortrait</string>
+      <string>UIInterfaceOrientationPortraitUpsideDown</string>
+      <string>UIInterfaceOrientationLandscapeLeft</string>
+      <string>UIInterfaceOrientationLandscapeRight</string>
+    </array>
+    <key>CADisableMinimumFrameDurationOnPhone</key>
+    <true/>
+    <key>UIApplicationSupportsIndirectInputEvents</key>
+    <true/>
+    <key>UIStatusBarHidden</key>
+    <false/>
+    <key>NSPhotoLibraryAddUsageDescription</key>
+    <string>We need access to save your Pre Code image to your photo library.</string>
+    <key>NSPhotoLibraryUsageDescription</key>
+    <string>We need access to save your Pre Code image to your photo library.</string>
+    <!-- WebView 相关配置 -->
+    <key>NSAppTransportSecurity</key>
+    <dict>
+      <key>NSAllowsArbitraryLoads</key>
+      <true/>
+      <key>NSAllowsLocalNetworking</key>
+      <true/>
+    </dict>
+    <!-- WebView 可能需要的相机和麦克风权限 -->
+    <key>NSCameraUsageDescription</key>
+    <string>This app needs camera access to use camera features in web pages.</string>
+    <key>NSMicrophoneUsageDescription</key>
+    <string>This app needs microphone access to use audio features in web pages.</string>
+  </dict>
+</plist>

+ 1 - 1
lib/app/api/base/base_api.dart

@@ -129,7 +129,7 @@ abstract class BaseApi {
         client.autoUncompress = true;
 
         // 设置用户代理
-        client.userAgent = 'Nomo/1.0';
+        client.userAgent = 'flashlink/1.0';
 
         // 设置连接工厂
         client.connectionFactory = (Uri uri, String? host, int? port) async {

+ 2 - 2
lib/app/api/core/api_core.dart

@@ -141,7 +141,7 @@ class ApiCore extends BaseApi {
         options: Options(
           headers: {
             'Authorization': user.refreshToken,
-            'X-NL-Product-Code': 'nomo',
+            'X-NL-Product-Code': 'flashlink',
             'X-NL-Content-Encoding': 'gzip',
           },
         ),
@@ -201,7 +201,7 @@ class ApiCore extends BaseApi {
   Map<String, dynamic>? getDefaultHeader() {
     // 可以设置自定义Header
     final headers = {
-      'X-NL-Product-Code': 'nomo',
+      'X-NL-Product-Code': 'flashlink',
       'X-NL-Content-Encoding': 'gzip',
     };
     return headers;

+ 1 - 1
lib/app/api/file/api_file.dart

@@ -66,7 +66,7 @@ class ApiFile extends BaseApi {
   Map<String, dynamic>? getDefaultHeader() {
     // 可以设置自定义Header
     final headers = {
-      'X-NL-Product-Code': 'nomo',
+      'X-NL-Product-Code': 'flashlink',
       'X-NL-Content-Encoding': 'gzip',
     };
     return headers;

+ 1 - 1
lib/app/api/log/api_log.dart

@@ -65,7 +65,7 @@ class ApiLog extends BaseApi {
   Map<String, dynamic>? getDefaultHeader() {
     // 可以设置自定义Header
     final headers = {
-      'X-NL-Product-Code': 'nomo',
+      'X-NL-Product-Code': 'flashlink',
       'X-NL-Content-Encoding': 'gzip',
     };
     return headers;

+ 1 - 1
lib/app/api/router/api_router.dart

@@ -65,7 +65,7 @@ class ApiRouter extends BaseApi {
   Map<String, dynamic>? getDefaultHeader() {
     // 可以设置自定义Header
     final headers = {
-      'X-NL-Product-Code': 'nomo',
+      'X-NL-Product-Code': 'flashlink',
       'X-NL-Content-Encoding': 'gzip',
     };
     return headers;

+ 3 - 3
lib/app/app.dart

@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:get/get.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
-import 'package:nomo/utils/misc.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/utils/misc.dart';
 import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
 import '../config/theme/ix_theme.dart';
 import '../config/translations/localization_service.dart';
@@ -56,7 +56,7 @@ class App extends StatelessWidget {
 
   Widget _buildMaterialApp() {
     return GetMaterialApp.router(
-      title: 'ixVPN',
+      title: 'FlashLink VPN',
       useInheritedMediaQuery: true,
       debugShowCheckedModeBanner: Configs.debug,
       backButtonDispatcher: IXBackButtonDispatcher(),

+ 1 - 1
lib/app/components/country_restricted_overlay.dart

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 import '../../config/translations/strings_enum.dart';
 import '../constants/assets.dart';
 import '../widgets/ix_image.dart';

+ 1 - 1
lib/app/components/ix_snackbar.dart

@@ -1,6 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../constants/assets.dart';
 

+ 5 - 5
lib/app/components/protocol_overlay.dart

@@ -3,9 +3,9 @@ import 'package:flutter/services.dart';
 import 'package:flutter_markdown/flutter_markdown.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/widgets/ix_image.dart';
-import 'package:nomo/app/widgets/submit_btn.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/widgets/ix_image.dart';
+import 'package:flashlink/app/widgets/submit_btn.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../constants/assets.dart';
 import '../routes/app_pages.dart';
@@ -38,7 +38,7 @@ class _ProtocolOverlayState extends State<ProtocolOverlay> {
                   borderRadius: BorderRadius.circular(12.r),
                 ),
                 child: IXImage(
-                  source: Assets.nomoLogo,
+                  source: Assets.flashlinkLogo,
                   width: 43.w,
                   height: 49.w,
                   sourceType: ImageSourceType.asset,
@@ -46,7 +46,7 @@ class _ProtocolOverlayState extends State<ProtocolOverlay> {
               ),
               18.verticalSpaceFromWidth,
               IXImage(
-                source: Assets.nomo,
+                source: Assets.flashlink,
                 width: 104.w,
                 height: 40.w,
                 fit: BoxFit.fitWidth,

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

@@ -3,7 +3,7 @@ import 'dart:io';
 
 import 'package:dio/dio.dart';
 import 'package:dio/io.dart';
-import 'package:nomo/app/api/router/api_router.dart';
+import 'package:flashlink/app/api/router/api_router.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 import '../../utils/crypto.dart';
 import '../../utils/developer/ix_developer_tools.dart';
@@ -60,7 +60,7 @@ class ApiDomains {
   }
 
   // 默认API URL列表
-  final List<String> _defaultApiUrls = ['https://api.znomo.com'];
+  final List<String> _defaultApiUrls = ['https://api.flashlink.me'];
 
   // 默认Router URL列表
   final List<String> _defaultRouterUrls = [];
@@ -120,8 +120,8 @@ class ApiDomains {
   void initUrls() {
     if (Configs.debug) {
       _apiUrls = [
-        'https://api.znomo.com', // 测试环境
-        // "https://nomo-api.clickto.dev", // 开发环境
+        'https://api.flashlink.me', // 测试环境
+        // "https://dev.flashlink.me", // 开发环境
       ];
       _routerUrls = [];
       _logUrls = [];

+ 3 - 3
lib/app/constants/assets.dart

@@ -1,4 +1,4 @@
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../config/translations/localization_service.dart';
 
@@ -49,8 +49,8 @@ class Assets {
       'assets/images/switch_status_connecting.png';
 
   // 协议
-  static const String nomoLogo = 'assets/images/nomo_logo.png';
-  static const String nomo = 'assets/images/nomo.png';
+  static const String flashlinkLogo = 'assets/images/flashlink_logo.png';
+  static const String flashlink = 'assets/images/flashlink.png';
   static const String refersh = 'assets/vectors/boost/refersh.svg';
 
   // 错误页

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

@@ -2,18 +2,18 @@ class Configs {
   Configs._();
 
   //官网
-  static const String officialWebsiteEmail = "support@nomovpn.com";
-  static const String officialWebsiteHttp = "https://www.znomo.com";
+  static const String officialWebsiteEmail = "support@flashlink.me";
+  static const String officialWebsiteHttp = "https://flashlink.me";
 
   // 调试相关
   static var debug = false;
 
-  static var assetUrl = "https://res.golink.dev";
+  static var assetUrl = "https://res.flashlink.me";
 
-  static var websiteUrl = "https:/www.znomo.com";
+  static var websiteUrl = "https:/flashlink.me";
 
   // 内核使用
-  static const String appName = 'Nomo VPN';
+  static const String appName = 'FlashLink VPN';
   // api使用
-  static const String productCode = "nomo";
+  static const String productCode = "flashlink";
 }

+ 3 - 3
lib/app/controllers/api_controller.dart

@@ -7,9 +7,9 @@ import 'package:dio/dio.dart';
 import 'package:flutter/material.dart';
 
 import 'package:get/get.dart';
-import 'package:nomo/app/api/router/api_router.dart';
-import 'package:nomo/app/data/sp/ix_sp.dart';
-import 'package:nomo/app/constants/sp_keys.dart';
+import 'package:flashlink/app/api/router/api_router.dart';
+import 'package:flashlink/app/data/sp/ix_sp.dart';
+import 'package:flashlink/app/constants/sp_keys.dart';
 import 'package:package_info_plus/package_info_plus.dart';
 import 'package:path_provider/path_provider.dart';
 import 'package:play_install_referrer/play_install_referrer.dart';

+ 1 - 1
lib/app/controllers/base_core_api.dart

@@ -1,6 +1,6 @@
 import 'dart:io';
 
-import 'package:nomo/pigeons/core_api.g.dart' as pigeon;
+import 'package:flashlink/pigeons/core_api.g.dart' as pigeon;
 
 import 'mobile_core_api.dart';
 import 'windows_core_api.dart';

+ 3 - 3
lib/app/controllers/core_controller.dart

@@ -5,9 +5,9 @@ import 'dart:io';
 import 'package:device_info_plus/device_info_plus.dart';
 import 'package:dio/dio.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/constants/api_domains.dart';
-import 'package:nomo/app/constants/keys.dart';
-import 'package:nomo/app/dialog/all_dialog.dart';
+import 'package:flashlink/app/constants/api_domains.dart';
+import 'package:flashlink/app/constants/keys.dart';
+import 'package:flashlink/app/dialog/all_dialog.dart';
 import 'package:package_info_plus/package_info_plus.dart';
 import 'package:uuid/uuid.dart';
 

+ 1 - 1
lib/app/controllers/mobile_core_api.dart

@@ -1,4 +1,4 @@
-import 'package:nomo/pigeons/core_api.g.dart' as pigeon;
+import 'package:flashlink/pigeons/core_api.g.dart' as pigeon;
 
 import 'base_core_api.dart';
 

+ 1 - 1
lib/app/controllers/windows/tray_controller.dart

@@ -16,7 +16,7 @@ const kEventOnTrayIconRButtonUp = 'onTrayIconRButtonUp';
 const kEventOnTrayMenuItemClick = 'onTrayMenuItemClick';
 
 class TrayController {
-  final _channel = const MethodChannel("app.nomo/tray");
+  final _channel = const MethodChannel("app.flashlink/tray");
   final ObserverList<TrayListener> _listeners = ObserverList<TrayListener>();
   Menu? _trayMenu;
 

+ 1 - 1
lib/app/controllers/windows/vpn_service.dart

@@ -2,7 +2,7 @@ import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
 import 'package:dio/dio.dart';
-import 'package:nomo/app/constants/errors.dart';
+import 'package:flashlink/app/constants/errors.dart';
 import 'package:shelf/shelf_io.dart' as shelf_io;
 import 'package:shelf_web_socket/shelf_web_socket.dart';
 

+ 1 - 1
lib/app/controllers/windows/window_controller.dart

@@ -7,7 +7,7 @@ const kEventOnWindowShow = 'onWindowShow';
 const kEventOnWindowHide = 'onWindowHide';
 
 class WindowController {
-  final _channel = const MethodChannel("app.nomo/app");
+  final _channel = const MethodChannel("app.flashlink/app");
   final ObserverList<WindowListener> _listeners =
       ObserverList<WindowListener>();
 

+ 7 - 5
lib/app/controllers/windows_core_api.dart

@@ -4,7 +4,7 @@ import 'dart:io';
 
 import 'package:flutter/services.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/controllers/windows/window_service.dart';
+import 'package:flashlink/app/controllers/windows/window_service.dart';
 import 'package:path/path.dart' as path;
 import 'package:path_provider/path_provider.dart';
 import 'package:uuid/uuid.dart';
@@ -56,7 +56,9 @@ class WindowsCoreApi implements BaseCoreApi {
   factory WindowsCoreApi.create() => WindowsCoreApi._();
 
   // Windows Method Channel
-  static const MethodChannel _channel = MethodChannel('app.xixi.nomo/core_api');
+  static const MethodChannel _channel = MethodChannel(
+    'com.flashlink.vpn/core_api',
+  );
 
   // Windows 事件流控制器
   static final StreamController<String> _eventController =
@@ -175,7 +177,7 @@ class WindowsCoreApi implements BaseCoreApi {
             time: ts,
             level: 'info',
             module: 'NM_BoostResult',
-            category: 'nomo',
+            category: 'flashlink',
             fields: Fields(
               code: 0,
               boostSessionId: _boostSessionId,
@@ -225,7 +227,7 @@ class WindowsCoreApi implements BaseCoreApi {
             time: ts,
             level: 'info',
             module: 'NM_BoostResult',
-            category: 'nomo',
+            category: 'flashlink',
             fields: Fields(
               code: code,
               boostSessionId: _boostSessionId,
@@ -426,7 +428,7 @@ class WindowsCoreApi implements BaseCoreApi {
   /// ```cpp
   /// // C++ 示例
   /// flutter::MethodChannel<flutter::EncodableValue> channel(
-  ///     messenger, "app.xixi.nomo/core_api",
+  ///     messenger, "com.flashlink.vpn/core_api",
   ///     &flutter::StandardMethodCodec::GetInstance());
   ///
   /// // 发送 VPN 状态变化

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

@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/constants/assets.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
-import 'package:nomo/config/translations/strings_enum.dart';
+import 'package:flashlink/app/constants/assets.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/config/translations/strings_enum.dart';
 import '../../config/theme/dark_theme_colors.dart';
 import '../../utils/system_helper.dart';
 import '../constants/iconfont/iconfont.dart';

+ 2 - 2
lib/app/dialog/custom_dialog.dart

@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_svg/flutter_svg.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 /// 通用弹窗组件
 class CustomDialog {

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

@@ -1,7 +1,7 @@
 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 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../config/translations/strings_enum.dart';
 import '../widgets/submit_btn.dart';

+ 1 - 1
lib/app/dialog/feedback_bottom_sheet.dart

@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
 
 import '../../config/translations/strings_enum.dart';
 import '../widgets/submit_btn.dart';

+ 1 - 1
lib/app/dialog/loading/loading_dialog.dart

@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:lottie/lottie.dart';
 import 'package:get/get.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../components/ix_snackbar.dart';
 import '../../data/models/api_exception.dart';

+ 1 - 1
lib/app/dialog/loading/simple_loading_dialog.dart

@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:lottie/lottie.dart';
 import 'package:get/get.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../components/ix_snackbar.dart';
 import '../../data/models/api_exception.dart';

+ 1 - 1
lib/app/dialog/update_dailog.dart

@@ -1,7 +1,7 @@
 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 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../config/translations/strings_enum.dart';
 import '../data/models/launch/upgrade.dart';

+ 5 - 5
lib/app/modules/account/views/account_view.dart

@@ -3,11 +3,11 @@ import 'package:flutter/services.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_svg/flutter_svg.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/app/widgets/ix_app_bar.dart';
-import 'package:nomo/app/widgets/submit_btn.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/ix_app_bar.dart';
+import 'package:flashlink/app/widgets/submit_btn.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/theme/dark_theme_colors.dart';
 import '../../../../config/translations/strings_enum.dart';

+ 1 - 1
lib/app/modules/deviceauth/controllers/deviceauth_controller.dart

@@ -1,7 +1,7 @@
 import 'dart:async';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/components/ix_snackbar.dart';
+import 'package:flashlink/app/components/ix_snackbar.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 

+ 4 - 4
lib/app/modules/deviceauth/views/deviceauth_view.dart

@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/app/widgets/ix_app_bar.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/ix_app_bar.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 import 'package:pinput/pinput.dart';
 
 import '../../../../config/theme/dark_theme_colors.dart';

+ 2 - 2
lib/app/modules/deviceauth/widgets/device_card.dart

@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../../../constants/iconfont/iconfont.dart';

+ 1 - 1
lib/app/modules/feedback/controllers/feedback_controller.dart

@@ -1,6 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/components/ix_snackbar.dart';
+import 'package:flashlink/app/components/ix_snackbar.dart';
 import 'package:uuid/uuid.dart';
 
 import '../../../../config/translations/strings_enum.dart';

+ 4 - 4
lib/app/modules/feedback/views/feedback_view.dart

@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_spinkit/flutter_spinkit.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/app/widgets/ix_app_bar.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/ix_app_bar.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../controllers/feedback_controller.dart';

+ 1 - 1
lib/app/modules/forgotpwd/views/forgotpwd_view.dart

@@ -2,7 +2,7 @@ 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 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../../../base/base_view.dart';

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

@@ -1,6 +1,6 @@
 import 'package:get/get.dart';
-import 'package:nomo/app/controllers/api_controller.dart';
-import 'package:nomo/utils/misc.dart';
+import 'package:flashlink/app/controllers/api_controller.dart';
+import 'package:flashlink/utils/misc.dart';
 import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
 import '../../../../utils/system_helper.dart';
 import '../../../controllers/base_core_api.dart';

+ 4 - 4
lib/app/modules/home/views/home_view.dart

@@ -2,10 +2,10 @@ import 'package:carousel_slider/carousel_slider.dart';
 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:flashlink/app/constants/iconfont/iconfont.dart';
+import 'package:flashlink/app/data/sp/ix_sp.dart';
+import 'package:flashlink/app/extensions/widget_extension.dart';
+import 'package:flashlink/utils/misc.dart';
 import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
 import '../../../../config/theme/dark_theme_colors.dart';
 import '../../../../config/theme/light_theme_colors.dart';

+ 1 - 1
lib/app/modules/home/widgets/connection_button.dart

@@ -3,7 +3,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'dart:math' as math;
 import 'dart:async';
 import 'package:get/get.dart';
-import 'package:nomo/app/widgets/ix_image.dart';
+import 'package:flashlink/app/widgets/ix_image.dart';
 
 import '../../../constants/assets.dart';
 import '../../../../config/theme/theme_extensions/theme_extension.dart';

+ 1 - 1
lib/app/modules/home/widgets/connection_round_button.dart

@@ -3,7 +3,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'dart:math' as math;
 import 'dart:async';
 import 'package:get/get.dart';
-import 'package:nomo/app/widgets/ix_image.dart';
+import 'package:flashlink/app/widgets/ix_image.dart';
 
 import '../../../constants/assets.dart';
 import '../../../../config/theme/theme_extensions/theme_extension.dart';

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

@@ -3,8 +3,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'dart:math' as math;
 import 'dart:async';
 import 'package:get/get.dart';
-import 'package:nomo/app/widgets/ix_image.dart';
-import 'package:nomo/utils/misc.dart';
+import 'package:flashlink/app/widgets/ix_image.dart';
+import 'package:flashlink/utils/misc.dart';
 
 import '../../../constants/assets.dart';
 import '../../../../config/theme/theme_extensions/theme_extension.dart';

+ 4 - 4
lib/app/modules/language/views/language_view.dart

@@ -1,10 +1,10 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/app/widgets/ix_app_bar.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/ix_app_bar.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../controllers/language_controller.dart';

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

@@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
 
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/constants/iconfont/iconfont.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/constants/iconfont/iconfont.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../../../routes/app_pages.dart';

+ 1 - 1
lib/app/modules/markdown/views/markdown_view.dart

@@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
 import 'package:flutter_markdown/flutter_markdown.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../base/base_view.dart';
 import '../../../widgets/ix_app_bar.dart';

+ 1 - 1
lib/app/modules/medialocation/views/medialocation_view.dart

@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart' hide Banner;
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/config/theme/dark_theme_colors.dart';
+import 'package:flashlink/config/theme/dark_theme_colors.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../../../constants/assets.dart';

+ 2 - 2
lib/app/modules/node/views/node_view.dart

@@ -1,8 +1,8 @@
 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 'package:nomo/utils/misc.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/utils/misc.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../../../base/base_view.dart';

+ 2 - 2
lib/app/modules/node/widgets/node_list.dart

@@ -3,8 +3,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_sticky_header/flutter_sticky_header.dart';
 
 import 'package:get/get.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
 
 import '../../../../config/translations/strings_enum.dart';

+ 1 - 1
lib/app/modules/notfound/views/notfound_view.dart

@@ -1,7 +1,7 @@
 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 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 import '../../../../config/translations/strings_enum.dart';
 import '../../../constants/assets.dart';
 import '../../../widgets/ix_app_bar.dart';

+ 1 - 1
lib/app/modules/precode/controllers/precode_controller.dart

@@ -84,7 +84,7 @@ class PrecodeController extends GetxController {
       final result = await ImageGallerySaverPlus.saveImage(
         imageBytes,
         quality: 100,
-        name: 'nomo_precode_${DateTime.now().millisecondsSinceEpoch}',
+        name: 'flashlink_precode_${DateTime.now().millisecondsSinceEpoch}',
       );
 
       if (result['isSuccess'] == true) {

+ 1 - 1
lib/app/modules/precode/sendemail/controllers/precode_sendemail_controller.dart

@@ -1,6 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/dialog/all_dialog.dart';
+import 'package:flashlink/app/dialog/all_dialog.dart';
 
 import '../../../../../config/translations/strings_enum.dart';
 

+ 3 - 3
lib/app/modules/precode/sendemail/views/precode_sendemail_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/base/base_view.dart';
-import 'package:nomo/app/widgets/submit_btn.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/submit_btn.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../../config/theme/dark_theme_colors.dart';
 import '../../../../../config/translations/strings_enum.dart';

+ 4 - 4
lib/app/modules/precode/views/precode_view.dart

@@ -1,10 +1,10 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/app/widgets/ix_image.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/ix_image.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/theme/dark_theme_colors.dart';
 import '../../../../config/translations/strings_enum.dart';

+ 2 - 2
lib/app/modules/precode/widgets/precode_save_dialog.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/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 import 'package:screenshot/screenshot.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
 
 import '../../../../config/theme/dark_theme_colors.dart';
 import '../../../../config/translations/strings_enum.dart';

+ 2 - 2
lib/app/modules/routingmode/controllers/routingmode_controller.dart

@@ -1,6 +1,6 @@
 import 'package:get/get.dart';
-import 'package:nomo/app/data/sp/ix_sp.dart';
-import 'package:nomo/app/constants/sp_keys.dart';
+import 'package:flashlink/app/data/sp/ix_sp.dart';
+import 'package:flashlink/app/constants/sp_keys.dart';
 
 enum RoutingMode { smart, global }
 

+ 4 - 4
lib/app/modules/routingmode/views/routingmode_view.dart

@@ -1,10 +1,10 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/app/widgets/ix_app_bar.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/ix_app_bar.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../../../constants/iconfont/iconfont.dart';

+ 8 - 8
lib/app/modules/setting/views/setting_view.dart

@@ -5,14 +5,14 @@ import 'package:flutter/services.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_svg/flutter_svg.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/constants/assets.dart';
-import 'package:nomo/app/dialog/all_dialog.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/app/widgets/ix_image.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
-import 'package:nomo/utils/device_manager.dart';
-import 'package:nomo/utils/misc.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/constants/assets.dart';
+import 'package:flashlink/app/dialog/all_dialog.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/ix_image.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/utils/device_manager.dart';
+import 'package:flashlink/utils/misc.dart';
 
 import '../../../../utils/formater.dart';
 import '../../../constants/enums.dart';

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

@@ -3,7 +3,7 @@ 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 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../config/translations/strings_enum.dart';
 import '../../../base/base_view.dart';

+ 1 - 1
lib/app/modules/splash/controllers/splash_controller.dart

@@ -1,6 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_controller.dart';
+import 'package:flashlink/app/base/base_controller.dart';
 import 'package:package_info_plus/package_info_plus.dart';
 
 import '../../../../utils/geo_downloader.dart';

+ 4 - 4
lib/app/modules/splash/views/splash_view.dart

@@ -4,10 +4,10 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_spinkit/flutter_spinkit.dart';
 import 'package:get/get.dart';
 
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/widgets/ix_image.dart';
-import 'package:nomo/app/widgets/submit_btn.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/ix_image.dart';
+import 'package:flashlink/app/widgets/submit_btn.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 import '../../../../config/translations/strings_enum.dart';
 import '../../../constants/assets.dart';
 import '../../../routes/app_pages.dart';

+ 2 - 2
lib/app/modules/splittunneling/controllers/splittunneling_controller.dart

@@ -4,8 +4,8 @@ import 'package:get/get.dart';
 
 import '../../../../utils/event_bus.dart';
 import '../../../../utils/log/logger.dart';
-import 'package:nomo/app/data/sp/ix_sp.dart';
-import 'package:nomo/app/constants/sp_keys.dart';
+import 'package:flashlink/app/data/sp/ix_sp.dart';
+import 'package:flashlink/app/constants/sp_keys.dart';
 import '../../../routes/app_pages.dart';
 import '../selectapp/controllers/splittunneling_selectapp_controller.dart';
 

+ 5 - 5
lib/app/modules/splittunneling/selectapp/controllers/splittunneling_selectapp_controller.dart

@@ -1,11 +1,11 @@
 import 'dart:convert';
 
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_controller.dart';
-import 'package:nomo/app/data/sp/ix_sp.dart';
-import 'package:nomo/app/constants/sp_keys.dart';
-import 'package:nomo/app/controllers/base_core_api.dart';
-import 'package:nomo/utils/log/logger.dart';
+import 'package:flashlink/app/base/base_controller.dart';
+import 'package:flashlink/app/data/sp/ix_sp.dart';
+import 'package:flashlink/app/constants/sp_keys.dart';
+import 'package:flashlink/app/controllers/base_core_api.dart';
+import 'package:flashlink/utils/log/logger.dart';
 
 /// 分流隧道模式枚举
 enum SplitTunnelingMode {

+ 5 - 5
lib/app/modules/splittunneling/selectapp/views/splittunneling_selectapp_view.dart

@@ -1,11 +1,11 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
-import 'package:nomo/app/base/base_view.dart';
-import 'package:nomo/app/widgets/click_opacity.dart';
-import 'package:nomo/app/widgets/ix_app_bar.dart';
-import 'package:nomo/app/widgets/ix_image.dart';
-import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
+import 'package:flashlink/app/base/base_view.dart';
+import 'package:flashlink/app/widgets/click_opacity.dart';
+import 'package:flashlink/app/widgets/ix_app_bar.dart';
+import 'package:flashlink/app/widgets/ix_image.dart';
+import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../../../config/translations/strings_enum.dart';
 import '../../../../../utils/event_bus.dart';

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません