Skip to content

Commit 7114b86

Browse files
author
Stossy11
committed
Add Apple TV support and Fix UI
1 parent b83ab41 commit 7114b86

File tree

4 files changed

+144
-13
lines changed

4 files changed

+144
-13
lines changed

Build.xcconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ MARKETING_VERSION = 1.1.1
55
CURRENT_PROJECT_VERSION = 1
66

77
// Vars to be overwritten by `CodeSigning.xcconfig` if exists
8-
DEVELOPMENT_TEAM = S32Z3HMYVQ
8+
DEVELOPMENT_TEAM = 95J8WZ4TN8
99
ORG_IDENTIFIER = com.stossy11
1010

1111
// Codesigning settings defined optionally, see `CodeSigning.xcconfig.example`

StosVPN.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,13 @@
417417
"$(inherited)",
418418
"@executable_path/Frameworks",
419419
);
420+
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
421+
SUPPORTS_MACCATALYST = NO;
420422
SWIFT_OBJC_BRIDGING_HEADER = "StosVPN/StosVPN-Bridging-Header.h";
421423
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
422424
SWIFT_VERSION = 5.0;
425+
TARGETED_DEVICE_FAMILY = "1,2,3";
426+
TVOS_DEPLOYMENT_TARGET = 17.0;
423427
};
424428
name = Debug;
425429
};
@@ -440,8 +444,12 @@
440444
"$(inherited)",
441445
"@executable_path/Frameworks",
442446
);
447+
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
448+
SUPPORTS_MACCATALYST = NO;
443449
SWIFT_OBJC_BRIDGING_HEADER = "StosVPN/StosVPN-Bridging-Header.h";
444450
SWIFT_VERSION = 5.0;
451+
TARGETED_DEVICE_FAMILY = "1,2,3";
452+
TVOS_DEPLOYMENT_TARGET = 17.0;
445453
};
446454
name = Release;
447455
};
@@ -455,8 +463,12 @@
455463
);
456464
PRODUCT_BUNDLE_IDENTIFIER = "$(TUNNEL_BUNDLE_IDENTIFIER)";
457465
SKIP_INSTALL = YES;
466+
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
467+
SUPPORTS_MACCATALYST = NO;
458468
SWIFT_OBJC_BRIDGING_HEADER = "StosVPN/StosVPN-Bridging-Header.h";
459469
SWIFT_VERSION = 5.0;
470+
TARGETED_DEVICE_FAMILY = "1,2,3";
471+
TVOS_DEPLOYMENT_TARGET = 17.0;
460472
};
461473
name = Debug;
462474
};
@@ -470,8 +482,12 @@
470482
);
471483
PRODUCT_BUNDLE_IDENTIFIER = "$(TUNNEL_BUNDLE_IDENTIFIER)";
472484
SKIP_INSTALL = YES;
485+
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
486+
SUPPORTS_MACCATALYST = NO;
473487
SWIFT_OBJC_BRIDGING_HEADER = "StosVPN/StosVPN-Bridging-Header.h";
474488
SWIFT_VERSION = 5.0;
489+
TARGETED_DEVICE_FAMILY = "1,2,3";
490+
TVOS_DEPLOYMENT_TARGET = 17.0;
475491
};
476492
name = Release;
477493
};

StosVPN/ContentView.swift

