Version 1.0.0

1.0.0
This commit is contained in:
se2crid
2025-11-29 18:14:06 +01:00
parent e2ca18bf36
commit 3f56d1f35a
45 changed files with 151 additions and 61 deletions

View File

Before

Width:  |  Height:  |  Size: 773 B

After

Width:  |  Height:  |  Size: 773 B

View File

@@ -0,0 +1,3 @@
<svg width="674" height="674" viewBox="0 0 674 674" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M605 0C643.108 3.92999e-06 674 30.8924 674 69V605C674 643.108 643.108 674 605 674H414V593H439L520 376.5C521.833 372.333 526.4 363 530 359C534.5 354 537 346.5 537 341C537 335.529 532.547 311.258 470 294.27V149C470 140.714 467.198 133.084 462.494 127H382.506C377.802 133.084 375 140.714 375 149V275.253C350.381 273.121 325.624 273.092 301 275.167V149C301 140.714 298.198 133.084 293.494 127H213.506C208.802 133.084 206 140.714 206 149V294L204.522 294.399C142.43 311.381 138 335.543 138 341C138 346.5 140.5 354 145 359C148.6 363 153.167 372.333 155 376.5L237 593H262V674H69C30.8924 674 0 643.108 0 605V69C3.9305e-06 30.8924 30.8924 0 69 0H605Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 773 B

View File

@@ -1,8 +1,8 @@
{
"fill" : {
"linear-gradient" : [
"display-p3:0.72718,1.00000,0.56150,1.00000",
"display-p3:0.23889,0.54053,0.96826,1.00000"
"display-p3:0.72549,1.00000,0.56078,1.00000",
"display-p3:0.23922,0.54118,0.96863,1.00000"
],
"orientation" : {
"start" : {
@@ -17,20 +17,19 @@
},
"groups" : [
{
"hidden-specializations" : [
{
"value" : true
},
{
"appearance" : "tinted",
"value" : false
}
],
"layers" : [
{
"blend-mode" : "normal",
"hidden" : false,
"image-name" : "StosPlug.svg",
"name" : "StosPlug",
"opacity" : 0.5,
"position" : {
"scale" : 1,
"translation-in-points" : [
0,
0
]
}
"image-name" : "StosPlug 3.svg",
"name" : "StosPlug 3"
}
],
"shadow" : {
@@ -46,6 +45,45 @@
}
}
]
},
{
"hidden-specializations" : [
{
"value" : false
},
{
"appearance" : "tinted",
"value" : true
}
],
"layers" : [
{
"fill-specializations" : [
{
"value" : {
"solid" : "display-p3:0.94916,0.94916,0.94916,0.50000"
}
},
{
"appearance" : "tinted",
"value" : {
"solid" : "display-p3:1.00000,1.00000,1.00000,0.50000"
}
}
],
"hidden" : false,
"image-name" : "StosPlug 2.svg",
"name" : "StosPlug"
}
],
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
}
],
"supported-platforms" : {

View File

@@ -420,7 +420,7 @@
DEVELOPMENT_TEAM = 42Q7QX86GV;
ENABLE_PREVIEWS = YES;
INFOPLIST_KEY_CFBundleDisplayName = LocalDevVPN;
INFOPLIST_KEY_NSHumanReadableCopyright = Stossy11;
INFOPLIST_KEY_NSHumanReadableCopyright = "Coxson Engineering";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -430,14 +430,15 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jkcoxson.LocalDevVPN;
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "LocalDevVPN/LocalDevVPN-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,3";
TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 17.0;
};
name = Debug;
@@ -455,7 +456,7 @@
DEVELOPMENT_TEAM = 42Q7QX86GV;
ENABLE_PREVIEWS = YES;
INFOPLIST_KEY_CFBundleDisplayName = LocalDevVPN;
INFOPLIST_KEY_NSHumanReadableCopyright = Stossy11;
INFOPLIST_KEY_NSHumanReadableCopyright = "Coxson Engineering";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -465,13 +466,14 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jkcoxson.LocalDevVPN;
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "LocalDevVPN/LocalDevVPN-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,3";
TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 17.0;
};
name = Release;

