feat: add package to backport to iOS 14, fix other portions to aid backport

- transferred project to use xcconfig files
 - bumped version to 1.1.1
 - added helper to get correct version in settings
 - fixed language picker
 - fixed connection status text
 - fixed various code formatting things
This commit is contained in:
ny
2025-07-05 01:56:34 -04:00
parent 118bbf0b50
commit d1f30b9817
9 changed files with 161 additions and 84 deletions

BIN
.DS_Store vendored

Binary file not shown.

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
CodeSigning.xcconfig
*.ipa
/build

23
Build.xcconfig Normal file
View File

@@ -0,0 +1,23 @@
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974
MARKETING_VERSION = 1.1.1
CURRENT_PROJECT_VERSION = 1
// Vars to be overwritten by `CodeSigning.xcconfig` if exists
DEVELOPMENT_TEAM = S32Z3HMYVQ
ORG_IDENTIFIER = com.stossy11
// Codesigning settings defined optionally, see `CodeSigning.xcconfig.example`
#include? "CodeSigning.xcconfig"
ORG_PREFIX = $(ORG_IDENTIFIER)
PRODUCT_BUNDLE_IDENTIFIER = $(ORG_PREFIX).StosVPN
TUNNEL_NAME = TunnelProv
TUNNEL_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER).$(TUNNEL_NAME)
// Mute warnings about duplicate classes in AuthKit and AuthUIKit
DEBUG_DUPLICATE_CLASSES = NO

View File

@@ -0,0 +1,34 @@
// Your Team ID.
// If you have a paid Apple Developer account, you can find your Team ID at
// https://developer.apple.com/account/#/membership
DEVELOPMENT_TEAM = 95J8WZ4TN8
// Prefix of unique bundle IDs registered to you in Apple Developer Portal.
// You need to register:
// - com.myuniquename.StosVPN
ORG_IDENTIFIER = com.stossy11
// Name of the iOS development signing certificate, you probably do not need
// to change this.
CODE_SIGN_IDENTITY_IOS = Apple Development
// Name of the iOS development signing certificate, you probably do not need
// to change this.
CODE_SIGN_IDENTITY_TVOS = Apple Development
// The values below are specific to macOS development. If you do not define
// these keys, the build will default to ad-hoc signing. You will need to
// follow `Documentation/MacDevelopment.md` to disable library verification and
// remove unsupported entitlements.
// Name of the macOS development signing certificate. Comment out this line to
// use ad-hoc signing.
CODE_SIGN_IDENTITY_MAC = Apple Development
// Create a Mac provisioning profile for com.myuniquename.UTM with the
// Hypervisor entitlements and get its UUID. If you do not have access to these
// entitlements, comment out the line and delete the following entitlements
// - com.apple.vm.device-access
// from the following file
// - Provenance/macOS.entitlements
PROVISIONING_PROFILE_SPECIFIER_MAC = 00000000-1111-2222-3333-444444444444

View File

