taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit 061835647cd835734dfa227468b0ac0ec00fe71e
parent a9e40d4e1b2cf3d84c5db60b6541c2bb2bff9f48
Author: Marc Stibane <marc@taler.net>
Date:   Sun,  5 Jul 2026 21:02:49 +0200

preferredColorScheme

Diffstat:
MTalerWallet1/Controllers/TalerWallet1App.swift | 2+-
MTalerWallet1/Helper/WalletColors.swift | 7++-----
MTalerWallet1/Views/Balances/BalancesListView.swift | 10+++++++++-
MTalerWallet1/Views/Balances/DiscountPasses.swift | 10++++++++--
MTalerWallet1/Views/Main/WalletEmptyView.swift | 23++++++++++++++++++++---
MTalerWallet1/Views/Settings/MoreSettingsView.swift | 6+++---
MTalerWallet1/Views/Settings/SettingsItem.swift | 65+++++++++++++++++++++++++++++++++++++++++++++++++++--------------
MTalerWallet1/Views/Transactions/TransactionSummaryList.swift | 8+++++---
MTalerWallet1/Views/Transactions/TransactionsListView.swift | 14+++++++++++---
9 files changed, 110 insertions(+), 35 deletions(-)

diff --git a/TalerWallet1/Controllers/TalerWallet1App.swift b/TalerWallet1/Controllers/TalerWallet1App.swift @@ -103,7 +103,7 @@ struct TalerWallet1App: App { } var body: some Scene { - let colorScheme = preferredColorScheme < 0 ? ColorScheme.dark + let colorScheme = preferredColorScheme > 1 ? ColorScheme.dark : preferredColorScheme > 0 ? ColorScheme.light : nil // use the current scheme let mainView = MainView(logger: logger, stack: CallStack("App")) diff --git a/TalerWallet1/Helper/WalletColors.swift b/TalerWallet1/Helper/WalletColors.swift @@ -10,10 +10,7 @@ import SwiftUI fileprivate let grouped = true struct FullBackground: View { - @Environment(\.colorScheme) private var colorScheme - @AppStorage("liquidBack") var liquidBack: Bool = false - - var isDark: Bool { colorScheme == .dark } + @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0 @available(iOS 17.0, *) @MainActor @@ -39,7 +36,7 @@ struct FullBackground: View { } var body: some View { - if isDark, liquidBack, #available(iOS 17.0, *) { + if preferredColorScheme == 3, #available(iOS 17.0, *) { liquidView } else { backgroundView diff --git a/TalerWallet1/Views/Balances/BalancesListView.swift b/TalerWallet1/Views/Balances/BalancesListView.swift @@ -22,6 +22,7 @@ struct BalancesListView: View { @EnvironmentObject private var controller: Controller @Environment(\.accessibilityVoiceOverEnabled) private var voiceOverEnabled @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic + @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0 @AppStorage("oimEuro") var oimEuro: Bool = false @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING) // Update currency when used @@ -107,7 +108,7 @@ struct BalancesListView: View { /// However, the user can select another balance (with the picker) in each action /// In OIM mode, the user selects a balance 'here' (in OIMView) when tapping on a savings box (representing the balance) - balancesList() + let list = balancesList() .onChange(of: controller.oimModeActive) { oimModeActive in if !oimModeActive { print("🚩BalancesListView.onChange(of: oimModeActive) reset selectedBalance") @@ -116,6 +117,13 @@ struct BalancesListView: View { // } } } + ZStack { + if preferredColorScheme == 3, #available(iOS 17.0, *) { + list.scrollContentBackground(.hidden) + } else { + list + } + } .overlay { if #available(iOS 16.4, *) { if controller.oimModeActive { #if OIM diff --git a/TalerWallet1/Views/Balances/DiscountPasses.swift b/TalerWallet1/Views/Balances/DiscountPasses.swift @@ -132,6 +132,7 @@ struct DiscountsPassesList: View { @EnvironmentObject private var model: WalletModel @EnvironmentObject private var controller: Controller @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic + @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0 @State private var activeExpired: Int = 0 func delete(_ tokenID: String) async { @@ -195,15 +196,20 @@ struct DiscountsPassesList: View { } .listStyle(myListStyle.style).anyView .background(FullBackground()) + .navigationTitle(navTitle) .refreshable { controller.hapticNotification(.success) await refresh() } - list - .navigationTitle(navTitle) .task { await refresh() } + if #available(iOS 17.0, *) { + list + .scrollContentBackground(preferredColorScheme == 3 ? .hidden : .visible) + } else { + list + } } } // MARK: - diff --git a/TalerWallet1/Views/Main/WalletEmptyView.swift b/TalerWallet1/Views/Main/WalletEmptyView.swift @@ -23,6 +23,7 @@ struct ProdSectionView: View { #else @AppStorage("developerMode") var developerMode: Bool = false #endif + @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0 @State private var selectedCurrency: Int = 0 @State private var showDropdown = true @@ -36,7 +37,7 @@ struct ProdSectionView: View { var body: some View { let defaultExchanges = controller.defaultExchanges let count = defaultExchanges.count - Section { + let section = Section { let chevron = Image(systemName: CHEVRON_UP) // 􀆇 if isEmpty { Text("Welcome to Taler Wallet!") @@ -108,6 +109,12 @@ struct ProdSectionView: View { } .listRowSeparator(.hidden) // .listSectionSpacing(.compact) iOS 17 + + if preferredColorScheme == 3, #available(iOS 17.0, *) { + section.listRowBackground(Color.white.opacity(0.1)) + } else { + section + } } } @@ -187,6 +194,7 @@ struct WalletEmptyView: View { @EnvironmentObject private var controller: Controller @EnvironmentObject private var model: WalletModel @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic + @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0 @State private var withDrawStarted = false @State private var urlToOpen: URL? = nil @@ -206,7 +214,7 @@ struct WalletEmptyView: View { // .talerFont(.body) // } #endif - Section { + let section = Section { // Text("Demo") // .talerFont(.headline) // Text("Get digital cash to experience how easy you can pay online, and send money to friends & family.") @@ -234,12 +242,21 @@ struct WalletEmptyView: View { // .talerFont(.title3) // .foregroundColor(WalletColors().secondary(colorScheme, colorSchemeContrast)) } + if preferredColorScheme == 3, #available(iOS 17.0, *) { + section.listRowBackground(Color.white.opacity(0.1)) + } else { + section + } } .listStyle(myListStyle.style).anyView .talerFont(.title2) .background(FullBackground()) ZStack { - list + if preferredColorScheme == 3, #available(iOS 17.0, *) { + list.scrollContentBackground(.hidden) + } else { + list + } if withDrawStarted { RotatingTaler(size: 150, progress: true, once: false, rotationEnabled: $withDrawStarted) } diff --git a/TalerWallet1/Views/Settings/MoreSettingsView.swift b/TalerWallet1/Views/Settings/MoreSettingsView.swift @@ -60,9 +60,9 @@ struct MoreSettingsView: View { SettingsToggle(name: showQRstring, value: $showQRauto16, id1: "showQRautomatic", description: showQRhint) } - SettingsTriState(name: String(localized: "Preferred Appearance"), value: $preferredColorScheme, - id1: "colorScheme", - description: String(localized: "Individual preference")) + SettingsQuadState(name: String(localized: "Preferred Appearance"), + value: $preferredColorScheme, + id1: "colorScheme") if controller.hapticCapability.supportsHaptics { SettingsToggle(name: String(localized: "Haptics"), value: $useHaptics, id1: "haptics", diff --git a/TalerWallet1/Views/Settings/SettingsItem.swift b/TalerWallet1/Views/Settings/SettingsItem.swift @@ -221,20 +221,14 @@ struct SettingsTriState: View { var description: String? var action: (_ value: Int) -> Void = {value in } - func imageName1(_ value: Int) -> (String, String) { + func imageName(_ value: Int) -> (String, String) { return (value == 0) ? ("eye.slash", "Off") : (value == 1) ? ("eye", "Type only") : ("eye.fill", "Type and JSON") } - func imageName2(_ value: Int) -> (String, String) { - return (value == 0) ? ("iphone", "System") // or apple.logo - : (value == 1) ? (LIGHT_OFF, "light") // 􀛭 - : (LIGHT_ON, "dark") // 􀛮 - } var body: some View { - let observe = "observe" == id1 - let image = observe ? imageName1(value) : imageName2(value) + let image = imageName(value) VStack { HStack { @@ -247,15 +241,11 @@ struct SettingsTriState: View { if value > 0 { value = -1 action(value) - if observe { - Controller.shared.playSound(1) - } + Controller.shared.playSound(1) } else { value = value + 1 action(value) - if observe { - Controller.shared.playSound(value) - } + Controller.shared.playSound(value) } } label: { Image(systemName: image.0) @@ -273,6 +263,53 @@ struct SettingsTriState: View { } } // MARK: - +struct SettingsQuadState: View { + var name: String + @Binding var value: Int + let id1: String? + var action: (_ value: Int) -> Void = {value in } + + func imageName(_ value: Int) -> (String, String) { + return (value == 0) ? ("iphone", "System") // or apple.logo + : (value == 1) ? (LIGHT_OFF, "Light") // 􀛭 + : (value == 2) ? (LIGHT_ON, "Dark") // 􀛮 + : ("swirl.circle.righthalf.filled", "Liquid dark") // 􁹢 + } + + var body: some View { + let image = imageName(value) + + VStack { + HStack { + Text(name) + .talerFont(.title2) + Spacer() + Text(verbatim: " ") + .talerFont(.largeTitle) + Button { + var maxValue = if #available(iOS 17.0, *) { 3 } else { 2 } + if value >= maxValue { + value = 0 + action(value) + } else { + value = value + 1 + action(value) + } + } label: { + Image(systemName: image.0) + .talerFont(.largeTitle) + } + } + + SettingsDescription(id1: id1, description: image.1) + } + .accessibilityElement(children: .combine) + .accessibilityLabel(name) + .accessibility(value: Text(image.1)) + .padding([.bottom], 4) + } +} +// MARK: - #if DEBUG struct SettingsItemPreview : View { @State var developerMode: Bool = false diff --git a/TalerWallet1/Views/Transactions/TransactionSummaryList.swift b/TalerWallet1/Views/Transactions/TransactionSummaryList.swift @@ -227,6 +227,7 @@ struct TransactionSummaryList: View { @Environment(\.dismiss) var dismiss // call dismiss() to pop back @AppStorage("minimalistic") var minimalistic: Bool = false @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic + @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0 #if DEBUG @AppStorage("developerMode") var developerMode: Bool = true #else @@ -475,6 +476,7 @@ struct TransactionSummaryList: View { if withActions { abortFailDelete(common) } }.id(viewId) // change viewId to enforce a draw update .listStyle(myListStyle.style).anyView + .background(FullBackground()) .navigationBarBackButtonHidden(hasDone) .interactiveDismissDisabled(hasDone) // can only use "Done" button to dismiss .safeAreaInset(edge: .bottom) { @@ -530,12 +532,12 @@ struct TransactionSummaryList: View { .navigationTitle(navTitle ?? navTitle2) if #available(iOS 17.0, *) { - list.toolbarTitleDisplayMode(.inlineLarge) + list + .scrollContentBackground(preferredColorScheme == 3 ? .hidden : .visible) + .toolbarTitleDisplayMode(.inlineLarge) } else { list } - - } else { Color.clear .frame(maxWidth: .infinity, maxHeight: .infinity) diff --git a/TalerWallet1/Views/Transactions/TransactionsListView.swift b/TalerWallet1/Views/Transactions/TransactionsListView.swift @@ -31,6 +31,7 @@ struct TransactionsListView: View { @Environment(\.colorScheme) private var colorScheme @Environment(\.colorSchemeContrast) private var colorSchemeContrast @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic + @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0 @State private var viewId = UUID() @StateObject private var cash: OIMcash @Namespace var namespace @@ -71,8 +72,7 @@ struct TransactionsListView: View { await reloadAllAction(stack.push()) } } else { -// Group { - ScrollViewReader { scrollProxy in + let list = ScrollViewReader { scrollProxy in List { let header = scope.url?.trimURL ?? scope.currency TransactionsArraySection(symLog: symLog, @@ -85,6 +85,7 @@ struct TransactionsListView: View { } .id(viewId) .listStyle(myListStyle.style).anyView + .background(FullBackground()) .refreshable { controller.hapticNotification(.success) symLog.log("refreshing") @@ -118,7 +119,14 @@ struct TransactionsListView: View { print("🚩,32TransactionsListView.onAppear() set selectedBalance to", balance.scopeInfo.currency) selectedBalance = balance // set this balance (fix) for send/request/deposit/withdraw } -// } + + ZStack { + if preferredColorScheme == 3, #available(iOS 17.0, *) { + list.scrollContentBackground(.hidden) + } else { + list + } + } #if OIM .overlay { if #available(iOS 16.4, *) { if controller.oimModeActive {