diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..03adc8d
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,4 @@
+{
+ "IDX.aI.enableInlineCompletion": true,
+ "IDX.aI.enableCodebaseIndexing": true
+}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..be8db4f
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,54 @@
+# Changelog
+
+
+## [Unreleased]
+
+### Added
+- Run scripts for different platforms (Android device/emulator, iOS device/simulator)
+- Flutter Gen integration for better asset management
+- Improved localization with proper l10n configuration
+- Enhanced search dialog UI and state management
+
+### Changed
+- Replaced flutter_v2ray with vpnclient_engine_flutter
+- Updated dependencies and removed unused code
+- Improved UI responsiveness and overflow handling
+- Refactored main.dart for better localization support
+
+### Fixed
+- Resolved potential UI overflow issues in search dialog
+- Enhanced state initialization and lifecycle management
+- Improved layout responsiveness and SafeArea integration
+
+### Merged
+- Merged branch `development`: updated VPN link configuration to use 5.35.98.91
+- Merged branch `dodonov`: updated dependencies, improved l10n configuration, changed Android status bar style
+- Merged branch `feat/setting_page+adapter_telegrambot`: added settings page adapter, improved localization, updated plugin registrants, switched to JSON localization assets
+- Merged branch `bugfix/localization-no-synthetic-package`: resolved localization package issues, merged latest development changes
+- Merged branch `bugfix/vpnclient-engine-dependency`: improved VPN engine dependency handling, resolved localization and UI conflicts
+- Merged branch `refactoring-branch`: added new functionality including settings page, speed page, VPN provider, and navigation improvements
+- Merged branch `hotfix/temporary-vpn-uri`: updated VPN URI configuration to use temporary server
+- Merged branch `feat/vpn-link-selector`: added VPN link selector functionality
+- Merged branch `feat/dimensions`: added dimension links and UI improvements
+- Merged branch `feat/adding-ios-VPN-profile`: added iOS VPN profile support structure
+- Merged branch `ci/use-flutter-instead-dart-format`: updated CI configuration to use Flutter instead of dart format
+
+### Conflict Resolution
+- Resolved multiple merge conflicts in pubspec.yaml, pubspec.lock, localization files, and generated plugin registrants
+- Kept latest HEAD versions for all major Dart and localization files to ensure stability and consistency
+
+## [1.0.12] - 2025-01-XX
+
+### Added
+- Initial release of VPN Client app
+- Basic VPN functionality
+- Multi-language support (English, Russian, Thai, Chinese)
+- Dark/Light theme support
+- Server selection interface
+- Apps management page
+
+### Changed
+- Initial project structure and architecture
+
+### Fixed
+- Various UI improvements and bug fixes
\ No newline at end of file
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
index 06952be..aec7904 100644
--- a/android/app/src/main/res/values-night/styles.xml
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -14,5 +14,7 @@
This Theme is only used starting with V2 of Flutter's Android embedding. -->
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index cb1ef88..eb6a4d6 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -14,5 +14,7 @@
This Theme is only used starting with V2 of Flutter's Android embedding. -->
diff --git a/assets/lang/en.json b/assets/lang/en.json
index 612e72d..8dcfcc8 100644
--- a/assets/lang/en.json
+++ b/assets/lang/en.json
@@ -22,6 +22,7 @@
"disconnected": "DISCONNECTED",
"reconnecting": "RECONNECTING",
"connecting": "CONNECTING",
+<<<<<<< HEAD
"disconnecting": "DISCONNECTING",
"settings": "Settings",
"version": "Version",
@@ -38,4 +39,7 @@
"connection_reset": "Connection settings have been reset",
"failed_open_telegram": "Failed to open Telegram bot",
"about_app": "About App"
+=======
+ "disconnecting": "DISCONNECTING"
+>>>>>>> origin/bugfix/vpnclient-engine-dependency
}
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 70a622a..9f0de26 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -26,9 +26,9 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
- flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29
- flutter_v2ray: 21ee520e013877941e2e67b3b48aed9c6870e8dc
- shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
+ flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
+ flutter_v2ray: 1190bb389b67a1dc9f28ece1d4b308101e38395e
+ shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
PODFILE CHECKSUM: f8e15f817b1bf5846cb6aad560a31cf33c165196
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
index 21a3cc1..3a6a651 100644
--- a/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -2,7 +2,7 @@
+ location = "group:VPN Client.xcodeproj">
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index cbf8e75..2d87ba2 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -1,50 +1,75 @@
import Flutter
import UIKit
-///VPN
-///import Foundation
import NetworkExtension
-class VpnConfigurator {
- static func setupTunnel() {
- let manager = NEVPNManager.shared()
- manager.loadFromPreferences { error in
- if let error = error {
- print("Failed to load VPN preferences: \(error)")
- return
- }
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
- let proto = NETunnelProviderProtocol()
- proto.providerBundleIdentifier = "com.vpnclient.VPNclientTunnel"
- proto.serverAddress = "VPNclient"
+ let controller = window?.rootViewController as! FlutterViewController
+ let vpnChannel = FlutterMethodChannel(
+ name: "com.vpnclient/vpn_control",
+ binaryMessenger: controller.binaryMessenger
+ )
- manager.protocolConfiguration = proto
- manager.localizedDescription = "VPNclient"
- manager.isEnabled = true
+ vpnChannel.setMethodCallHandler { [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) in
+ guard let self = self else { return }
+ switch call.method {
+ case "setupVPN":
+ guard let args = call.arguments as? [String: String],
+ let tunAddr = args["tunAddr"],
+ let tunMask = args["tunMask"],
+ let tunDns = args["tunDns"],
+ let socks5Proxy = args["socks5Proxy"] else {
+ result(FlutterError(code: "INVALID_ARGS", message: "Invalid arguments", details: nil))
+ return
+ }
+ print("AppDelegate: Setting up VPN with tunAddr=\(tunAddr), socks5Proxy=\(socks5Proxy)")
+ let vpnManager = VPNManager.sharedInstance ?? VPNManager()
+ vpnManager.setupVPNConfiguration(tunAddr: tunAddr, tunMask: tunMask, tunDns: tunDns, socks5Proxy: socks5Proxy) { error in
+ if let error = error {
+ print("AppDelegate: Setup VPN failed: \(error.localizedDescription)")
+ result(FlutterError(code: "SETUP_FAILED", message: error.localizedDescription, details: nil))
+ } else {
+ print("AppDelegate: Setup VPN succeeded")
+ result(nil)
+ }
+ }
- manager.saveToPreferences { error in
- if let error = error {
- print("Failed to save VPN configuration: \(error)")
- } else {
- print("VPN configuration saved successfully.")
+ case "startVPN":
+ let vpnManager = VPNManager.sharedInstance ?? VPNManager()
+ vpnManager.startVPN { error in
+ if let error = error {
+ print("AppDelegate: Start VPN failed: \(error.localizedDescription)")
+ result(FlutterError(code: "START_FAILED", message: error.localizedDescription, details: nil))
+ } else {
+ print("AppDelegate: Start VPN succeeded")
+ result(nil)
+ }
}
- }
- }
- }
-}
-///VPN
+ case "stopVPN":
+ let vpnManager = VPNManager.sharedInstance ?? VPNManager()
+ vpnManager.stopVPN {
+ print("AppDelegate: Stop VPN succeeded")
+ result(nil)
+ }
+ case "getVPNStatus":
+ let vpnManager = VPNManager.sharedInstance ?? VPNManager()
+ let status = vpnManager.vpnStatus.description
+ print("AppDelegate: VPN status: \(status)")
+ result(status)
-@main
-@objc class AppDelegate: FlutterAppDelegate {
- override func application(
- _ application: UIApplication,
- didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
- ) -> Bool {
- GeneratedPluginRegistrant.register(with: self)
- ///vpn
- VpnConfigurator.setupTunnel()
- ///vpn
- return super.application(application, didFinishLaunchingWithOptions: launchOptions)
- }
-}
+ default:
+ result(FlutterMethodNotImplemented)
+ }
+ }
+
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+}
\ No newline at end of file
diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard
index f3c2851..ff3ee21 100644
--- a/ios/Runner/Base.lproj/Main.storyboard
+++ b/ios/Runner/Base.lproj/Main.storyboard
@@ -1,8 +1,10 @@
-
-
+
+
+
-
+
+
@@ -14,13 +16,14 @@
-
+
-
+
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 8100ced..57a060e 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -33,6 +33,11 @@
UIApplicationSupportsIndirectInputEvents
+ UIBackgroundModes
+
+ fetch
+ remote-notification
+
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
@@ -50,5 +55,9 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
+ com.apple.developer.networking.vpn.api
+
+ allow-vpn
+
diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements
new file mode 100644
index 0000000..ffab33e
--- /dev/null
+++ b/ios/Runner/Runner.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.developer.networking.networkextension
+
+ packet-tunnel-provider
+
+
+
diff --git a/ios/Runner/RunnerRelease.entitlements b/ios/Runner/RunnerRelease.entitlements
index 7b3112c..0c67376 100644
--- a/ios/Runner/RunnerRelease.entitlements
+++ b/ios/Runner/RunnerRelease.entitlements
@@ -1,18 +1,5 @@
-
- com.apple.developer.networking.networkextension
-
- dns-settings
- packet-tunnel-provider
- dns-proxy
- app-proxy-provider
- content-filter-provider
-
- com.apple.developer.networking.vpn.api
-
- allow-vpn
-
-
+
diff --git a/ios/Runner/VPNManager.swift b/ios/Runner/VPNManager.swift
new file mode 100644
index 0000000..7c018d7
--- /dev/null
+++ b/ios/Runner/VPNManager.swift
@@ -0,0 +1,180 @@
+import NetworkExtension
+import Foundation
+
+class VPNManager {
+ private var vpnManager: NETunnelProviderManager?
+ private let profileName = "Controller"
+ private var isInitialized = false
+ private var initializationCompletion: ((Error?) -> Void)?
+ static var sharedInstance: VPNManager?
+
+ init() {
+ print("VPNManager: Initializing...")
+ loadVPNManager { error in
+ if let error = error {
+ print("VPNManager: Initialization failed with error: \(error.localizedDescription)")
+ } else {
+ print("VPNManager: Initialization completed successfully")
+ }
+ self.isInitialized = true
+ self.initializationCompletion?(error)
+ self.initializationCompletion = nil
+ }
+ }
+
+ private func loadVPNManager(completion: @escaping (Error?) -> Void) {
+ print("VPNManager: Loading existing VPN managers...")
+ NETunnelProviderManager.loadAllFromPreferences { managers, error in
+ if let error = error {
+ print("VPNManager: Error loading VPN managers: \(error.localizedDescription)")
+ self.vpnManager = NETunnelProviderManager()
+ self.vpnManager?.localizedDescription = self.profileName
+ print("VPNManager: Created new VPN profile due to error: \(self.profileName)")
+ completion(nil)
+ return
+ }
+
+ print("VPNManager: Loaded \(managers?.count ?? 0) VPN managers")
+ if let existingManager = managers?.first(where: { $0.localizedDescription == self.profileName }) {
+ self.vpnManager = existingManager
+ print("VPNManager: Found existing VPN profile: \(self.profileName)")
+ } else {
+ self.vpnManager = NETunnelProviderManager()
+ self.vpnManager?.localizedDescription = self.profileName
+ print("VPNManager: Created new VPN profile: \(self.profileName)")
+ }
+ print("VPNManager: vpnManager is \(self.vpnManager != nil ? "set" : "nil")")
+ completion(nil)
+ }
+
+ // Таймаут для loadAllFromPreferences
+ DispatchQueue.global().asyncAfter(deadline: .now() + 5) {
+ if !self.isInitialized {
+ print("VPNManager: loadAllFromPreferences timed out")
+ self.vpnManager = NETunnelProviderManager()
+ self.vpnManager?.localizedDescription = self.profileName
+ print("VPNManager: Created new VPN profile due to timeout: \(self.profileName)")
+ self.isInitialized = true
+ completion(nil)
+ }
+ }
+ }
+
+ private func waitForInitialization(completion: @escaping (Error?) -> Void) {
+ if isInitialized {
+ print("VPNManager: Already initialized")
+ completion(nil)
+ return
+ }
+ print("VPNManager: Waiting for initialization...")
+ initializationCompletion = completion
+ }
+
+ func setupVPNConfiguration(tunAddr: String, tunMask: String, tunDns: String, socks5Proxy: String, completion: @escaping (Error?) -> Void) {
+ print("VPNManager: Setting up VPN configuration with tunAddr=\(tunAddr), tunMask=\(tunMask), tunDns=\(tunDns), socks5Proxy=\(socks5Proxy)")
+ waitForInitialization { error in
+ if let error = error {
+ completion(error)
+ return
+ }
+ guard let vpnManager = self.vpnManager else {
+ print("VPNManager: VPN Manager not initialized")
+ completion(NSError(domain: "VPNError", code: -1, userInfo: [NSLocalizedDescriptionKey: "VPN Manager not initialized"]))
+ return
+ }
+
+ vpnManager.loadFromPreferences { error in
+ if let error = error {
+ print("VPNManager: Load preferences error: \(error.localizedDescription)")
+ completion(error)
+ return
+ }
+
+ let tunnelProtocol = NETunnelProviderProtocol()
+ tunnelProtocol.providerBundleIdentifier = "click.vpnclient.VPNclientTunnel"
+ tunnelProtocol.serverAddress = socks5Proxy
+ tunnelProtocol.providerConfiguration = [
+ "tunAddr": tunAddr,
+ "tunMask": tunMask,
+ "tunDns": tunDns,
+ "socks5Proxy": socks5Proxy
+ ]
+
+ vpnManager.protocolConfiguration = tunnelProtocol
+ vpnManager.isEnabled = true
+ vpnManager.isOnDemandEnabled = false
+
+ print("VPNManager: Saving VPN configuration...")
+ vpnManager.saveToPreferences { error in
+ if let error = error {
+ print("VPNManager: Save preferences error: \(error.localizedDescription)")
+ completion(error)
+ } else {
+ print("VPNManager: VPN configuration saved successfully")
+ completion(nil)
+ }
+ }
+ }
+ }
+ }
+
+ func startVPN(completion: @escaping (Error?) -> Void) {
+ print("VPNManager: Starting VPN...")
+ waitForInitialization { error in
+ if let error = error {
+ completion(error)
+ return
+ }
+ guard let vpnManager = self.vpnManager else {
+ print("VPNManager: VPN Manager not initialized")
+ completion(NSError(domain: "VPNError", code: -1, userInfo: [NSLocalizedDescriptionKey: "VPN Manager not initialized"]))
+ return
+ }
+ vpnManager.loadFromPreferences { error in
+ if let error = error {
+ print("VPNManager: Load preferences error before start: \(error.localizedDescription)")
+ completion(error)
+ return
+ }
+ do {
+ try vpnManager.connection.startVPNTunnel()
+ print("VPNManager: VPN tunnel started successfully")
+ completion(nil)
+ } catch {
+ print("VPNManager: Start VPN error: \(error.localizedDescription)")
+ completion(error)
+ }
+ }
+ }
+ }
+
+ func stopVPN(completion: @escaping () -> Void) {
+ print("VPNManager: Stopping VPN...")
+ waitForInitialization { _ in
+ self.vpnManager?.connection.stopVPNTunnel()
+ completion()
+ }
+ }
+
+ var vpnStatus: NEVPNStatus {
+ let status = vpnManager?.connection.status ?? .invalid
+ print("VPNManager: Current VPN status: \(status.description)")
+ return status
+ }
+
+ static func cleanup() {
+ sharedInstance = nil
+ }
+}
+
+extension NEVPNStatus {
+ var description: String {
+ switch self {
+ case .disconnected: return "Disconnected"
+ case .connecting: return "Connecting..."
+ case .connected: return "Connected"
+ case .disconnecting: return "Disconnecting..."
+ default: return "Not Added Profile"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/VPN Client.xcodeproj/project.pbxproj
similarity index 69%
rename from ios/Runner.xcodeproj/project.pbxproj
rename to ios/VPN Client.xcodeproj/project.pbxproj
index 6251e06..500eac7 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/VPN Client.xcodeproj/project.pbxproj
@@ -3,19 +3,21 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 54;
+ objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
- 05623FCADE53740FE6EC38FC /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C1A7CF68EF82448274F79EE /* Pods_RunnerTests.framework */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 2D7B47EE58217BA44F021C99 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A0366090C7CE5E83E3E66D2 /* Pods_RunnerTests.framework */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
- 5CF4606063F6CF5DDF0DEF1E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 474E7930403F702C7244270A /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ ADCEA9EEA0674573FF96F9D6 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C9AB3A9273437DA77CF7190 /* Pods_Runner.framework */; };
+ D86303622DDAA124009E3D50 /* VPNManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D86303612DDAA124009E3D50 /* VPNManager.swift */; };
+ D863037A2DDAD1CC009E3D50 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D86303792DDAD1CC009E3D50 /* NetworkExtension.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -26,12 +28,19 @@
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
+ D86303802DDAD1CC009E3D50 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D86303772DDAD1CC009E3D50;
+ remoteInfo = VPNclientTunnel;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
+ buildActionMask = 12;
dstPath = "";
dstSubfolderSpec = 10;
files = (
@@ -39,23 +48,31 @@
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
+ D86303832DDAD1CC009E3D50 /* Embed Foundation Extensions */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = "";
+ dstSubfolderSpec = 13;
+ files = (
+ );
+ name = "Embed Foundation Extensions";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
- 197284AFD158A57F33B7508F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
- 2BABBD1CBB549C229028E3E6 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3A0366090C7CE5E83E3E66D2 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3AC403B42DBB3FD400E35EC1 /* RunnerRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerRelease.entitlements; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
- 40D432E32B669D72F284E50A /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; };
- 474E7930403F702C7244270A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 6C9AB3A9273437DA77CF7190 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
- 8C1A7CF68EF82448274F79EE /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8665B952CF21C952CDD28CC0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -63,17 +80,44 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- B67FBA7DE552A310D8682AF3 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; };
- D486CAC8BA4A2B991D6B8DDF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
- DED175BEB396A3E3B6FCC983 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; };
+ A232C605EB1ADE1BB86E5BF8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ AC1B24E5523670E179DC665F /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; };
+ ACFD93A1D03164446FE727AB /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; };
+ C5E533B152977104C504A2D5 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ D86303602DDAA0DD009E3D50 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
+ D86303612DDAA124009E3D50 /* VPNManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNManager.swift; sourceTree = ""; };
+ D86303782DDAD1CC009E3D50 /* VPNclientTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = VPNclientTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ D86303792DDAD1CC009E3D50 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
+ E092053B252D5542B476BDA0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
+/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
+ D86303872DDAD1CC009E3D50 /* Exceptions for "VPNclientTunnel" folder in "VPNclientTunnel" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ Info.plist,
+ );
+ target = D86303772DDAD1CC009E3D50 /* VPNclientTunnel */;
+ };
+/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
+
+/* Begin PBXFileSystemSynchronizedRootGroup section */
+ D863037B2DDAD1CC009E3D50 /* VPNclientTunnel */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ exceptions = (
+ D86303872DDAD1CC009E3D50 /* Exceptions for "VPNclientTunnel" folder in "VPNclientTunnel" target */,
+ );
+ path = VPNclientTunnel;
+ sourceTree = "";
+ };
+/* End PBXFileSystemSynchronizedRootGroup section */
+
/* Begin PBXFrameworksBuildPhase section */
960B5143B6A69B8BB00D37F4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 05623FCADE53740FE6EC38FC /* Pods_RunnerTests.framework in Frameworks */,
+ 2D7B47EE58217BA44F021C99 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -81,7 +125,15 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 5CF4606063F6CF5DDF0DEF1E /* Pods_Runner.framework in Frameworks */,
+ ADCEA9EEA0674573FF96F9D6 /* Pods_Runner.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D86303752DDAD1CC009E3D50 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D863037A2DDAD1CC009E3D50 /* NetworkExtension.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -91,12 +143,12 @@
1676946CE4F357204D9C4813 /* Pods */ = {
isa = PBXGroup;
children = (
- 197284AFD158A57F33B7508F /* Pods-Runner.debug.xcconfig */,
- D486CAC8BA4A2B991D6B8DDF /* Pods-Runner.release.xcconfig */,
- 2BABBD1CBB549C229028E3E6 /* Pods-Runner.profile.xcconfig */,
- 40D432E32B669D72F284E50A /* Pods-RunnerTests.debug.xcconfig */,
- DED175BEB396A3E3B6FCC983 /* Pods-RunnerTests.release.xcconfig */,
- B67FBA7DE552A310D8682AF3 /* Pods-RunnerTests.profile.xcconfig */,
+ C5E533B152977104C504A2D5 /* Pods-Runner.debug.xcconfig */,
+ A232C605EB1ADE1BB86E5BF8 /* Pods-Runner.release.xcconfig */,
+ E092053B252D5542B476BDA0 /* Pods-Runner.profile.xcconfig */,
+ ACFD93A1D03164446FE727AB /* Pods-RunnerTests.debug.xcconfig */,
+ AC1B24E5523670E179DC665F /* Pods-RunnerTests.release.xcconfig */,
+ 8665B952CF21C952CDD28CC0 /* Pods-RunnerTests.profile.xcconfig */,
);
path = Pods;
sourceTree = "";
@@ -125,6 +177,7 @@
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
+ D863037B2DDAD1CC009E3D50 /* VPNclientTunnel */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
1676946CE4F357204D9C4813 /* Pods */,
@@ -137,6 +190,7 @@
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
+ D86303782DDAD1CC009E3D50 /* VPNclientTunnel.appex */,
);
name = Products;
sourceTree = "";
@@ -144,6 +198,8 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
+ D86303612DDAA124009E3D50 /* VPNManager.swift */,
+ D86303602DDAA0DD009E3D50 /* Runner.entitlements */,
3AC403B42DBB3FD400E35EC1 /* RunnerRelease.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
@@ -160,8 +216,9 @@
E9078DB93BAB5787C511C451 /* Frameworks */ = {
isa = PBXGroup;
children = (
- 474E7930403F702C7244270A /* Pods_Runner.framework */,
- 8C1A7CF68EF82448274F79EE /* Pods_RunnerTests.framework */,
+ D86303792DDAD1CC009E3D50 /* NetworkExtension.framework */,
+ 6C9AB3A9273437DA77CF7190 /* Pods_Runner.framework */,
+ 3A0366090C7CE5E83E3E66D2 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "";
@@ -173,7 +230,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
- 81BFDB42C18FDD849CBD3B91 /* [CP] Check Pods Manifest.lock */,
+ 4D1B5BEE14246A87461BBB9B /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
960B5143B6A69B8BB00D37F4 /* Frameworks */,
@@ -192,24 +249,46 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
- 6540B4C79A6EB9CD6CA8C965 /* [CP] Check Pods Manifest.lock */,
+ 2119E14845FE31FAB4D234BF /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
- F6B5A4EE9456ACB2EE7DD28F /* [CP] Embed Pods Frameworks */,
+ D86303832DDAD1CC009E3D50 /* Embed Foundation Extensions */,
+ F443A19394F529718D644FF5 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
+ D86303812DDAD1CC009E3D50 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
+ D86303772DDAD1CC009E3D50 /* VPNclientTunnel */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D86303882DDAD1CC009E3D50 /* Build configuration list for PBXNativeTarget "VPNclientTunnel" */;
+ buildPhases = (
+ D86303742DDAD1CC009E3D50 /* Sources */,
+ D86303752DDAD1CC009E3D50 /* Frameworks */,
+ D86303762DDAD1CC009E3D50 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ fileSystemSynchronizedGroups = (
+ D863037B2DDAD1CC009E3D50 /* VPNclientTunnel */,
+ );
+ name = VPNclientTunnel;
+ productName = VPNclientTunnel;
+ productReference = D86303782DDAD1CC009E3D50 /* VPNclientTunnel.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -217,6 +296,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
+ LastSwiftUpdateCheck = 1620;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
@@ -228,10 +308,12 @@
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
+ D86303772DDAD1CC009E3D50 = {
+ CreatedOnToolsVersion = 16.2;
+ };
};
};
- buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
- compatibilityVersion = "Xcode 9.3";
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "VPN Client" */;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -239,12 +321,14 @@
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
+ preferredProjectObjectVersion = 77;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
+ D86303772DDAD1CC009E3D50 /* VPNclientTunnel */,
);
};
/* End PBXProject section */
@@ -268,26 +352,17 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
- isa = PBXShellScriptBuildPhase;
- alwaysOutOfDate = 1;
+ D86303762DDAD1CC009E3D50 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
- inputPaths = (
- "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
- );
- name = "Thin Binary";
- outputPaths = (
- );
runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
- 6540B4C79A6EB9CD6CA8C965 /* [CP] Check Pods Manifest.lock */ = {
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 2119E14845FE31FAB4D234BF /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -309,7 +384,23 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 81BFDB42C18FDD849CBD3B91 /* [CP] Check Pods Manifest.lock */ = {
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 12;
+ files = (
+ );
+ inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
+ };
+ 4D1B5BEE14246A87461BBB9B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -346,7 +437,7 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
- F6B5A4EE9456ACB2EE7DD28F /* [CP] Embed Pods Frameworks */ = {
+ F443A19394F529718D644FF5 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -380,6 +471,14 @@
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ D86303622DDAA124009E3D50 /* VPNManager.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D86303742DDAD1CC009E3D50 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -391,6 +490,11 @@
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
+ D86303812DDAD1CC009E3D50 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D86303772DDAD1CC009E3D50 /* VPNclientTunnel */;
+ targetProxy = D86303802DDAD1CC009E3D50 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -472,17 +576,20 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
- DEVELOPMENT_TEAM = "";
+ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6XT4R7V83F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = "VPN Client";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.5;
- PRODUCT_BUNDLE_IDENTIFIER = click.vpnclient;
+ MARKETING_VERSION = 1.0.12;
+ PRODUCT_BUNDLE_IDENTIFIER = vpnclient.click;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -493,7 +600,7 @@
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 40D432E32B669D72F284E50A /* Pods-RunnerTests.debug.xcconfig */;
+ baseConfigurationReference = ACFD93A1D03164446FE727AB /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -511,7 +618,7 @@
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = DED175BEB396A3E3B6FCC983 /* Pods-RunnerTests.release.xcconfig */;
+ baseConfigurationReference = AC1B24E5523670E179DC665F /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -527,7 +634,7 @@
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = B67FBA7DE552A310D8682AF3 /* Pods-RunnerTests.profile.xcconfig */;
+ baseConfigurationReference = 8665B952CF21C952CDD28CC0 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -660,17 +767,20 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
- DEVELOPMENT_TEAM = "";
+ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6XT4R7V83F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = "VPN Client";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.5;
- PRODUCT_BUNDLE_IDENTIFIER = click.vpnclient;
+ MARKETING_VERSION = 1.0.12;
+ PRODUCT_BUNDLE_IDENTIFIER = vpnclient.click;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -688,17 +798,18 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
- CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
- DEVELOPMENT_TEAM = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6XT4R7V83F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = "VPN Client";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.5;
- PRODUCT_BUNDLE_IDENTIFIER = click.vpnclient;
+ MARKETING_VERSION = 1.0.12;
+ PRODUCT_BUNDLE_IDENTIFIER = vpnclient.click;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -707,6 +818,123 @@
};
name = Release;
};
+ D86303842DDAD1CC009E3D50 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = VPNclientTunnel/VPNclientTunnel.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6XT4R7V83F;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = VPNclientTunnel/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = VPNclientTunnel;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = click.vpnclient.VPNclientTunnel;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ D86303852DDAD1CC009E3D50 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = VPNclientTunnel/VPNclientTunnel.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6XT4R7V83F;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = VPNclientTunnel/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = VPNclientTunnel;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = click.vpnclient.VPNclientTunnel;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ D86303862DDAD1CC009E3D50 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = VPNclientTunnel/VPNclientTunnel.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6XT4R7V83F;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = VPNclientTunnel/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = VPNclientTunnel;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = click.vpnclient.VPNclientTunnel;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Profile;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -720,7 +948,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "VPN Client" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
@@ -740,6 +968,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ D86303882DDAD1CC009E3D50 /* Build configuration list for PBXNativeTarget "VPNclientTunnel" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D86303842DDAD1CC009E3D50 /* Debug */,
+ D86303852DDAD1CC009E3D50 /* Release */,
+ D86303862DDAD1CC009E3D50 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/VPN Client.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to ios/VPN Client.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/VPN Client.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 100%
rename from ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
rename to ios/VPN Client.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/VPN Client.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
similarity index 100%
rename from ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
rename to ios/VPN Client.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/VPN Client.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
similarity index 90%
rename from ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
rename to ios/VPN Client.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 15cada4..ba31c1f 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/VPN Client.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -17,7 +17,7 @@
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
- ReferencedContainer = "container:Runner.xcodeproj">
+ ReferencedContainer = "container:VPN Client.xcodeproj">
@@ -33,7 +33,7 @@
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
- ReferencedContainer = "container:Runner.xcodeproj">
+ ReferencedContainer = "container:VPN Client.xcodeproj">
@@ -45,7 +45,7 @@
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
- ReferencedContainer = "container:Runner.xcodeproj">
+ ReferencedContainer = "container:VPN Client.xcodeproj">
@@ -68,7 +68,7 @@
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
- ReferencedContainer = "container:Runner.xcodeproj">
+ ReferencedContainer = "container:VPN Client.xcodeproj">
@@ -85,7 +85,7 @@
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
- ReferencedContainer = "container:Runner.xcodeproj">
+ ReferencedContainer = "container:VPN Client.xcodeproj">
diff --git a/ios/VPNclientTunnel/Info.plist b/ios/VPNclientTunnel/Info.plist
new file mode 100644
index 0000000..9a63630
--- /dev/null
+++ b/ios/VPNclientTunnel/Info.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ NSExtension
+
+ com.apple.developer.networking.vpn.api
+
+ allow-vpn
+
+ UIBackgroundModes
+
+ fetch
+ remote-notification
+
+ NSExtensionPointIdentifier
+ com.apple.networkextension.packet-tunnel
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).PacketTunnelProvider
+
+
+
diff --git a/ios/VPNclientTunnel/PacketTunnelProvider.swift b/ios/VPNclientTunnel/PacketTunnelProvider.swift
new file mode 100644
index 0000000..6d96061
--- /dev/null
+++ b/ios/VPNclientTunnel/PacketTunnelProvider.swift
@@ -0,0 +1,137 @@
+import NetworkExtension
+import os.log
+
+class PacketTunnelProvider: NEPacketTunnelProvider {
+ private var tunnelRunning = false
+
+ override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
+ os_log(.debug, "PacketTunnelProvider: Starting tunnel with options: %@", String(describing: options))
+
+ guard let protocolConfiguration = protocolConfiguration as? NETunnelProviderProtocol,
+ let providerConfig = protocolConfiguration.providerConfiguration,
+ let tunAddr = providerConfig["tunAddr"] as? String,
+ let tunMask = providerConfig["tunMask"] as? String,
+ let tunDns = providerConfig["tunDns"] as? String,
+ let socks5Proxy = providerConfig["socks5Proxy"] as? String else {
+ os_log(.error, "PacketTunnelProvider: Failed to load provider configuration")
+ completionHandler(NSError(domain: "PacketTunnelProvider", code: -1, userInfo: [NSLocalizedDescriptionKey: "Missing provider configuration"]))
+ return
+ }
+
+ os_log(.debug, "PacketTunnelProvider: Config - tunAddr: %@, tunMask: %@, tunDns: %@, socks5Proxy: %@", tunAddr, tunMask, tunDns, socks5Proxy)
+
+ let proxyComponents = socks5Proxy.components(separatedBy: ":")
+ guard proxyComponents.count == 2,
+ let socks5Address = proxyComponents.first,
+ let socks5Port = UInt16(proxyComponents.last ?? "1080") else {
+ os_log(.error, "PacketTunnelProvider: Invalid SOCKS5 proxy format: %@", socks5Proxy)
+ completionHandler(NSError(domain: "PacketTunnelProvider", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid SOCKS5 proxy format"]))
+ return
+ }
+
+ let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: socks5Address)
+ settings.mtu = 1500
+
+ let ipv4Settings = NEIPv4Settings(addresses: [tunAddr], subnetMasks: [tunMask])
+ ipv4Settings.includedRoutes = [NEIPv4Route.default()]
+ settings.ipv4Settings = ipv4Settings
+
+ let dnsSettings = NEDNSSettings(servers: [tunDns])
+ settings.dnsSettings = dnsSettings
+
+ os_log(.debug, "PacketTunnelProvider: Applying tunnel network settings...")
+ setTunnelNetworkSettings(settings) { error in
+ if let error = error {
+ os_log(.error, "PacketTunnelProvider: Failed to set tunnel network settings: %@", error.localizedDescription)
+ completionHandler(error)
+ return
+ }
+
+ os_log(.info, "PacketTunnelProvider: Tunnel network settings applied successfully")
+
+ let config = """
+ tunnel:
+ name: tun0
+ mtu: 8500
+ socks5:
+ address: "\(socks5Address)"
+ port: \(socks5Port)
+ """
+
+ os_log(.debug, "PacketTunnelProvider: Starting hev-socks5-tunnel with config: %@", config)
+ DispatchQueue.global().async {
+ self.startHevSocks5Tunnel(withConfig: config)
+ }
+
+ self.monitorTunnelActivity()
+
+ os_log(.debug, "PacketTunnelProvider: Calling completion handler with success")
+ completionHandler(nil)
+ }
+ }
+
+ func startHevSocks5Tunnel(withConfig config: String) {
+ os_log(.debug, "PacketTunnelProvider: Starting hev-socks5-tunnel...")
+
+ guard let configData = config.data(using: .utf8) else {
+ os_log(.error, "PacketTunnelProvider: Failed to convert config to UTF-8 data")
+ return
+ }
+ let configLen = UInt32(configData.count)
+
+ // Поскольку мы не можем получить tun_fd, нужно переработать логику
+ os_log(.debug, "PacketTunnelProvider: Using packetFlow instead of tun_fd")
+
+ // Запускаем hev-socks5-tunnel в режиме, где мы сами обрабатываем пакеты
+ tunnelRunning = true
+ DispatchQueue.global().async {
+ // Читаем пакеты из packetFlow и передаём их в SOCKS5
+ self.handlePackets()
+ }
+ }
+
+ func handlePackets() {
+ let flow = self.packetFlow
+
+ flow.readPackets { packets, protocols in
+ if !self.tunnelRunning {
+ os_log(.info, "PacketTunnelProvider: Stopping packet handling")
+ return
+ }
+
+ for (packet, proto) in zip(packets, protocols) {
+ os_log(.debug, "PacketTunnelProvider: Received packet of size %d, protocol: %@", packet.count, proto.description)
+ // Здесь нужно передать пакет в hev-socks5-tunnel
+ // Например, через кастомный интерфейс или сокет
+ }
+
+ // Продолжаем читать пакеты
+ self.handlePackets()
+ }
+ }
+
+ func monitorTunnelActivity() {
+ DispatchQueue.global().async {
+ while self.tunnelRunning {
+ usleep(1000000) // Проверка каждую секунду
+ os_log(.debug, "PacketTunnelProvider: Tunnel still active, checking packets...")
+ }
+ }
+ }
+
+ func checkTunnelStatus() {
+ os_log(.debug, "PacketTunnelProvider: Checking tunnel status...")
+ if self.packetFlow == nil {
+ os_log(.error, "PacketTunnelProvider: Tunnel flow is nil, possible disconnection")
+ } else {
+ os_log(.info, "PacketTunnelProvider: Tunnel flow is active")
+ }
+ }
+
+ override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
+ os_log(.debug, "PacketTunnelProvider: Stopping tunnel with reason: %@", reason.rawValue.description)
+ tunnelRunning = false
+// hev_socks5_tunnel_quit()
+ completionHandler()
+ }
+}
diff --git a/ios/VPNclientTunnel/VPNclientTunnel.entitlements b/ios/VPNclientTunnel/VPNclientTunnel.entitlements
new file mode 100644
index 0000000..0154eb4
--- /dev/null
+++ b/ios/VPNclientTunnel/VPNclientTunnel.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.click.vpnclient
+
+
+
diff --git a/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/build-request.json b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/build-request.json
new file mode 100644
index 0000000..38eab09
--- /dev/null
+++ b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/build-request.json
@@ -0,0 +1,27 @@
+{
+ "buildCommand" : {
+ "command" : "build",
+ "skipDependencies" : false,
+ "style" : "buildOnly"
+ },
+ "configuredTargets" : [
+
+ ],
+ "continueBuildingAfterErrors" : false,
+ "dependencyScope" : "workspace",
+ "enableIndexBuildArena" : false,
+ "hideShellScriptEnvironment" : false,
+ "parameters" : {
+ "action" : "build",
+ "overrides" : {
+
+ }
+ },
+ "qos" : "utility",
+ "schemeCommand" : "launch",
+ "showNonLoggedProgress" : true,
+ "useDryRun" : false,
+ "useImplicitDependencies" : false,
+ "useLegacyBuildLocations" : false,
+ "useParallelTargets" : true
+}
\ No newline at end of file
diff --git a/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/description.msgpack b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/description.msgpack
new file mode 100644
index 0000000..0e18711
Binary files /dev/null and b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/description.msgpack differ
diff --git a/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/manifest.json b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/manifest.json
new file mode 100644
index 0000000..7391713
--- /dev/null
+++ b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/manifest.json
@@ -0,0 +1 @@
+{"client":{"name":"basic","version":0,"file-system":"device-agnostic","perform-ownership-analysis":"no"},"targets":{"":[""]},"commands":{"":{"tool":"phony","inputs":[""],"outputs":[""]},"P0:::Gate WorkspaceHeaderMapVFSFilesWritten":{"tool":"phony","inputs":[],"outputs":[""]}}}
\ No newline at end of file
diff --git a/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/target-graph.txt b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/target-graph.txt
new file mode 100644
index 0000000..b83b158
--- /dev/null
+++ b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/target-graph.txt
@@ -0,0 +1 @@
+Target dependency graph (0 target)
\ No newline at end of file
diff --git a/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/task-store.msgpack b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/task-store.msgpack
new file mode 100644
index 0000000..6cef3fe
Binary files /dev/null and b/ios/build/XCBuildData/2b3a1334de51e4dc6dd39387be36d594.xcbuilddata/task-store.msgpack differ
diff --git a/lib/core/constants/storage_keys.dart b/lib/core/constants/storage_keys.dart
new file mode 100644
index 0000000..5277ad4
--- /dev/null
+++ b/lib/core/constants/storage_keys.dart
@@ -0,0 +1,8 @@
+// lib/core/constants/storage_keys.dart
+class StorageKeys {
+ static const String selectedApps = 'selected_apps';
+ static const String selectedServers = 'selected_servers';
+ static const String recentlySearchedApps = 'recently_searched_apps';
+ static const String recentlySearchedServers = 'recently_searched_servers';
+ static const String isDarkTheme = 'isDarkTheme';
+}
diff --git a/lib/design/dimensions.dart b/lib/design/dimensions.dart
index 52ecaf9..2730677 100644
--- a/lib/design/dimensions.dart
+++ b/lib/design/dimensions.dart
@@ -1,72 +1,3 @@
-import 'package:flutter/material.dart';
-
-class CustomString {
- final BuildContext context;
- late Locale locale;
-
- CustomString(this.context) {
- locale = Localizations.localeOf(context);
- }
-
- String get connected {
- return _localized('connected');
- }
-
- String get disconnected {
- return _localized('disconnected');
- }
-
- String get connecting {
- return _localized('connecting');
- }
-
- String get disconnecting {
- return _localized('disconnecting');
- }
-
- String get allapp {
- return _localized('all_apps');
- }
-
- String _localized(String key) {
- switch (locale.languageCode) {
- case 'ru':
- return {
- 'connected': 'ПОДКЛЮЧЕН',
- 'disconnected': 'ОТКЛЮЧЕН',
- 'connecting': 'ПОДКЛЮЧЕНИЕ',
- 'disconnecting': 'ОТКЛЮЧЕНИЕ',
- "all_apps": "Все приложения",
- }[key]!;
- case 'th':
- return {
- "connected": "เชื่อมต่อแล้ว",
- "disconnected": "ไม่ได้เชื่อมต่อ",
- "connecting": "กำลังเชื่อมต่อ",
- "disconnecting": "กำลังตัดการเชื่อมต่อ",
- "all_apps": "แอปทั้งหมด",
- }[key]!;
- case 'zh':
- return {
- "connected": "已连接",
- "disconnected": "已断开",
- "connecting": "正在连接",
- "disconnecting": "正在断开",
- "all_apps": "所有应用",
- }[key]!;
- case 'en':
- default:
- return {
- 'connected': 'CONNECTED',
- 'disconnected': 'DISCONNECTED',
- 'connecting': 'CONNECTING',
- 'disconnecting': 'DISCONNECTING',
- "all_apps": "All Applications",
- }[key]!;
- }
- }
-}
-
// style
const double elevation0 = 0;
diff --git a/lib/main.dart b/lib/main.dart
index bab09d3..6cb0b15 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -6,7 +6,6 @@ import 'package:vpn_client/pages/main/main_page.dart';
import 'package:vpn_client/pages/settings/setting_page.dart';
import 'package:vpn_client/pages/servers/servers_page.dart';
import 'package:vpn_client/theme_provider.dart';
-import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:vpn_client/vpn_state.dart';
import 'package:vpn_client/localization_service.dart';
// import 'package:vpn_client/pages/apps/apps_page.dart';
@@ -26,13 +25,7 @@ void main() async {
DeviceOrientation.portraitDown,
]);
runApp(
- MultiProvider(
- providers: [
- ChangeNotifierProvider(create: (_) => ThemeProvider()),
- ChangeNotifierProvider(create: (_) => VpnState()),
- ],
- child: const App(),
- ),
+ ChangeNotifierProvider(create: (_) => ThemeProvider(), child: const App()),
);
}
@@ -42,11 +35,7 @@ class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of(context);
-
- // If you want to override it manually, do it here (or leave as null to use system):
- // final Locale? manualLocale = const Locale('ru'); // ← override example
- final Locale? manualLocale = null; // ← use system by default
-
+ final Locale? manualLocale = null;
return MaterialApp(
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
@@ -60,26 +49,40 @@ class App extends StatelessWidget {
locale: manualLocale,
localeResolutionCallback: (locale, _) {
if (locale == null) return const Locale('en');
-
- // Check for exact match
- final supported = ['en', 'ru', 'th', 'zh'];
- if (supported.contains(locale.languageCode)) {
- return Locale(locale.languageCode);
+ for (var supportedLocale in supportedLocales) {
+ if (supportedLocale.languageCode == locale.languageCode &&
+ (supportedLocale.countryCode == null ||
+ supportedLocale.countryCode == locale.countryCode)) {
+ return supportedLocale;
+ }
+ }
+ if (locale.languageCode == 'zh') {
+ return supportedLocales.contains(const Locale('zh'))
+ ? const Locale('zh')
+ : const Locale('en');
}
-
- // Fallback to 'en' if not found
return const Locale('en');
},
-
themeMode: themeProvider.themeMode,
home: const MainScreen(),
+ localizationsDelegates: const [
+ AppLocalizations.delegate,
+ GlobalMaterialLocalizations.delegate,
+ GlobalWidgetsLocalizations.delegate,
+ GlobalCupertinoLocalizations.delegate,
+ ],
+ supportedLocales: const [
+ Locale('en'),
+ Locale('ru'),
+ Locale('th'),
+ Locale('zh'),
+ ],
);
}
}
class MainScreen extends StatefulWidget {
const MainScreen({super.key});
-
@override
State createState() => _MainScreenState();
}
@@ -87,7 +90,6 @@ class MainScreen extends StatefulWidget {
class _MainScreenState extends State {
int _currentIndex = 1;
late List _pages;
-
@override
void initState() {
super.initState();
@@ -99,13 +101,11 @@ class _MainScreenState extends State {
SettingPage(onNavBarTap: _handleNavBarTap),
];
}
-
void _handleNavBarTap(int index) {
setState(() {
_currentIndex = index;
});
}
-
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -121,7 +121,6 @@ class _MainScreenState extends State {
class PlaceholderPage extends StatelessWidget {
final String text;
const PlaceholderPage({super.key, required this.text});
-
@override
Widget build(BuildContext context) {
return Center(child: Text(text));
diff --git a/lib/models/nav_item.dart b/lib/models/nav_item.dart
new file mode 100644
index 0000000..13c2a72
--- /dev/null
+++ b/lib/models/nav_item.dart
@@ -0,0 +1,8 @@
+import 'package:flutter/material.dart';
+
+class NavItem {
+ final Widget inactiveIcon;
+ final Widget activeIcon;
+
+ NavItem({required this.inactiveIcon, required this.activeIcon});
+}
\ No newline at end of file
diff --git a/lib/pages/apps/apps_list.dart b/lib/pages/apps/apps_list.dart
index 9074481..a1b2486 100644
--- a/lib/pages/apps/apps_list.dart
+++ b/lib/pages/apps/apps_list.dart
@@ -1,8 +1,9 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
-import 'package:vpn_client/design/dimensions.dart';
import 'apps_list_item.dart';
+import 'package:vpn_client/l10n/app_localizations.dart';
import 'dart:convert';
+import 'package:vpn_client/core/constants/storage_keys.dart'; // Importar as constantes
class AppsList extends StatefulWidget {
final Function(List