diff --git a/Passepartout/Library/Sources/AppUITV/Views/App/AppCoordinator.swift b/Passepartout/Library/Sources/AppUITV/Views/App/AppCoordinator.swift index 95f875e0..3ee2644f 100644 --- a/Passepartout/Library/Sources/AppUITV/Views/App/AppCoordinator.swift +++ b/Passepartout/Library/Sources/AppUITV/Views/App/AppCoordinator.swift @@ -108,19 +108,6 @@ private extension AppCoordinator { DebugLogContentView(lines: $0) } - case .credits: - CreditsView() - .resized(width: 0.5) - .themeList() - - case .donate: - DonateView(modifier: DonateViewModifier()) - - case .purchased: - PurchasedView() - .resized(width: 0.5) - .themeList() - case .tunnelLog: DebugLogView(withTunnel: tunnel, parameters: Constants.shared.log) { DebugLogContentView(lines: $0) diff --git a/Passepartout/Library/Sources/AppUITV/Views/App/AppCoordinatorRoute.swift b/Passepartout/Library/Sources/AppUITV/Views/App/AppCoordinatorRoute.swift index 98d2d2ff..e2f9772c 100644 --- a/Passepartout/Library/Sources/AppUITV/Views/App/AppCoordinatorRoute.swift +++ b/Passepartout/Library/Sources/AppUITV/Views/App/AppCoordinatorRoute.swift @@ -28,11 +28,5 @@ import Foundation enum AppCoordinatorRoute: Hashable { case appLog - case credits - - case donate - - case purchased - case tunnelLog } diff --git a/Passepartout/Library/Sources/AppUITV/Views/Settings/DonateViewModifier.swift b/Passepartout/Library/Sources/AppUITV/Views/Settings/DonateViewModifier.swift index 53df9f32..18c25ae1 100644 --- a/Passepartout/Library/Sources/AppUITV/Views/Settings/DonateViewModifier.swift +++ b/Passepartout/Library/Sources/AppUITV/Views/Settings/DonateViewModifier.swift @@ -38,12 +38,11 @@ struct DonateViewModifier: ViewModifier { } } } - .padding(.top, 150) } } private extension DonateViewModifier { var columns: [GridItem] { - [GridItem(.adaptive(minimum: 500))] + [GridItem(.adaptive(minimum: 300))] } } diff --git a/Passepartout/Library/Sources/AppUITV/Views/Settings/SettingsView.swift b/Passepartout/Library/Sources/AppUITV/Views/Settings/SettingsView.swift index 3b4a95e1..3f0bff54 100644 --- a/Passepartout/Library/Sources/AppUITV/Views/Settings/SettingsView.swift +++ b/Passepartout/Library/Sources/AppUITV/Views/Settings/SettingsView.swift @@ -29,17 +29,51 @@ import PassepartoutKit import SwiftUI import UILibrary +enum Detail { + case credits + + case donate + + case other + + case purchased +} + struct SettingsView: View { let tunnel: ExtendedTunnel + @Namespace + private var masterScope + + @Namespace + private var detailScope + + @FocusState + private var focus: Detail? + + @State + private var detail: Detail? + var body: some View { - listView - .resized(width: 0.5) + HStack { + masterView + .frame(maxWidth: .infinity) + .focused($focus, equals: .other) + + DetailView(detail: detail) + .frame(maxWidth: .infinity) + } + .onChange(of: focus) { + guard focus != nil else { + return + } + detail = focus + } } } private extension SettingsView { - var listView: some View { + var masterView: some View { List { creditsSection diagnosticsSection @@ -50,8 +84,10 @@ private extension SettingsView { var creditsSection: some View { Group { - NavigationLink(Strings.Views.About.Credits.title, value: AppCoordinatorRoute.credits) - NavigationLink(Strings.Views.Donate.title, value: AppCoordinatorRoute.donate) + Button(Strings.Views.About.Credits.title) {} + .focused($focus, equals: .credits) + Button(Strings.Views.Donate.title) {} + .focused($focus, equals: .donate) } .themeSection(header: Strings.Unlocalized.appName) } @@ -67,7 +103,8 @@ private extension SettingsView { var aboutSection: some View { Group { - NavigationLink(Strings.Views.Purchased.title, value: AppCoordinatorRoute.purchased) + Button(Strings.Views.Purchased.title) {} + .focused($focus, equals: .purchased) Text(Strings.Global.Nouns.version) .themeTrailingValue(BundleConfiguration.mainVersionString) } @@ -75,6 +112,28 @@ private extension SettingsView { } } +private struct DetailView: View { + let detail: Detail? + + var body: some View { + switch detail { + case .credits: + CreditsView() + .themeList() + + case .donate: + DonateView(modifier: DonateViewModifier()) + + case .purchased: + PurchasedView() + .themeList() + + default: + VStack {} + } + } +} + // MARK: - #Preview { diff --git a/Passepartout/Library/Sources/CommonUtils/Views/GenericCreditsView.swift b/Passepartout/Library/Sources/CommonUtils/Views/GenericCreditsView.swift index 47d8b022..e5dc4678 100644 --- a/Passepartout/Library/Sources/CommonUtils/Views/GenericCreditsView.swift +++ b/Passepartout/Library/Sources/CommonUtils/Views/GenericCreditsView.swift @@ -178,15 +178,7 @@ private extension GenericCreditsView { var translationsSection: some View { Section { ForEach(sortedLanguages, id: \.self) { code in -#if os(tvOS) - Button { - // - } label: { - translationLabel(code) - } -#else translationLabel(code) -#endif } } header: { translationsHeader.map(Text.init) @@ -215,6 +207,7 @@ private extension GenericCreditsView { } } } + .scrollableOnTV() } } diff --git a/Passepartout/Library/Sources/CommonUtils/Views/View+Extensions.swift b/Passepartout/Library/Sources/CommonUtils/Views/View+Extensions.swift index 782623fa..e5d2764c 100644 --- a/Passepartout/Library/Sources/CommonUtils/Views/View+Extensions.swift +++ b/Passepartout/Library/Sources/CommonUtils/Views/View+Extensions.swift @@ -67,6 +67,15 @@ extension View { ) } } + + public func scrollableOnTV() -> some View { +// focusable() + Button { + // + } label: { + self + } + } } extension ViewModifier { diff --git a/Passepartout/Library/Sources/UILibrary/Views/About/PurchasedView.swift b/Passepartout/Library/Sources/UILibrary/Views/About/PurchasedView.swift index 75cad67f..ca53a9c9 100644 --- a/Passepartout/Library/Sources/UILibrary/Views/About/PurchasedView.swift +++ b/Passepartout/Library/Sources/UILibrary/Views/About/PurchasedView.swift @@ -77,19 +77,23 @@ private extension PurchasedView { Group { Text(Strings.Views.Purchased.Rows.buildNumber) .themeTrailingValue(build.description) + .scrollableOnTV() } .themeSection(header: Strings.Views.Purchased.Sections.Download.header) } } var productsSection: some View { - Group { - ForEach(products, id: \.productIdentifier) { - Text($0.localizedTitle) - .themeTrailingValue($0.localizedPrice) + products.nilIfEmpty.map { products in + Group { + ForEach(products, id: \.productIdentifier) { + Text($0.localizedTitle) + .themeTrailingValue($0.localizedPrice) + .scrollableOnTV() + } } + .themeSection(header: Strings.Views.Purchased.Sections.Products.header) } - .themeSection(header: Strings.Views.Purchased.Sections.Products.header) } var featuresSection: some View { @@ -101,6 +105,7 @@ private extension PurchasedView { ThemeImage(.marked) .opaque(iapManager.isEligible(for: feature)) } + .scrollableOnTV() } } .themeSection(header: Strings.Views.Purchased.Sections.Features.header) diff --git a/Passepartout/Library/Sources/UILibrary/Views/Paywall/PaywallView.swift b/Passepartout/Library/Sources/UILibrary/Views/Paywall/PaywallView.swift index 6cb693a7..df4735e2 100644 --- a/Passepartout/Library/Sources/UILibrary/Views/Paywall/PaywallView.swift +++ b/Passepartout/Library/Sources/UILibrary/Views/Paywall/PaywallView.swift @@ -155,13 +155,8 @@ private extension PaywallView { } func featureView(for feature: AppFeature) -> some View { -#if os(tvOS) - Button(feature.localizedDescription) { - // - } -#else Text(feature.localizedDescription) -#endif + .scrollableOnTV() } var restoreView: some View {