Lines changed: 127 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ struct ContentView: View {
533533
}
534534
.padding()
535535
.navigationTitle("StosVPN")
536-
.navigationBarTitleDisplayMode(.inline)
536+
.tvOSNavigationBarTitleDisplayMode(.inline)
537537
.toolbar {
538538
ToolbarItem(placement: .topBarTrailing) {
539539
Button {
@@ -559,6 +559,17 @@ struct ContentView: View {
559559
}
560560
}
561561

562+
extension View {
563+
@ViewBuilder
564+
func tvOSNavigationBarTitleDisplayMode(_ displayMode: NavigationBarItem.TitleDisplayMode) -> some View {
565+
#if os(iOS)
566+
self.navigationBarTitleDisplayMode(displayMode)
567+
#else
568+
self
569+
#endif
570+
}
571+
}
572+
562573

563574
struct StatusIndicatorView: View {
564575
@StateObject private var tunnelManager = TunnelManager.shared
@@ -776,6 +787,7 @@ struct SettingsView: View {
776787
@AppStorage("autoConnect") private var autoConnect = false
777788
@AppStorage("shownTunnelAlert") private var shownTunnelAlert = false
778789
@StateObject private var tunnelManager = TunnelManager.shared
790+
@AppStorage("hasNotCompletedSetup") private var hasNotCompletedSetup = true
779791

780792
@State private var showNetworkWarning = false
781793

@@ -843,7 +855,7 @@ struct SettingsView: View {
843855
)
844856
}
845857
.navigationTitle(Text("settings"))
846-
.navigationBarTitleDisplayMode(.inline)
858+
.tvOSNavigationBarTitleDisplayMode(.inline)
847859
.toolbar {
848860
ToolbarItem(placement: .topBarTrailing) {
849861
Button("done") {
@@ -920,7 +932,7 @@ struct DataCollectionInfoView: View {
920932
.padding()
921933
}
922934
.navigationTitle(Text("data_collection_policy_nav"))
923-
.navigationBarTitleDisplayMode(.inline)
935+
.tvOSNavigationBarTitleDisplayMode(.inline)
924936
}
925937
}
926938

@@ -932,7 +944,7 @@ struct ConnectionLogView: View {
932944
.font(.system(.body, design: .monospaced))
933945
}
934946
.navigationTitle(Text("logs_nav"))
935-
.navigationBarTitleDisplayMode(.inline)
947+
.tvOSNavigationBarTitleDisplayMode(.inline)
936948
}
937949
}
938950

@@ -1023,7 +1035,7 @@ struct HelpView: View {
10231035
}
10241036
}
10251037
.navigationTitle(Text("help_and_support_nav"))
1026-
.navigationBarTitleDisplayMode(.inline)
1038+
.tvOSNavigationBarTitleDisplayMode(.inline)
10271039
}
10281040
}
10291041