View File

@@ -19,7 +19,7 @@
BlueprintIdentifier = "4EB3C76D2D96715400C1B22C"
BuildableName = "TunnelProv.appex"
BlueprintName = "TunnelProv"
ReferencedContainer = "container:StosVPN.xcodeproj">
ReferencedContainer = "container:LocalDevVPN.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
@@ -33,7 +33,7 @@
BlueprintIdentifier = "4EB3C7572D96631A00C1B22C"
BuildableName = "LocalDevVPN.app"
BlueprintName = "LocalDevVPN"
ReferencedContainer = "container:StosVPN.xcodeproj">
ReferencedContainer = "container:LocalDevVPN.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -64,7 +64,7 @@
BlueprintIdentifier = "4EB3C7572D96631A00C1B22C"
BuildableName = "LocalDevVPN.app"
BlueprintName = "LocalDevVPN"
ReferencedContainer = "container:StosVPN.xcodeproj">
ReferencedContainer = "container:LocalDevVPN.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
@@ -74,7 +74,6 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
@@ -83,7 +82,7 @@
BlueprintIdentifier = "4EB3C7572D96631A00C1B22C"
BuildableName = "LocalDevVPN.app"
BlueprintName = "LocalDevVPN"
ReferencedContainer = "container:StosVPN.xcodeproj">
ReferencedContainer = "container:LocalDevVPN.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>

View File

@@ -4,7 +4,7 @@
<dict>
<key>SchemeUserState</key>
<dict>
<key>StosVPN.xcscheme_^#shared#^_</key>
<key>LocalDevVPN.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>

View File

@@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "StosVPN-icon.jpg",
"filename" : "image-5.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

@@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "1280x768 copy 3.jpeg",
"filename" : "image-2.png",
"idiom" : "tv"
}
],

View File

@@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "1280x768.png",
"filename" : "image.png",
"idiom" : "tv"
}
],

View File

@@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "1280x768 copy 3.jpeg",
"filename" : "image-2.png",
"idiom" : "tv"
}
],

View File