@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
0E6351BE2E18EABA002AF750 /* NavigationBackport in Frameworks */ = {isa = PBXBuildFile; productRef = 0E6351BD2E18EABA002AF750 /* NavigationBackport */; };
4EB3C7712D96715400C1B22C /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EB3C7702D96715400C1B22C /* NetworkExtension.framework */; };
4EB3C7792D96715400C1B22C /* TunnelProv.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 4EB3C76E2D96715400C1B22C /* TunnelProv.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
@@ -36,6 +37,9 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0E6351B62E18DF53002AF750 /* Build.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Build.xcconfig; sourceTree = "<group>"; };
0E6351B72E18DF53002AF750 /* CodeSigning.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = CodeSigning.xcconfig; sourceTree = "<group>"; };
0E6351B82E18DF53002AF750 /* CodeSigning.xcconfig.sample */ = {isa = PBXFileReference; lastKnownFileType = text; path = CodeSigning.xcconfig.sample; sourceTree = "<group>"; };
4EB3C7582D96631A00C1B22C /* StosVPN.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StosVPN.app; sourceTree = BUILT_PRODUCTS_DIR; };
4EB3C76E2D96715400C1B22C /* TunnelProv.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TunnelProv.appex; sourceTree = BUILT_PRODUCTS_DIR; };
4EB3C7702D96715400C1B22C /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
@@ -68,6 +72,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0E6351BE2E18EABA002AF750 /* NavigationBackport in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -85,6 +90,9 @@
4EB3C74F2D96631A00C1B22C = {
isa = PBXGroup;
children = (
0E6351B62E18DF53002AF750 /* Build.xcconfig */,
0E6351B72E18DF53002AF750 /* CodeSigning.xcconfig */,
0E6351B82E18DF53002AF750 /* CodeSigning.xcconfig.sample */,
4EB3C75A2D96631A00C1B22C /* StosVPN */,
4EB3C7722D96715400C1B22C /* TunnelProv */,
4EB3C76F2D96715400C1B22C /* Frameworks */,
@@ -131,6 +139,7 @@
);
name = StosVPN;
packageProductDependencies = (
0E6351BD2E18EABA002AF750 /* NavigationBackport */,
);
productName = StosVPN;
productReference = 4EB3C7582D96631A00C1B22C /* StosVPN.app */;
@@ -185,9 +194,14 @@
knownRegions = (
en,
Base,
es,
it,
);
mainGroup = 4EB3C74F2D96631A00C1B22C;
minimizedProjectReferenceProxies = 1;
packageReferences = (
0E6351BC2E18EABA002AF750 /* XCRemoteSwiftPackageReference "NavigationBackport" */,
);
productRefGroup = 4EB3C7592D96631A00C1B22C /* Products */;
projectDirPath = "";
projectRoot = "";
@@ -243,6 +257,7 @@
/* Begin XCBuildConfiguration section */
4EB3C7642D96631B00C1B22C /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0E6351B62E18DF53002AF750 /* Build.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
@@ -274,6 +289,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "$(TARGET_NAME)/$(TARGET_NAME).entitlements";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -293,19 +309,31 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.2;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "$(TARGET_NAME)/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "$(TARGET_NAME)";
INFOPLIST_KEY_NSHumanReadableCopyright = Stossy11;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 15.0;
WATCHOS_DEPLOYMENT_TARGET = 8.0;
XROS_DEPLOYMENT_TARGET = 1.0;
};
name = Debug;
};
4EB3C7652D96631B00C1B22C /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0E6351B62E18DF53002AF750 /* Build.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
@@ -337,6 +365,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "$(TARGET_NAME)/$(TARGET_NAME).entitlements";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
@@ -350,13 +379,24 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.2;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "$(TARGET_NAME)/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "$(TARGET_NAME)";
INFOPLIST_KEY_NSHumanReadableCopyright = Stossy11;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_EMIT_LOC_STRINGS = YES;
TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 15.0;
VALIDATE_PRODUCT = YES;
WATCHOS_DEPLOYMENT_TARGET = 8.0;
XROS_DEPLOYMENT_TARGET = 1.0;
};
name = Release;
};
@@ -366,32 +406,20 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = StosVPN/StosVPN.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"StosVPN/Preview Content\"";
DEVELOPMENT_TEAM = 95J8WZ4TN8;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = StosVPN/Info.plist;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.StosVPN;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "StosVPN/StosVPN-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -401,87 +429,49 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = StosVPN/StosVPN.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"StosVPN/Preview Content\"";
DEVELOPMENT_TEAM = 95J8WZ4TN8;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = StosVPN/Info.plist;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.StosVPN;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "StosVPN/StosVPN-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
4EB3C77C2D96715400C1B22C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = TunnelProv/TunnelProv.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 95J8WZ4TN8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = TunnelProv/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = TunnelProv;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.StosVPN.TunnelProv;
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = "$(TUNNEL_BUNDLE_IDENTIFIER)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "StosVPN/StosVPN-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
4EB3C77D2D96715400C1B22C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = TunnelProv/TunnelProv.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 95J8WZ4TN8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = TunnelProv/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = TunnelProv;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.StosVPN.TunnelProv;
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = "$(TUNNEL_BUNDLE_IDENTIFIER)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "StosVPN/StosVPN-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
@@ -516,6 +506,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
0E6351BC2E18EABA002AF750 /* XCRemoteSwiftPackageReference "NavigationBackport" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/johnpatrickmorgan/NavigationBackport";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.11.5;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
0E6351BD2E18EABA002AF750 /* NavigationBackport */ = {
isa = XCSwiftPackageProductDependency;
package = 0E6351BC2E18EABA002AF750 /* XCRemoteSwiftPackageReference "NavigationBackport" */;
productName = NavigationBackport;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 4EB3C7502D96631A00C1B22C /* Project object */;
}