@@ -1078,6 +1090,8 @@ struct SetupView: View {
10781090
.fontWeight(.semibold)
10791091
.frame(height: 50)
10801092
.frame(maxWidth: .infinity)
1093+
.background(Color.blue)
1094+
.foregroundColor(.white)
10811095
.cornerRadius(10)
10821096
.padding(.horizontal)
10831097
}
@@ -1091,14 +1105,17 @@ struct SetupView: View {
10911105
.fontWeight(.semibold)
10921106
.frame(height: 50)
10931107
.frame(maxWidth: .infinity)
1108+
.background(Color.blue)
1109+
.foregroundColor(.white)
10941110
.cornerRadius(10)
10951111
.padding(.horizontal)
10961112
}
10971113
.padding(.bottom)
10981114
}
1115+
10991116
}
11001117
.navigationTitle(Text("setup_nav"))
1101-
.navigationBarTitleDisplayMode(.inline)
1118+
.tvOSNavigationBarTitleDisplayMode(.inline)
11021119
.toolbar {
11031120
ToolbarItem(placement: .topBarTrailing) {
11041121
Button("setup_skip") { hasNotCompletedSetup = false; dismiss() }
@@ -1123,25 +1140,25 @@ struct SetupPageView: View {
11231140
let page: SetupPage
11241141

11251142
var body: some View {
1126-
VStack(spacing: 30) {
1143+
VStack(spacing: tvOSSpacing) {
11271144
Image(systemName: page.imageName)
1128-
.font(.system(size: 80))
1145+
.font(.system(size: tvOSImageSize))
11291146
.foregroundColor(.blue)
1130-
.padding(.top, 50)
1147+
.padding(.top, tvOSTopPadding)
11311148

11321149
Text(page.title)
1133-
.font(.title)
1150+
.font(tvOSTitleFont)
11341151
.fontWeight(.bold)
11351152
.multilineTextAlignment(.center)
11361153

11371154
Text(page.description)
1138-
.font(.headline)
1155+
.font(tvOSDescriptionFont)
11391156
.foregroundColor(.secondary)
11401157
.multilineTextAlignment(.center)
11411158

11421159
ScrollView {
11431160
Text(page.details)
1144-
.font(.body)
1161+
.font(tvOSBodyFont)
11451162
.multilineTextAlignment(.leading)
11461163
.padding(.horizontal)
11471164
}
@@ -1150,8 +1167,58 @@ struct SetupPageView: View {
11501167
}
11511168
.padding()
11521169
}
1170+
1171+
// MARK: - Conditional sizes for tvOS
1172+
private var tvOSImageSize: CGFloat {
1173+
#if os(tvOS)
1174+
return 60
1175+
#else
1176+
return 80
1177+
#endif
1178+
}
1179+
1180+
private var tvOSTopPadding: CGFloat {
1181+
#if os(tvOS)
1182+
return 30
1183+
#else
1184+
return 50
1185+
#endif
1186+
}
1187+
1188+
private var tvOSSpacing: CGFloat {
1189+
#if os(tvOS)
1190+
return 20
1191+
#else
1192+
return 30
1193+
#endif
1194+
}
1195+
1196+
private var tvOSTitleFont: Font {
1197+
#if os(tvOS)
1198+
return .headline //.system(size: 35).bold()
1199+
#else
1200+
return .title
1201+
#endif
1202+
}
1203+
1204+
private var tvOSDescriptionFont: Font {
1205+
#if os(tvOS)
1206+
return .subheadline
1207+
#else
1208+
return .headline
1209+
#endif
1210+
}
1211+
1212+
private var tvOSBodyFont: Font {
1213+
#if os(tvOS)
1214+
return .system(size: 18).bold()
1215+
#else
1216+
return .body
1217+
#endif
1218+
}
11531219
}
11541220

1221+
11551222
class LanguageManager: ObservableObject {
11561223
static let shared = LanguageManager()
11571224

@@ -1172,6 +1239,54 @@ class LanguageManager: ObservableObject {
11721239
}
11731240
}
11741241

1242+
#if os(tvOS)
1243+
@ViewBuilder
1244+
func GroupBox<Content: View>(
1245+
label: some View,
1246+
@ViewBuilder content: @escaping () -> Content
1247+
) -> some View {
1248+
#if os(tvOS)
1249+
tvOSGroupBox(label: {
1250+
label
1251+
}, content: content)
1252+
#else
1253+
SwiftUI.GroupBox(label: label, content: content)
1254+
#endif
1255+
}
1256+
1257+
struct tvOSGroupBox<Label: View, Content: View>: View {
1258+
@ViewBuilder let label: () -> Label
1259+
@ViewBuilder let content: () -> Content
1260+
1261+
init(
1262+
@ViewBuilder label: @escaping () -> Label,
1263+
@ViewBuilder content: @escaping () -> Content
1264+
) {
1265+
self.label = label
1266+
self.content = content
1267+
}
1268+
1269+
var body: some View {
1270+
VStack(alignment: .leading, spacing: 8) {
1271+
label()
1272+
.font(.headline)
1273+
1274+
content()
1275+
.padding(.top, 4)
1276+
}
1277+
.padding()
1278+
.background(
1279+
RoundedRectangle(cornerRadius: 12, style: .continuous)
1280+
.fill(.secondary)
1281+
)
1282+
.overlay(
1283+
RoundedRectangle(cornerRadius: 12, style: .continuous)
1284+
.stroke(.separator, lineWidth: 0.5)
1285+
)
1286+
}
1287+
}
1288+
#endif
1289+
11751290
#Preview {
11761291
ContentView()
11771292
}

0 commit comments

Comments
 (0)