taler-ios

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

commit 56100061b880d42db7c5cb33cfaefb85210f2870
parent 4527d4a9d89a56226e4318c47fa264b117c3e2f6
Author: Marc Stibane <marc@taler.net>
Date:   Sat, 18 Apr 2026 07:55:30 +0200

haveProdBalance

Diffstat:
MTalerWallet1/Controllers/Controller.swift | 7+++++--
MTalerWallet1/Model/Model+Balances.swift | 13++++++++-----
MTalerWallet1/Model/Model+Exchange.swift | 16+++++++++++++---
3 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/TalerWallet1/Controllers/Controller.swift b/TalerWallet1/Controllers/Controller.swift @@ -105,6 +105,7 @@ class Controller: ObservableObject { public static let shared = Controller() private let symLog = SymLogC() + @Published var haveProdBalance: Bool = false @Published var balances: [Balance] = [] @Published var scannedURLs: [ScannedURL] = [] @@ -272,7 +273,8 @@ class Controller: ObservableObject { @MainActor @discardableResult func loadBalances(_ stack: CallStack,_ model: WalletModel) async -> Int? { - if let reloaded = try? await model.getBalances(stack.push()) { + if let response = try? await model.getBalances(stack.push()) { + let reloaded = response.balances if reloaded != balances { for balance in reloaded { let scope = balance.scopeInfo @@ -283,6 +285,7 @@ class Controller: ObservableObject { } else { self.logger.log("••Same balances, no redraw") } + haveProdBalance = response.haveProdBalance return reloaded.count } return nil @@ -431,7 +434,7 @@ class Controller: ObservableObject { #if !TALER_WALLET if developerMode { try? await model.setConfig(setTesting: true) - try? await model.devExperimentT(talerUri: "taler://dev-experiment/default-exchange-demo?val=1") +// try? await model.devExperimentT(talerUri: "taler://dev-experiment/default-exchange-demo?val=1") try? await model.devExperimentT(talerUri: "taler://dev-experiment/demo-shortcuts?val=KUDOS:4,KUDOS:8,KUDOS:16,KUDOS:32") try? await model.setConfig(setTesting: false) } diff --git a/TalerWallet1/Model/Model+Balances.swift b/TalerWallet1/Model/Model+Balances.swift @@ -68,6 +68,11 @@ extension Balance { } } // MARK: - +struct BalancesResponse: Decodable, Hashable, Sendable { + let haveProdBalance: Bool // if false, show DefaultExchange hint + let balances: [Balance] +} + /// A request to get the balances held in the wallet. fileprivate struct Balances: WalletBackendFormattedRequest { func operation() -> String { "getBalances" } @@ -75,16 +80,14 @@ fileprivate struct Balances: WalletBackendFormattedRequest { struct Args: Encodable {} // no arguments needed - struct Response: Decodable, Sendable { // list of balances - var balances: [Balance] - } + typealias Response = BalancesResponse } // MARK: - extension WalletModel { /// fetch Balances from Wallet-Core. No networking involved - nonisolated func getBalances(_ stack: CallStack, viewHandles: Bool = false) async throws -> [Balance] { + nonisolated func getBalances(_ stack: CallStack, viewHandles: Bool = false) async throws -> BalancesResponse { let request = Balances() let response = try await sendRequest(request, viewHandles: viewHandles) - return response.balances + return response } } diff --git a/TalerWallet1/Model/Model+Exchange.swift b/TalerWallet1/Model/Model+Exchange.swift @@ -15,6 +15,11 @@ struct OperationErrorInfo: Codable, Hashable { var error: TalerErrorDetail } +enum ExchangeType: String, Codable { + case demo + case prod +} + enum ExchangeEntryStatus: String, Codable { case preset case ephemeral @@ -141,12 +146,14 @@ extension DefaultExchange: Identifiable { /// A request to list exchanges names for a currency fileprivate struct ListExchanges: WalletBackendFormattedRequest { func operation() -> String { "listExchanges" } - func args() -> Args { Args(filterByScope: scope, filterByExchangeEntryStatus: filterByStatus) } + func args() -> Args { Args(filterByScope: scope, filterByType: filterByType, filterByExchangeEntryStatus: filterByStatus) } var scope: ScopeInfo? + var filterByType: ExchangeType? var filterByStatus: ExchangeEntryStatus? struct Args: Encodable { var filterByScope: ScopeInfo? + var filterByType: ExchangeType? var filterByExchangeEntryStatus: ExchangeEntryStatus? } struct Response: Decodable { // list of known exchanges @@ -268,10 +275,13 @@ fileprivate struct RmvGlobalCurrency: WalletBackendFormattedRequest { // MARK: - extension WalletModel { /// ask wallet-core for its list of known exchanges - nonisolated func listExchanges(scope: ScopeInfo?, filterByStatus: ExchangeEntryStatus? = nil, viewHandles: Bool = false) + nonisolated func listExchanges(scope: ScopeInfo?, filterByType: ExchangeType? = nil, + filterByStatus: ExchangeEntryStatus? = nil, viewHandles: Bool = false) async -> [Exchange] { // M for MainActor do { - let request = ListExchanges(scope: scope, filterByStatus: filterByStatus) // .used, .preset + let request = ListExchanges(scope: scope, + filterByType: filterByType, // .demo, .prod + filterByStatus: filterByStatus) // .used, .preset let response = try await sendRequest(request, viewHandles: viewHandles) return response.exchanges } catch {