taler-ios

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

commit 670083e3c71390f9c446e9b26d564d14839fed00
parent d265f565bbf727a7868fc68946269d550c3e7d58
Author: Marc Stibane <marc@taler.net>
Date:   Tue, 11 Aug 2026 10:25:54 +0200

Get more demo cash, add Exchange simplified

Diffstat:
MTalerWallet1/Views/Main/WalletEmptyView.swift | 4++--
MTalerWallet1/Views/Settings/Exchange/ExchangeListView.swift | 48+++++++++++++++++++++++++++++++++++++++++++-----
MTalerWallet1/Views/Settings/Exchange/ExchangeSectionView.swift | 21++++++++++++++++++++-
3 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/TalerWallet1/Views/Main/WalletEmptyView.swift b/TalerWallet1/Views/Main/WalletEmptyView.swift @@ -236,9 +236,9 @@ struct WalletEmptyView: View { withDrawStarted = true // don't run twice Task { // runs on MainActor let amount = Amount(currency: DEMOCURRENCY, cent: 2500) - symLog.log("Withdraw KUDOS") + symLog.log("Withdraw 25 KUDOS") try? await model.loadTestKudos(0, amount: amount) - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + DispatchQueue.main.asyncAfter(deadline: .now() + 5) { withDrawStarted = false } } diff --git a/TalerWallet1/Views/Settings/Exchange/ExchangeListView.swift b/TalerWallet1/Views/Settings/Exchange/ExchangeListView.swift @@ -19,6 +19,7 @@ func addExchange(_ exchange: String, model: WalletModel) -> Void { if UIAccessibility.isVoiceOverRunning { UIAccessibility.post(notification: .announcement, argument: "added: \(exchange)") } + Controller.shared.hapticNotification(.success) NotificationCenter.default.post(name: .ExchangeAdded, object: nil, userInfo: nil) NotificationCenter.default.post(name: .BalanceChange, object: nil, userInfo: nil) // TODO: ExchangeAdded should suffice } @@ -39,8 +40,25 @@ struct ExchangeListView: View { @AppStorage("developerMode") var developerMode: Bool = false #endif - @State var showAlert: Bool = false - @State var newExchange: String = TESTEXCHANGE + @State private var showAlert: Bool = false + @State private var newExchange: String = EXCHANGE + DEMO // without HTTPS + + func checkExchanges() { + var hasNoDEMO = true + var hasNoTEST = true + for balance in controller.balances { + if let baseUrl = balance.scopeInfo.url { + if baseUrl.contains(EXCHANGE + DEMO) { + hasNoDEMO = false + } else if baseUrl.contains(EXCHANGE + TEST) { + hasNoTEST = false + } + } + } + newExchange = hasNoDEMO ? EXCHANGE + DEMO + : hasNoTEST && developerMode ? EXCHANGE + TEST + : EMPTYSTRING + } var body: some View { let a11yLabelStr = String(localized: "Add payment service", comment: "a11y for the + button") @@ -50,7 +68,9 @@ struct ExchangeListView: View { let addTitleStr = String(localized: "Add payment service", comment: "title of the addExchange alert") let addButtonStr = String(localized: "Add", comment: "button in the addExchange alert") let enterURL = String(localized: "Enter the URL") - let listView = ExchangeListCommonV(symLog: symLog, stack: stack.push(), developerMode: developerMode) + let listView = ExchangeListCommonV(symLog: symLog, stack: stack.push(), + newExchange: $newExchange, + checkExchanges: checkExchanges) .navigationTitle(TITLE_EXCHANGES) .navigationBarItems(trailing: plusButton) .task { @@ -58,6 +78,8 @@ struct ExchangeListView: View { newExchange = newUrl.trimmedString showAlert = true url = nil + } else { + checkExchanges() } } if #available(iOS 16.4, *) { @@ -67,6 +89,9 @@ struct ExchangeListView: View { // .textFieldStyle(.roundedBorder) Yikes: when adding style the alert will stop showing the textfield! Don't do this. Button(addButtonStr) { addExchange(newExchange, model: model) + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + checkExchanges() + } } Button("Cancel", role: .cancel) { } } message: { @@ -88,12 +113,18 @@ struct ExchangeListView: View { struct ExchangeListCommonV: View { let symLog: SymLogV? let stack: CallStack - let developerMode: Bool + @Binding var newExchange: String + let checkExchanges: () -> Void @EnvironmentObject private var controller: Controller @EnvironmentObject private var model: WalletModel @AppStorage("minimalistic") var minimalistic: Bool = false @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic +#if DEBUG + @AppStorage("developerMode") var developerMode: Bool = true +#else + @AppStorage("developerMode") var developerMode: Bool = false +#endif var body: some View { #if PRINT_CHANGES @@ -122,7 +153,11 @@ struct ExchangeListCommonV: View { ExchangeSectionView(stack: stack.push(), balance: balance, thousand: index * MAXEXCHANGES, // unique ID - developerMode: developerMode) + developerMode: developerMode) { + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + checkExchanges() + } + } } #if DEBUG if developerMode { @@ -168,6 +203,9 @@ struct ExchangeListCommonV: View { symLog?.log("refreshing") // await reloadExchanges() NotificationCenter.default.post(name: .BalanceChange, object: nil, userInfo: nil) + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + checkExchanges() + } } .onAppear() { DebugViewC.shared.setViewID(VIEW_PAYMENT_SERVICES, stack: stack.push()) diff --git a/TalerWallet1/Views/Settings/Exchange/ExchangeSectionView.swift b/TalerWallet1/Views/Settings/Exchange/ExchangeSectionView.swift @@ -17,6 +17,7 @@ struct ExchangeSectionView: View { let balance: Balance let thousand: Int // index of balance times 1000 (MAXEXCHANGES per currency) let developerMode: Bool + let deleteTask: () -> Void @EnvironmentObject private var model: WalletModel @EnvironmentObject private var controller: Controller @@ -27,6 +28,7 @@ struct ExchangeSectionView: View { @State private var exchanges: [Exchange] = [] @State private var reloadTransactions: Int = 0 @State private var currencyInfo: CurrencyInfo = CurrencyInfo.zero(UNKNOWN) + @State private var withDrawStarted = false @State private var didDelete: Bool = false @State private var disabled: Bool = false @State private var showAlert: Bool = false @@ -62,6 +64,7 @@ struct ExchangeSectionView: View { NotificationCenter.default.post(name: .ExchangeDeleted, object: nil, userInfo: nil) NotificationCenter.default.post(name: .BalanceChange, object: nil, userInfo: nil) demoHints = true + deleteTask() } else { purge = true showAlert = true @@ -115,10 +118,26 @@ struct ExchangeSectionView: View { description: String("Remove fee and gros from details")) } if DEMOCURRENCY == currency { + let title = String(localized: "LinkTitle_Test_Money2", defaultValue: "Get more demo cash") + Button(title) { + withDrawStarted = true // don't run twice + Task { // runs on MainActor + let amount = Amount(currency: DEMOCURRENCY, cent: 1000) + symLog.log("Withdraw 10 KUDOS") + try? await model.loadTestKudos(0, amount: amount) + DispatchQueue.main.asyncAfter(deadline: .now() + 5) { + withDrawStarted = false + } + } + } + .buttonStyle(TalerButtonStyle(type: .bordered, narrow: false, disabled: withDrawStarted, aligned: .center)) + .disabled(withDrawStarted) + SettingsToggle(name: String(localized: "Demo Hints"), value: $demoHints, id1: "demoHints", description: String(localized: "Show hints for demo money")) - .listRowSeparator(.hidden) + .listRowSeparator(.hidden) + let bankingHint = String(localized: "Since the demo bank supports the Taler integration, you can start a withdrawal directly on the") let linkTitle = String(localized: "LinkTitle_DEMOBANK", defaultValue: "Demo Bank Website") if demoHints {