Version 1.0.0
1.0.0
|
Before Width: | Height: | Size: 773 B After Width: | Height: | Size: 773 B |
3
AppIcon.icon/Assets/StosPlug 3.svg
Normal 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 |
@@ -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" : {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "StosVPN-icon.jpg",
|
||||
"filename" : "image-5.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
|
||||
|
Before Width: | Height: | Size: 42 KiB |
BIN
LocalDevVPN/Assets.xcassets/AppIcon.appiconset/image-5.png
Normal file
|
After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "1280x768 copy 3.jpeg",
|
||||
"filename" : "image-2.png",
|
||||
"idiom" : "tv"
|
||||
}
|
||||
],
|
||||
|
||||
|
After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 156 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "1280x768.png",
|
||||
"filename" : "image.png",
|
||||
"idiom" : "tv"
|
||||
}
|
||||
],
|
||||
|
||||
|
After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "1280x768 copy 3.jpeg",
|
||||
"filename" : "image-2.png",
|
||||
"idiom" : "tv"
|
||||
}
|
||||
],
|
||||
|
||||
|
After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -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"
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
@@ -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"
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
@@ -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"
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 198 KiB |
|
Before Width: | Height: | Size: 73 KiB |
@@ -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"
|
||||
}
|
||||
|
||||
BIN
LocalDevVPN/Assets.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/image-3 1.png
vendored
Normal file
|
After Width: | Height: | Size: 645 KiB |
BIN
LocalDevVPN/Assets.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/image-3.png
vendored
Normal file
|
After Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 160 KiB |
@@ -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"
|
||||
}
|
||||
|
||||
BIN
LocalDevVPN/Assets.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/image-4 1.png
vendored
Normal file
|
After Width: | Height: | Size: 639 KiB |
BIN
LocalDevVPN/Assets.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/image-4.png
vendored
Normal file
|
After Width: | Height: | Size: 277 KiB |
@@ -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())
|
||||
.padding(.leading, 5)
|
||||
.progressViewStyle(CircularProgressViewStyle(tint: .white))
|
||||
}
|
||||
|
||||
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")) {
|
||||
if let minVersion = Bundle.main.infoDictionary?["MinimumOSVersion"] as? String {
|
||||
let message = String(
|
||||
format: NSLocalizedString("requires_ios", comment: ""),
|
||||
minVersion
|
||||
)
|
||||
HStack {
|
||||
Image(systemName: "exclamationmark.shield")
|
||||
Text("requires_ios")
|
||||
Text(message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HStack {
|
||||
Image(systemName: "lock.shield")
|
||||
Text("uses_network_extension")
|
||||
|
||||