taler-ios

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

commit c429eb06c6e67557834af4102461542b90c8218f
parent 689e76e903ab94171f8b1e2a7479e06c703ecfe5
Author: Marc Stibane <marc@taler.net>
Date:   Mon,  9 Dec 2024 18:21:36 +0100

bank accounts

Diffstat:
MTalerWallet1/Model/Model+Deposit.swift | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
MTalerWallet1/Views/Actions/Banking/DepositIbanV.swift | 6+++---
MTalerWallet1/Views/Settings/Bank/BankEditView.swift | 12++++++------
MTalerWallet1/Views/Settings/Bank/BankListView.swift | 12++++--------
MTalerWallet1/Views/Settings/Bank/BankSectionView.swift | 31++++++++++++++++++-------------
5 files changed, 94 insertions(+), 60 deletions(-)

diff --git a/TalerWallet1/Model/Model+Deposit.swift b/TalerWallet1/Model/Model+Deposit.swift @@ -165,19 +165,20 @@ extension WalletModel { } } // MARK: - -struct KnownBankAccountsInfo: Decodable, Hashable { +struct BankAccountsInfo: Decodable, Hashable { + var bankAccountId: String var paytoUri: String var kycCompleted: Bool - var currencies: [String] - var alias: String? + var currencies: [String]? + var label: String? } -struct KnownBankAccounts: Decodable, Hashable { - var accounts: [KnownBankAccountsInfo] +struct BankAccounts: Decodable, Hashable { + var accounts: [BankAccountsInfo] } -/// A request to list know bank accounts. -fileprivate struct ListKnownBankAccounts: WalletBackendFormattedRequest { - typealias Response = KnownBankAccounts - func operation() -> String { "listKnownBankAccounts" } +/// A request to list known bank accounts. +fileprivate struct ListBankAccounts: WalletBackendFormattedRequest { + typealias Response = BankAccounts + func operation() -> String { "listBankAccounts" } func args() -> Args { Args(currency: currency) } var currency: String? struct Args: Encodable { @@ -186,53 +187,85 @@ fileprivate struct ListKnownBankAccounts: WalletBackendFormattedRequest { } extension WalletModel { /// ask for known accounts. No networking - nonisolated func listKnownBankAccounts(_ currency: String? = nil, viewHandles: Bool = false) - async throws -> [KnownBankAccountsInfo] { - let request = ListKnownBankAccounts(currency: currency) + nonisolated func listBankAccounts(_ currency: String? = nil, viewHandles: Bool = false) + async throws -> [BankAccountsInfo] { + let request = ListBankAccounts(currency: currency) let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response.accounts } } +/// A request to get one bank account. +fileprivate struct GetBankAccountById: WalletBackendFormattedRequest { + typealias Response = BankAccountsInfo + func operation() -> String { "getBankAccountById" } + func args() -> Args { Args(bankAccountId: bankAccountId) } + var bankAccountId: String + struct Args: Encodable { + var bankAccountId: String + } +} +extension WalletModel { + /// ask for a specific account. No networking + nonisolated func getBankAccountById(_ bankAccountId: String, viewHandles: Bool = false) + async throws -> BankAccountsInfo { + let request = GetBankAccountById(bankAccountId: bankAccountId) + let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) + return response + } +} + +struct AddBankAccountResponse: Decodable, Hashable { + var bankAccountId: String // Identifier of the added bank account +} /// A request to add a known bank account. -fileprivate struct AddKnownBankAccount: WalletBackendFormattedRequest { - struct Response: Decodable {} // no result - getting no error back means success - func operation() -> String { "addKnownBankAccount" } - func args() -> Args { Args(paytoUri: uri, alias: alias, replacePaytoUri: replaceUri) } +fileprivate struct AddBankAccount: WalletBackendFormattedRequest { + typealias Response = AddBankAccountResponse + func operation() -> String { "addBankAccount" } + func args() -> Args { Args(paytoUri: uri, + label: label, + currencies: currencies, + replacePaytoUri: replaceUri) } var uri: String - var alias: String + var label: String + var currencies: [String]? var replaceUri: String? struct Args: Encodable { var paytoUri: String // bank account that should be added - var alias: String // Human-readable alias / label + var label: String // Human-readable label var currencies: [String]? // currencies supported by the bank (if known) var replacePaytoUri: String? // account that this new account should replace } } extension WalletModel { /// add (or update) a known account. No networking - nonisolated func addKnownBankAccount(_ uri: String, alias: String, replaceUri: String? = nil, viewHandles: Bool = false) - async throws { - let request = AddKnownBankAccount(uri: uri, alias: alias, replaceUri: replaceUri) - _ = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) + nonisolated func addBankAccount(_ uri: String, + label: String, + currencies: [String]? = nil, + replaceUri: String? = nil, + viewHandles: Bool = false) + async throws -> String { + let request = AddBankAccount(uri: uri, label: label, currencies: currencies, replaceUri: replaceUri) + let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) + return response.bankAccountId } } /// A request to forget a known bank account. -fileprivate struct ForgetKnownBankAccount: WalletBackendFormattedRequest { +fileprivate struct ForgetBankAccount: WalletBackendFormattedRequest { struct Response: Decodable {} // no result - getting no error back means success - func operation() -> String { "forgetKnownBankAccount" } - func args() -> Args { Args(paytoUri: uri) } - var uri: String + func operation() -> String { "forgetBankAccount" } + func args() -> Args { Args(bankAccountId: accountId) } + var accountId: String struct Args: Encodable { - var paytoUri: String // bank account that should be forgotten + var bankAccountId: String // bank account that should be forgotten } } extension WalletModel { /// add a known account. No networking - nonisolated func forgetKnownBankAccount(_ uri: String, viewHandles: Bool = false) - async throws { - let request = ForgetKnownBankAccount(uri: uri) + nonisolated func forgetBankAccount(_ accountId: String, viewHandles: Bool = false) + async throws { + let request = ForgetBankAccount(accountId: accountId) _ = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) } } diff --git a/TalerWallet1/Views/Actions/Banking/DepositIbanV.swift b/TalerWallet1/Views/Actions/Banking/DepositIbanV.swift @@ -34,7 +34,7 @@ struct DepositIbanV: View { @State private var currencySymbol: String = UNKNOWN @State private var amountAvailable = Amount.zero(currency: EMPTYSTRING) // Update currency when used @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING) // Update currency when used - @State private var bankAccounts: [KnownBankAccountsInfo] = [] + @State private var bankAccounts: [BankAccountsInfo] = [] private var subjectTitle: String { @@ -45,7 +45,7 @@ struct DepositIbanV: View { @MainActor private func viewDidLoad() async { - if let accounts = try? await model.listKnownBankAccounts() { + if let accounts = try? await model.listBankAccounts() { withAnimation { bankAccounts = accounts } } } @@ -78,7 +78,7 @@ struct DepositIbanV: View { let payURL = URL(string: account.paytoUri) let iban = payURL?.iban let xTaler = payURL?.xTaler - let alias = account.alias + let alias = account.label let kyc = account.kycCompleted ? String(localized: "verified") : String(localized: "not yet verified") diff --git a/TalerWallet1/Views/Settings/Bank/BankEditView.swift b/TalerWallet1/Views/Settings/Bank/BankEditView.swift @@ -14,7 +14,7 @@ import SymLog struct BankEditView: View { private let symLog = SymLogV(0) let stack: CallStack - let account: KnownBankAccountsInfo + let account: BankAccountsInfo @EnvironmentObject private var model: WalletModel @EnvironmentObject private var controller: Controller @@ -33,13 +33,13 @@ struct BankEditView: View { @State private var accountHolder: String = EMPTYSTRING @State private var iban: String = EMPTYSTRING @State private var xTaler: String = EMPTYSTRING - @State private var alias: String = EMPTYSTRING + @State private var label: String = EMPTYSTRING @State private var paytoType: PaytoType = .iban @State private var selected = 0 @FocusState private var focus:FocusedField? enum FocusedField: Hashable { - case accountHolder, iban, xTaler, alias + case accountHolder, iban, xTaler, label } // @MainActor @@ -57,7 +57,7 @@ struct BankEditView: View { let payURL = URL(string: account.paytoUri) iban = payURL?.iban ?? EMPTYSTRING xTaler = payURL?.xTaler ?? EMPTYSTRING - alias = account.alias ?? EMPTYSTRING + label = account.label ?? EMPTYSTRING if let queryParameters = payURL?.queryParameters { let name = if let rcv = queryParameters["receiver-name"] { rcv.replacingOccurrences(of: "+", with: SPACE) @@ -169,9 +169,9 @@ struct BankEditView: View { .talerFont(.title3) .accessibilityHidden(true) } - TextField(minimalistic ? note : EMPTYSTRING, text: $alias) + TextField(minimalistic ? note : EMPTYSTRING, text: $label) .accessibilityLabel(noteColon) - .focused($focus, equals: .alias) + .focused($focus, equals: .label) .talerFont(.title2) .foregroundColor(WalletColors().fieldForeground) // text color .background(WalletColors().fieldBackground) diff --git a/TalerWallet1/Views/Settings/Bank/BankListView.swift b/TalerWallet1/Views/Settings/Bank/BankListView.swift @@ -22,11 +22,7 @@ struct BankListView: View { @State var showAddDialog: Bool = false @State var newExchange: String = TESTEXCHANGE - @State var newBankAccount = KnownBankAccountsInfo(paytoUri: EMPTYSTRING, - kycCompleted: false, - currencies: [], - alias: nil) - @State private var bankAccounts: [KnownBankAccountsInfo] = [] + @State private var bankAccounts: [BankAccountsInfo] = [] @MainActor func addExchange(_ exchange: String) -> Void { @@ -42,7 +38,7 @@ struct BankListView: View { @MainActor private func viewDidLoad() async { - if let accounts = try? await model.listKnownBankAccounts() { + if let accounts = try? await model.listBankAccounts() { withAnimation { bankAccounts = accounts } } } @@ -81,7 +77,7 @@ struct BankListView: View { } let addBankDest = BankEditView(stack: stack.push(), - account: newBankAccount) + account: nil) let actions = Group { NavLink($showAddDialog) { addBankDest } } @@ -94,7 +90,7 @@ struct BankListView: View { depositHint ForEach(bankAccounts, id: \.self) { account in BankSectionView(stack: stack.push(), - account: account) + account: account) // Text(account.paytoUri) } } diff --git a/TalerWallet1/Views/Settings/Bank/BankSectionView.swift b/TalerWallet1/Views/Settings/Bank/BankSectionView.swift @@ -14,7 +14,7 @@ import SymLog struct BankSectionView: View { private let symLog = SymLogV(0) let stack: CallStack - let account: KnownBankAccountsInfo + let account: BankAccountsInfo @EnvironmentObject private var model: WalletModel @EnvironmentObject private var controller: Controller @@ -33,13 +33,13 @@ struct BankSectionView: View { @State private var accountHolder: String = EMPTYSTRING @State private var iban: String = EMPTYSTRING @State private var xTaler: String = EMPTYSTRING - @State private var alias: String = EMPTYSTRING + @State private var label: String = EMPTYSTRING @State private var paytoType: PaytoType = .iban @State private var selected = 0 @FocusState private var focus:FocusedField? enum FocusedField: Hashable { - case accountHolder, iban, xTaler, alias + case accountHolder, iban, xTaler, label } // @MainActor @@ -57,7 +57,7 @@ struct BankSectionView: View { let payURL = URL(string: account.paytoUri) iban = payURL?.iban ?? EMPTYSTRING xTaler = payURL?.xTaler ?? EMPTYSTRING - alias = account.alias ?? EMPTYSTRING + label = account.label ?? EMPTYSTRING if let queryParameters = payURL?.queryParameters { let name = if let rcv = queryParameters["receiver-name"] { rcv.replacingOccurrences(of: "+", with: SPACE) @@ -105,18 +105,23 @@ struct BankSectionView: View { account: account) } label: { VStack(alignment: .leading) { - if account.currencies.count == 1 { - BankSectionRow(title: String(localized: "Currency:"), - value: account.currencies[0]) - } else { - if !minimalistic { Text("Currencies:") } - ForEach (account.currencies, id: \.self) { currency in - Text(currency) - .frame(maxWidth: .infinity, alignment: .trailing) + if let currencies = account.currencies { + if currencies.count == 1 { + BankSectionRow(title: String(localized: "Currency:"), + value: currencies[0]) + } else { + if !minimalistic { Text("Currencies:") } + ForEach (currencies, id: \.self) { currency in + Text(currency) + .frame(maxWidth: .infinity, alignment: .trailing) + } } + } else { + BankSectionRow(title: String(localized: "Currency:"), + value: "UNKNOWN") } BankSectionRow(title: String(localized: "Note:"), - value: alias) + value: label) BankSectionRow(title: String(localized: "Account holder:"), value: accountHolder) BankSectionRow(title: String(localized: "\(methodType):", comment: "methodType:"),