taler-ios

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

commit deec3fc223b81298360525bb7ddf3d5ef3598d1c
parent 6aef0c3b58db09b716fdfec3a10e18bb4407bd19
Author: Marc Stibane <marc@taler.net>
Date:   Sat,  9 Nov 2024 11:33:25 +0100

Withdraw

Diffstat:
MTalerWallet1/Model/Model+Withdraw.swift | 56++++++++++++++++++++++++++++++++++++--------------------
MTalerWallet1/Views/Actions/Banking/ManualWithdraw.swift | 5+++--
MTalerWallet1/Views/Actions/Banking/ManualWithdrawDone.swift | 3++-
MTalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift | 3++-
MTalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift | 53+++++++++++++++++++++++++++++------------------------
MTalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift | 35++++++++++++++++++++---------------
MTalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift | 10++++++----
MTalerWallet1/Views/Sheets/WithdrawExchangeV.swift | 2+-
MTalerWallet1/Views/Transactions/ManualDetailsV.swift | 7+++++--
9 files changed, 104 insertions(+), 70 deletions(-)

diff --git a/TalerWallet1/Model/Model+Withdraw.swift b/TalerWallet1/Model/Model+Withdraw.swift @@ -236,31 +236,37 @@ fileprivate struct GetQrCodesForPayto: WalletBackendFormattedRequest { // MARK: - extension WalletModel { /// load withdraw-exchange details. Networking involved - @MainActor // M for MainActor - func loadWithdrawalExchangeForUriM(_ talerUri: String, viewHandles: Bool = false) + nonisolated func loadWithdrawalExchangeForUri(_ talerUri: String, + viewHandles: Bool = false) async throws -> WithdrawExchangeResponse { let request = PrepareWithdrawExchange(talerUri: talerUri) let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response } + /// load withdrawal details. Networking involved - @MainActor // M for MainActor - func getWithdrawalDetailsForUriM(_ talerWithdrawUri: String, viewHandles: Bool = false) + nonisolated func getWithdrawalDetailsForUri(_ talerUri: String, + viewHandles: Bool = false) async throws -> WithdrawUriInfoResponse { - let request = GetWithdrawalDetailsForURI(talerWithdrawUri: talerWithdrawUri) + let request = GetWithdrawalDetailsForURI(talerWithdrawUri: talerUri) let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response } - @MainActor // M for MainActor - func getWithdrawalDetailsForAmountM(_ amount: Amount, baseUrl: String?, scope: ScopeInfo?, - viewHandles: Bool = false) + + nonisolated func getWithdrawalDetailsForAmount(_ amount: Amount, + baseUrl: String?, + scope: ScopeInfo?, + viewHandles: Bool = false) async throws -> WithdrawalDetailsForAmount { - let request = GetWithdrawalDetailsForAmount(amount: amount, baseUrl: baseUrl, scope: scope) + let request = GetWithdrawalDetailsForAmount(amount: amount, baseUrl: baseUrl, scope: scope) let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response } - @MainActor // M for MainActor - func loadExchangeTermsOfServiceM(_ exchangeBaseUrl: String, acceptedFormat: [String], acceptLanguage: String, viewHandles: Bool = false) + + nonisolated func loadExchangeTermsOfService(_ exchangeBaseUrl: String, + acceptedFormat: [String], + acceptLanguage: String, + viewHandles: Bool = false) async throws -> ExchangeTermsOfService { let request = GetExchangeTermsOfService(exchangeBaseUrl: exchangeBaseUrl, acceptedFormat: acceptedFormat, @@ -268,31 +274,41 @@ extension WalletModel { let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response } - @MainActor // M for MainActor - func setExchangeTOSAcceptedM(_ exchangeBaseUrl: String, etag: String, viewHandles: Bool = false) + + nonisolated func setExchangeTOSAccepted(_ exchangeBaseUrl: String, + etag: String, + viewHandles: Bool = false) async throws -> Decodable { let request = SetExchangeTOSAccepted(exchangeBaseUrl: exchangeBaseUrl, etag: etag) let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response } - @MainActor // M for MainActor - func sendAcceptIntWithdrawalM(_ exchangeBaseUrl: String, withdrawURL: String, amount: Amount?, restrictAge: Int?, viewHandles: Bool = false) + + nonisolated func acceptBankIntWithdrawal(_ exchangeBaseUrl: String, + withdrawURL: String, + amount: Amount?, + restrictAge: Int?, + viewHandles: Bool = false) async throws -> AcceptWithdrawalResponse? { let request = AcceptBankIntegratedWithdrawal(talerWithdrawUri: withdrawURL, exchangeBaseUrl: exchangeBaseUrl, amount: amount, restrictAge: restrictAge) let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response } - @MainActor // M for MainActor - func acceptManualWithdrawalM(_ amount: Amount, baseUrl: String, restrictAge: Int?, viewHandles: Bool = false) + + nonisolated func acceptManualWithdrawal(_ amount: Amount, + baseUrl: String, + restrictAge: Int?, + viewHandles: Bool = false) async throws -> AcceptManualWithdrawalResult? { let request = AcceptManualWithdrawal(amount: amount, baseUrl: baseUrl, restrictAge: restrictAge) let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response } - @MainActor // M for MainActor - func getQrCodesForPaytoM(_ paytoUri: String, viewHandles: Bool = false) - async throws -> [QrCodeSpec]? { + + nonisolated func getQrCodesForPayto(_ paytoUri: String, + viewHandles: Bool = false) + async throws -> [QrCodeSpec]? { let request = GetQrCodesForPayto(paytoUri: paytoUri) let response = try await sendRequest(request, ASYNCDELAY, viewHandles: viewHandles) return response.codes diff --git a/TalerWallet1/Views/Actions/Banking/ManualWithdraw.swift b/TalerWallet1/Views/Actions/Banking/ManualWithdraw.swift @@ -137,12 +137,13 @@ struct ManualWithdrawContent: View { return nil } + @MainActor private func computeFee(_ amount: Amount) async -> ComputeFeeResult? { if amount.isZero { return ComputeFeeResult.zero() } do { - let details = try await model.getWithdrawalDetailsForAmountM(amount, baseUrl: nil, scope: scope, + let details = try await model.getWithdrawalDetailsForAmount(amount, baseUrl: nil, scope: scope, viewHandles: true) detailsForAmount = details // agePicker.setAges(ages: detailsForAmount?.ageRestrictionOptions) @@ -163,7 +164,7 @@ struct ManualWithdrawContent: View { @MainActor private func viewDidLoad2() async { // neues scope wenn balance geƤndert wird? - let details = try? await model.getWithdrawalDetailsForAmountM(amountToTransfer, baseUrl: nil, scope: scope, + let details = try? await model.getWithdrawalDetailsForAmount(amountToTransfer, baseUrl: nil, scope: scope, viewHandles: true) if let details { detailsForAmount = details diff --git a/TalerWallet1/Views/Actions/Banking/ManualWithdrawDone.swift b/TalerWallet1/Views/Actions/Banking/ManualWithdrawDone.swift @@ -29,9 +29,10 @@ struct ManualWithdrawDone: View { return try await model.getTransactionByIdT(transactionId, viewHandles: viewHandles) } + @MainActor private func viewDidLoad() async { if transactionId == nil { - if let result = try? await model.acceptManualWithdrawalM(amountToTransfer, + if let result = try? await model.acceptManualWithdrawal(amountToTransfer, baseUrl: baseURL, restrictAge: 0) { transactionId = result.transactionId } diff --git a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift @@ -31,10 +31,11 @@ struct WithdrawAcceptDone: View { return response } + @MainActor private func viewDidLoad() async { if let exchangeBaseUrl { // TODO: restrictAge - if let result = try? await model.sendAcceptIntWithdrawalM(exchangeBaseUrl, + if let result = try? await model.acceptBankIntWithdrawal(exchangeBaseUrl, withdrawURL: url.absoluteString, amount: amountToTransfer, restrictAge: nil diff --git a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift @@ -37,6 +37,22 @@ struct WithdrawAcceptView: View { } } + @MainActor + private func viewDidLoad() async { + symLog.log(".task \(exchange?.id ?? "nil")") + if let exchange { + if let details = try? await model.getWithdrawalDetailsForAmount(amountToTransfer, + baseUrl: exchange.exchangeBaseUrl, + scope: nil) { // TODO: scope + withdrawalDetails = details + } +// agePicker.setAges(ages: details?.ageRestrictionOptions) + } else { // TODO: error + symLog.log("no exchangeBaseUrl or no exchange") + withdrawalDetails = nil + } + } + var body: some View { if let exchange, let withdrawalDetails { VStack { @@ -81,17 +97,19 @@ struct WithdrawAcceptView: View { } .listStyle(myListStyle.style).anyView .navigationTitle(navTitle) - if tosAccepted { - let destination = WithdrawAcceptDone(stack: stack.push(), - scope: scope, - exchangeBaseUrl: exchange.exchangeBaseUrl, - url: url, - amountToTransfer: amountToTransfer) - NavigationLink(destination: destination) { - Text("Confirm Withdrawal") // SHEET_WITHDRAW_ACCEPT + .safeAreaInset(edge: .bottom) { + if tosAccepted { + let destination = WithdrawAcceptDone(stack: stack.push(), + scope: scope, + exchangeBaseUrl: exchange.exchangeBaseUrl, + url: url, + amountToTransfer: amountToTransfer) + NavigationLink(destination: destination) { + Text("Confirm Withdrawal") // SHEET_WITHDRAW_ACCEPT + } + .buttonStyle(TalerButtonStyle(type: .prominent)) + .padding(.horizontal) } - .buttonStyle(TalerButtonStyle(type: .prominent)) - .padding(.horizontal) } } .onAppear() { @@ -105,20 +123,7 @@ struct WithdrawAcceptView: View { let message: String? = nil #endif LoadingView(scopeInfo: nil, message: message) - .task(id: exchange?.id) { - symLog.log(".task \(exchange?.id ?? "nil")") - if let exchange { - if let details = try? await model.getWithdrawalDetailsForAmountM(amountToTransfer, - baseUrl: exchange.exchangeBaseUrl, - scope: nil) { // TODO: scope - withdrawalDetails = details - } -// agePicker.setAges(ages: details?.ageRestrictionOptions) - } else { // TODO: error - symLog.log("no exchangeBaseUrl or no exchange") - withdrawalDetails = nil - } - } + .task(id: exchange?.id) { await viewDidLoad() } } } } diff --git a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift @@ -21,12 +21,13 @@ struct WithdrawTOSView: View { let navTitle = String(localized: "Terms of Service") + @MainActor func loadToS(_ language: String) async { if let exchangeBaseUrl { let acceptedFormat: [String] = [MARKDOWN, PLAINTEXT] // MARKDOWN, HTML, PLAINTEXT - if let someTOS = try? await model.loadExchangeTermsOfServiceM(exchangeBaseUrl, - acceptedFormat: acceptedFormat, - acceptLanguage: language) { + if let someTOS = try? await model.loadExchangeTermsOfService(exchangeBaseUrl, + acceptedFormat: acceptedFormat, + acceptLanguage: language) { exchangeTOS = someTOS } } else { @@ -34,24 +35,28 @@ struct WithdrawTOSView: View { } } + @MainActor + func viewDidLoad() async { + if let exchangeTOS, let exchangeBaseUrl { + _ = try? await model.setExchangeTOSAccepted(exchangeBaseUrl, + etag: exchangeTOS.currentEtag) + if acceptAction != nil { + await acceptAction!() + } else { // just go back - caller will reload + self.presentationMode.wrappedValue.dismiss() + } + } else { + // TODO: error + } + } + var body: some View { let languageCode = Locale.preferredLanguageCode // let languageName = Locale.current.localizedString(forLanguageCode: languageCode) if let exchangeTOS { Content(symLog: symLog, tos: exchangeTOS, myListStyle: $myListStyle, language: languageCode, languageAction: loadToS) { - Task { // runs on MainActor - if let exchangeBaseUrl { - _ = try? await model.setExchangeTOSAcceptedM(exchangeBaseUrl, etag: exchangeTOS.currentEtag) - if acceptAction != nil { - await acceptAction!() - } else { // just go back - caller will reload - self.presentationMode.wrappedValue.dismiss() - } - } else { - // TODO: error - } - } + Task { await viewDidLoad() } } .navigationTitle(navTitle) .onAppear() { diff --git a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift @@ -66,11 +66,12 @@ struct WithdrawURIView: View { : EMPTYSTRING } + @MainActor private func computeFeeWithdraw(_ amount: Amount) async -> ComputeFeeResult? { if let exchange { - if let details = try? await model.getWithdrawalDetailsForAmountM(amount, - baseUrl: exchange.exchangeBaseUrl, - scope: nil) { // TODO: scope + if let details = try? await model.getWithdrawalDetailsForAmount(amount, + baseUrl: exchange.exchangeBaseUrl, + scope: nil) { // TODO: scope let fee = try? details.amountRaw - details.amountEffective let feeStr = fee?.formatted(currencyInfo, isNegative: true) ?? "nix" symLog.log("Fee = \(feeStr)") @@ -89,10 +90,11 @@ struct WithdrawURIView: View { return nil } + @MainActor private func viewDidLoad() async { symLog.log(".task") do { - let uriInfoResponse = try await model.getWithdrawalDetailsForUriM(url.absoluteString) + let uriInfoResponse = try await model.getWithdrawalDetailsForUri(url.absoluteString) let amount = uriInfoResponse.amount let currency = amount?.currencyStr ?? uriInfoResponse.currency amountToTransfer = amount ?? Amount.zero(currency: currency) diff --git a/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift b/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift @@ -29,7 +29,7 @@ struct WithdrawExchangeV: View { private func viewDidLoad() async { if exchange == nil { symLog.log(".task") - if let withdrawExchange = try? await model.loadWithdrawalExchangeForUriM(url.absoluteString) { + if let withdrawExchange = try? await model.loadWithdrawalExchangeForUri(url.absoluteString) { let baseUrl = withdrawExchange.exchangeBaseUrl symLog.log("getExchangeByUrl(\(baseUrl))") if let exc = try? await model.getExchangeByUrl(url: baseUrl) { diff --git a/TalerWallet1/Views/Transactions/ManualDetailsV.swift b/TalerWallet1/Views/Transactions/ManualDetailsV.swift @@ -137,10 +137,13 @@ struct ManualDetailsV: View { } } + @MainActor private func viewDidLoad(_ payto: String) async { - if let specs = try? await model.getQrCodesForPaytoM(payto) { - qrCodeSpecs = specs ?? [] + if let specs = try? await model.getQrCodesForPayto(payto) { + qrCodeSpecs = specs + return } + qrCodeSpecs = [] } var body: some View {