View File

@@ -9,6 +9,12 @@ import SwiftUI
import Foundation
import NetworkExtension
import NavigationBackport
extension Bundle {
var shortVersion: String { object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "0.0.0" }
var tunnelBundleID: String { bundleIdentifier!.appending(".TunnelProv") }
}
// MARK: - Logging Utility
class VPNLogger: ObservableObject {
@@ -50,12 +56,6 @@ class TunnelManager: ObservableObject {
UserDefaults.standard.string(forKey: "TunnelSubnetMask") ?? "255.255.255.0"
}
private var tunnelBundleId: String {
Bundle.main.bundleIdentifier!.appending(".TunnelProv")
}
import SwiftUI
enum TunnelStatus {
case disconnected
case connecting
@@ -123,7 +123,7 @@ class TunnelManager: ObservableObject {
// Look specifically for StosVPN manager
for manager in managers {
if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol,
proto.providerBundleIdentifier == self.tunnelBundleId {
proto.providerBundleIdentifier == Bundle.main.tunnelBundleID {
self.vpnManager = manager
self.updateTunnelStatus(from: manager.connection.status)
VPNLogger.shared.log("Loaded existing StosVPN tunnel configuration")
@@ -173,7 +173,7 @@ class TunnelManager: ObservableObject {
self.tunnelStatus = .error
}
VPNLogger.shared.log("StosVPN status updated: \(self.tunnelStatus.rawValue)")
VPNLogger.shared.log("StosVPN status updated: \(self.tunnelStatus)")
}
}
@@ -182,7 +182,7 @@ class TunnelManager: ObservableObject {
manager.localizedDescription = "StosVPN"
let proto = NETunnelProviderProtocol()
proto.providerBundleIdentifier = self.tunnelBundleId
proto.providerBundleIdentifier = Bundle.main.tunnelBundleID
proto.serverAddress = NSLocalizedString("server_address_name", comment: "")
manager.protocolConfiguration = proto
@@ -248,7 +248,7 @@ class TunnelManager: ObservableObject {
guard let self = self else { return }
if let activeManager = activeManager,
(activeManager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier != self.tunnelBundleId {
(activeManager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier != Bundle.main.tunnelBundleID {
VPNLogger.shared.log("Disconnecting existing VPN connection before starting StosVPN")
// Set a flag to start StosVPN after disconnection
@@ -359,7 +359,7 @@ struct ContentView: View {
@AppStorage("hasNotCompletedSetup") private var hasNotCompletedSetup = true
var body: some View {
NavigationStack {
NBNavigationStack {
VStack(spacing: 30) {
Spacer()
@@ -430,7 +430,7 @@ struct StatusIndicatorView: View {
.font(.system(size: 50))
.foregroundColor(tunnelManager.tunnelStatus.color)
Text(tunnelManager.tunnelStatus.rawValue)
Text(tunnelManager.tunnelStatus.localizedTitle)
.font(.headline)
.foregroundColor(.primary)
}
@@ -614,7 +614,7 @@ struct StatItemView: View {
// MARK: - Updated SettingsView
struct SettingsView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.presentationMode) var presentationMode
@AppStorage("selectedLanguage") private var selectedLanguage = Locale.current.languageCode ?? "en"
@AppStorage("TunnelDeviceIP") private var deviceIP = "10.7.0.0"
@AppStorage("TunnelFakeIP") private var fakeIP = "10.7.0.1"
@@ -622,7 +622,7 @@ struct SettingsView: View {
@AppStorage("autoConnect") private var autoConnect = false
var body: some View {
NavigationStack {
NBNavigationStack {
List {
Section(header: Text("connection_settings")) {
Toggle("auto_connect_on_launch", isOn: $autoConnect)
@@ -670,7 +670,7 @@ struct SettingsView: View {
HStack {
Text("app_version")
Spacer()
Text("1.1.0")
Text(Bundle.main.shortVersion)
.foregroundColor(.secondary)
}
NavigationLink(destination: HelpView()) {
@@ -680,13 +680,13 @@ struct SettingsView: View {
Section(header: Text("language")) {
Picker("language", selection: $selectedLanguage) {
Text("English").tag(0)
Text("Spanish").tag(1)
Text("Italian").tag(2)
Text("English").tag("en")
Text("Spanish").tag("es")
Text("Italian").tag("it")
}
.onChange(of: selectedLanguage) { newValue in
let languageCode = ["en", "es", "it"][newValue]
LanguageManager().updateLanguage(to: languageCode)
let languageCode = newValue
LanguageManager.shared.updateLanguage(to: languageCode)
}
}
}
@@ -701,6 +701,10 @@ struct SettingsView: View {
}
}
}
private func dismiss() {
presentationMode.wrappedValue.dismiss()
}
}
@@ -779,7 +783,7 @@ struct HelpView: View {
VStack(alignment: .leading, spacing: 15) {
Text("faq_q2_a1")
.padding(.bottom, 10)
.fontWeight(.medium)
.font(.headline)
Text("faq_q2_point1")
Text("faq_q2_point2")
Text("faq_q2_point3")
@@ -794,7 +798,7 @@ struct HelpView: View {
Text("faq_q3_a1")
.padding(.bottom, 10)
Text("faq_troubleshoot_header")
.fontWeight(.medium)
.font(.headline)
Text("faq_troubleshoot1")
Text("faq_troubleshoot2")
Text("faq_troubleshoot3")
@@ -805,7 +809,7 @@ struct HelpView: View {
NavigationLink("faq_q4") {
VStack(alignment: .leading, spacing: 15) {
Text("faq_q4_intro")
.fontWeight(.medium)
.font(.headline)
.padding(.bottom, 10)
Text("faq_q4_case1")
Text("faq_q4_case2")
@@ -823,7 +827,7 @@ struct HelpView: View {
Text("biz_q1_a1")
.padding(.bottom, 10)
Text("biz_key_points_header")
.fontWeight(.medium)
.font(.headline)
Text("biz_point1")
Text("biz_point2")
Text("biz_point3")
@@ -850,7 +854,7 @@ struct HelpView: View {
}
struct SetupView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.presentationMode) var presentationMode
@AppStorage("hasNotCompletedSetup") private var hasNotCompletedSetup = true
@State private var currentPage = 0
let pages = [
@@ -880,7 +884,7 @@ struct SetupView: View {
)
]
var body: some View {
NavigationStack {
NBNavigationStack {
VStack {
TabView(selection: $currentPage) {
ForEach(0..<pages.count, id: \.self) { index in
@@ -928,6 +932,10 @@ struct SetupView: View {
}
}
}
private func dismiss() {
presentationMode.wrappedValue.dismiss()
}
}
struct SetupPage {
@@ -971,6 +979,8 @@ struct SetupPageView: View {
}
class LanguageManager: ObservableObject {
static let shared = LanguageManager()
@Published var currentLanguage: String = Locale.current.languageCode ?? "en"
private let supportedLanguages = ["en", "es", "it"]

View File

@@ -96,7 +96,7 @@
"biz_point4" = "• All features are free for all users";
"biz_point5" = "• The app is developed and maintained as an open utility for the iOS community";
"app_info_header" = "App Information";
"requires_ios" = "Requires iOS 16.0 or later";
"requires_ios" = "Requires iOS 14.0 or later";
"uses_network_extension" = "Uses Apple Network Extension APIs";
"help_and_support_nav" = "Help & Support";
"setup_welcome_title" = "Welcome to StosVPN";

View File

@@ -96,7 +96,7 @@
"biz_point4" = "• Todas las funciones son gratuitas para todos los usuarios";
"biz_point5" = "• La app es desarrollada y mantenida como una utilidad abierta para la comunidad de iOS";
"app_info_header" = "Información de la App";
"requires_ios" = "Requiere iOS 16.0 o superior";
"requires_ios" = "Requiere iOS 14.0 o superior";
"uses_network_extension" = "Usa la API de Extensión de Red de Apple";
"help_and_support_nav" = "Ayuda & Soporte";
"setup_welcome_title" = "Bienvenido a StosVPN";

View File

@@ -96,7 +96,7 @@
"biz_point4" = "• Tutte le funzionalità sono gratuite per tutti gli utenti";
"biz_point5" = "• L'app è sviluppata e mantenuta come utility open per la comunità iOS";
"app_info_header" = "Informazioni App";
"requires_ios" = "Richiede iOS 16.0 o superiore";
"requires_ios" = "Richiede iOS 14.0 o superiore";
"uses_network_extension" = "Usa le Network Extension API di Apple";
"help_and_support_nav" = "Guida & Supporto";
"setup_welcome_title" = "Benvenuto in StosVPN";