@@ -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
563574struct 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+
11551222class 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