@@ -1,12 +1,12 @@
{
"images" : [
{
"filename" : "Content.png",
"filename" : "image-2 1.png",
"idiom" : "tv",
"scale" : "1x"
},
{
"filename" : "Content@2x.png",
"filename" : "image-2.png",
"idiom" : "tv",
"scale" : "2x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -1,12 +1,12 @@
{
"images" : [
{
"filename" : "cool.png",
"filename" : "image.png",
"idiom" : "tv",
"scale" : "1x"
},
{
"filename" : "cool 1.png",
"filename" : "image 1.png",
"idiom" : "tv",
"scale" : "2x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,12 +1,12 @@
{
"images" : [
{
"filename" : "Content.png",
"filename" : "image-2.png",
"idiom" : "tv",
"scale" : "1x"
},
{
"filename" : "Content@2x.png",
"filename" : "image-2 1.png",
"idiom" : "tv",
"scale" : "2x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -1,12 +1,12 @@
{
"images" : [
{
"filename" : "1280x768 copy 4.jpeg",
"filename" : "image-3.png",
"idiom" : "tv",
"scale" : "1x"
},
{
"filename" : "1280x768 copy 4 2.jpeg",
"filename" : "image-3 1.png",
"idiom" : "tv",
"scale" : "2x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

View File

@@ -1,12 +1,12 @@
{
"images" : [
{
"filename" : "1280x768 copy 4.jpeg",
"filename" : "image-4.png",
"idiom" : "tv",
"scale" : "1x"
},
{
"filename" : "1280x768 copy 5.jpeg",
"filename" : "image-4 1.png",
"idiom" : "tv",
"scale" : "2x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

View File

@@ -655,8 +655,9 @@ struct ContentView: View {
Button {
showSettings = true
} label: {
Image(systemName: "gear")
.foregroundColor(.primary)
Image(systemName: "gearshape.fill")
.font(.system(size: 20, weight: .medium))
.foregroundColor(.secondary)
}
}
}
@@ -727,6 +728,7 @@ struct StatusIndicatorView: View {
.font(.subheadline)
.foregroundColor(tunnelManager.tunnelStatus == .connected ? .green : .secondary)
}
.padding(.horizontal)
}
private func updateAnimation() {
@@ -757,16 +759,39 @@ struct ConnectionButton: View {
var body: some View {
Button(action: action) {
HStack {
Text(buttonText)
.font(.headline)
.fontWeight(.semibold)
if #available(iOS 19.0, *) {
HStack(spacing: 8) {
if tunnelManager.tunnelStatus == .connecting || tunnelManager.tunnelStatus == .disconnecting {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
}
if tunnelManager.tunnelStatus == .connecting || tunnelManager.tunnelStatus == .disconnecting {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
.padding(.leading, 5)
Text(buttonText)
.font(.system(size: 17, weight: .semibold))
}
.frame(maxWidth: .infinity)
.frame(height: 56)
.glassEffect(.regular.interactive().tint(tunnelManager.tunnelStatus != .connected ? .red : .green), in: RoundedRectangle(cornerRadius: 14, style: .continuous))
.foregroundColor(.white)
.shadow(color: tunnelManager.tunnelStatus.color.opacity(0.3), radius: 12, x: 0, y: 6)
} else {
HStack(spacing: 8) {
if tunnelManager.tunnelStatus == .connecting || tunnelManager.tunnelStatus == .disconnecting {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
}
Text(buttonText)
.font(.system(size: 17, weight: .semibold))
}
.frame(maxWidth: .infinity)
.frame(height: 56)
.background(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.fill(buttonBackground)
)
.foregroundColor(.white)
.shadow(color: tunnelManager.tunnelStatus.color.opacity(0.3), radius: 12, x: 0, y: 6)
}
.frame(width: 200, height: 50)
.background(buttonBackground)
@@ -775,6 +800,7 @@ struct ConnectionButton: View {
.shadow(color: Color.black.opacity(0.15), radius: 10, x: 0, y: 5)
}
.disabled(tunnelManager.tunnelStatus == .connecting || tunnelManager.tunnelStatus == .disconnecting)
.padding(.horizontal, 20)
}
private var buttonText: String {
@@ -862,15 +888,20 @@ struct ConnectionStatsView: View {
if hours > 0 {
return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
} else {
return String(format: "%02d:%02d", minutes, seconds)
return LinearGradient(
colors: [Color.blue, Color.blue.opacity(0.8)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
}
}
struct StatItemView: View {
let title: LocalizedStringKey
let value: String
struct InfoCard: View {
let icon: String
let title: String
let subtitle: String
let accentColor: Color
var body: some View {
VStack(alignment: .leading, spacing: 10) {
@@ -879,15 +910,24 @@ struct StatItemView: View {
.foregroundColor(.blue)
Text(title)
.font(.caption)
.font(.system(size: 15, weight: .semibold))
.foregroundColor(.primary)
Text(subtitle)
.font(.system(size: 13, weight: .regular))
.foregroundColor(.secondary)
.lineLimit(2)
}
Text(value)
.font(.system(size: 16, weight: .semibold))
.foregroundColor(.primary)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(16)
.background(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.fill(Color(UIColor.secondarySystemGroupedBackground))
)
}
}
@@ -1151,10 +1191,18 @@ struct HelpView: View {
}
}
Section(header: Text("app_info_header")) {
HStack {
Image(systemName: "exclamationmark.shield")
Text("requires_ios")
if let minVersion = Bundle.main.infoDictionary?["MinimumOSVersion"] as? String {
let message = String(
format: NSLocalizedString("requires_ios", comment: ""),
minVersion
)
HStack {
Image(systemName: "exclamationmark.shield")
Text(message)
}
}
HStack {
Image(systemName: "lock.shield")
Text("uses_network_extension")