Improve TV settings screen (#943)

- Show detail side by side rather than navigate
- Fix scrolling in purchased view
This commit is contained in:
Davide 2024-11-26 15:55:04 +01:00 committed by GitHub
parent e49e8881b3
commit 80d40c3161
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 87 additions and 46 deletions

View File

@ -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)

View File

@ -28,11 +28,5 @@ import Foundation
enum AppCoordinatorRoute: Hashable {
case appLog
case credits
case donate
case purchased
case tunnelLog
}

View File

@ -38,12 +38,11 @@ struct DonateViewModifier: ViewModifier {
}
}
}
.padding(.top, 150)
}
}
private extension DonateViewModifier {
var columns: [GridItem] {
[GridItem(.adaptive(minimum: 500))]
[GridItem(.adaptive(minimum: 300))]
}
}

View File

@ -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 {

View File

@ -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()
}
}

View File

@ -67,6 +67,15 @@ extension View {
)
}
}
public func scrollableOnTV() -> some View {
// focusable()
Button {
//
} label: {
self
}
}
}
extension ViewModifier {

View File

@ -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)

View File

@ -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 {