[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-ios] 142/204: DepositAmountView
From: |
gnunet |
Subject: |
[taler-taler-ios] 142/204: DepositAmountView |
Date: |
Thu, 05 Dec 2024 23:51:50 +0100 |
This is an automated email from the git hooks/post-receive script.
marc-stibane pushed a commit to branch master
in repository taler-ios.
commit acd7dda4e3a53a90d45bf330ae479b8e72afb2c0
Author: Marc Stibane <marc@taler.net>
AuthorDate: Wed Nov 20 07:28:00 2024 +0100
DepositAmountView
---
TalerWallet.xcodeproj/project.pbxproj | 6 +
.../Views/Actions/Banking/DepositAmountV.swift | 189 +--------------------
...epositAmountV.swift => DepositAmountView.swift} | 148 +++-------------
3 files changed, 35 insertions(+), 308 deletions(-)
diff --git a/TalerWallet.xcodeproj/project.pbxproj
b/TalerWallet.xcodeproj/project.pbxproj
index 18b237e..135d956 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -289,6 +289,8 @@
4EE77E7F2C0280E5007C9064 /* Taler_Wallet InfoPlist.xcstrings in
Resources */ = {isa = PBXBuildFile; fileRef = 4EE77E7E2C0280E5007C9064 /*
Taler_Wallet InfoPlist.xcstrings */; };
4EE77E812C06E513007C9064 /* WithdrawAcceptView.swift in Sources
*/ = {isa = PBXBuildFile; fileRef = 4EE77E802C06E513007C9064 /*
WithdrawAcceptView.swift */; };
4EE77E822C06E513007C9064 /* WithdrawAcceptView.swift in Sources
*/ = {isa = PBXBuildFile; fileRef = 4EE77E802C06E513007C9064 /*
WithdrawAcceptView.swift */; };
+ 4EE9864F2CE26E0F00F75634 /* DepositAmountView.swift in Sources
*/ = {isa = PBXBuildFile; fileRef = 4EE9864E2CE26E0F00F75634 /*
DepositAmountView.swift */; };
+ 4EE986502CE26E0F00F75634 /* DepositAmountView.swift in Sources
*/ = {isa = PBXBuildFile; fileRef = 4EE9864E2CE26E0F00F75634 /*
DepositAmountView.swift */; };
4EEBEFB02C8982180020D340 /* View+innerSize.swift in Sources */
= {isa = PBXBuildFile; fileRef = 4EEBEFAF2C8982180020D340 /*
View+innerSize.swift */; };
4EEBEFB12C8982180020D340 /* View+innerSize.swift in Sources */
= {isa = PBXBuildFile; fileRef = 4EEBEFAF2C8982180020D340 /*
View+innerSize.swift */; };
4EEC118D2B83DE4800146CFF /* AmountInputV.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4EEC118C2B83DE4700146CFF /* AmountInputV.swift
*/; };
@@ -499,6 +501,7 @@
4EE77E7C2C0280E5007C9064 /* GNU_Taler InfoPlist.xcstrings */ =
{isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path =
"GNU_Taler InfoPlist.xcstrings"; sourceTree = "<group>"; };
4EE77E7E2C0280E5007C9064 /* Taler_Wallet InfoPlist.xcstrings */
= {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path =
"Taler_Wallet InfoPlist.xcstrings"; sourceTree = "<group>"; };
4EE77E802C06E513007C9064 /* WithdrawAcceptView.swift */ = {isa
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift;
path = WithdrawAcceptView.swift; sourceTree = "<group>"; };
+ 4EE9864E2CE26E0F00F75634 /* DepositAmountView.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= DepositAmountView.swift; sourceTree = "<group>"; };
4EEBEFAF2C8982180020D340 /* View+innerSize.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= "View+innerSize.swift"; sourceTree = "<group>"; };
4EEC118C2B83DE4700146CFF /* AmountInputV.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= AmountInputV.swift; sourceTree = "<group>"; };
4EEC11922B83FB7A00146CFF /* SubjectInputV.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= SubjectInputV.swift; sourceTree = "<group>"; };
@@ -924,6 +927,7 @@
children = (
4EBC0F002B7B3CD600C0CB19 /* DepositIbanV.swift
*/,
4E96583B2B79656E00404A68 /*
DepositAmountV.swift */,
+ 4EE9864E2CE26E0F00F75634 /*
DepositAmountView.swift */,
4E50B34F2A1BEE8000F9F01C /*
ManualWithdraw.swift */,
4EBA82AC2A3F580500E5F39A /*
QuiteSomeCoins.swift */,
4EB431662A1E55C700C5690E /*
ManualWithdrawDone.swift */,
@@ -1257,6 +1261,7 @@
4E3EAE3E2A990778009F1BE8 /*
ManualDetailsV.swift in Sources */,
4E3EAE3F2A990778009F1BE8 /*
View+dismissTop.swift in Sources */,
4E3EAE402A990778009F1BE8 /*
TransactionsListView.swift in Sources */,
+ 4EE9864F2CE26E0F00F75634 /*
DepositAmountView.swift in Sources */,
4E0A71142C396D86002485BB /*
Error+debugDescription.swift in Sources */,
4E3EAE412A990778009F1BE8 /*
WalletBackendRequest.swift in Sources */,
4E3EAE422A990778009F1BE8 /*
KeyboardResponder.swift in Sources */,
@@ -1392,6 +1397,7 @@
4E6EDD852A3615BE0031D520 /*
ManualDetailsV.swift in Sources */,
4EB0950B2989CB7C0043A8A1 /*
View+dismissTop.swift in Sources */,
4EB095562989CBFE0043A8A1 /*
TransactionsListView.swift in Sources */,
+ 4EE986502CE26E0F00F75634 /*
DepositAmountView.swift in Sources */,
4E0A71152C396D86002485BB /*
Error+debugDescription.swift in Sources */,
4EB0951F2989CBCB0043A8A1 /*
WalletBackendRequest.swift in Sources */,
4EAD117629F672FA008EDD0B /*
KeyboardResponder.swift in Sources */,
diff --git a/TalerWallet1/Views/Actions/Banking/DepositAmountV.swift
b/TalerWallet1/Views/Actions/Banking/DepositAmountV.swift
index a1c0d58..6a62589 100644
--- a/TalerWallet1/Views/Actions/Banking/DepositAmountV.swift
+++ b/TalerWallet1/Views/Actions/Banking/DepositAmountV.swift
@@ -82,7 +82,7 @@ struct DepositAmountV: View {
.padding(.horizontal)
.padding(.bottom, 4)
}
- DepositAmountContent(stack: stack.push(),
+ DepositAmountView(stack: stack.push(),
balance: $balance,
balanceIndex: $balanceIndex,
amountLastUsed: $amountLastUsed,
@@ -93,13 +93,6 @@ struct DepositAmountV: View {
.navigationTitle(navTitle)
.frame(maxWidth: .infinity, alignment: .leading)
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
- .onAppear {
- DebugViewC.shared.setViewID(VIEW_DEPOSIT, stack: stack.push())
- symLog.log("❗️ \(navTitle) onAppear")
- }
- .onDisappear {
- symLog.log("❗️ \(navTitle) onDisappear")
- }
.task { await viewDidLoad() }
.task(id: balanceIndex + (1000 * controller.currencyTicker)) {
await newBalance() }
@@ -115,183 +108,3 @@ struct DepositAmountV: View {
}
}
}
-// MARK: -
-struct DepositAmountContent: View {
- private let symLog = SymLogV(0)
- let stack: CallStack
- @Binding var balance: Balance?
- @Binding var balanceIndex: Int
- @Binding var amountLastUsed: Amount
- @Binding var amountToTransfer: Amount
- let amountAvailable: Amount
- let paytoUri: String?
-
- @EnvironmentObject private var controller: Controller
- @EnvironmentObject private var model: WalletModel
- @Environment(\.colorScheme) private var colorScheme
- @Environment(\.colorSchemeContrast) private var colorSchemeContrast
- @AppStorage("minimalistic") var minimalistic: Bool = false
-
- @State var checkDepositResult: CheckDepositResponse? = nil
- @State private var insufficient = false
- @State private var feeAmount: Amount? = nil
- @State private var feeStr: String = EMPTYSTRING
- @State private var depositStarted = false
- @State private var exchange: Exchange? = nil
// wg. noFees
-
- private func feeLabel(_ feeString: String) -> String {
- feeString.count > 0 ? String(localized: "+ \(feeString) fee")
- : EMPTYSTRING
- }
-
- private func feeIsNotZero() -> Bool? {
- if let hasNoFees = exchange?.noFees {
- if hasNoFees {
- return nil // this exchange never has fees
- }
- }
- return checkDepositResult == nil ? false
- : true // TODO: !(feeAmount?.isZero
?? false)
- }
-
- private func computeFeeDeposit(_ amount: Amount) async ->
ComputeFeeResult? {
- if amount.isZero {
- return ComputeFeeResult.zero()
- }
- let insufficient = (try? amount > amountAvailable) ?? true
- if insufficient {
- return ComputeFeeResult.insufficient()
- }
-// private func fee(ppCheck: CheckDepositResponse?) -> Amount? {
- do {
-// if let ppCheck {
-// // Outgoing: fee = effective - raw
-// feeAmount = try ppCheck.fees.coin + ppCheck.fees.wire +
ppCheck.fees.refresh
-// return feeAmount
-// }
- } catch {
-
- }
- return nil
- }
-
- private func buttonTitle(_ amount: Amount) -> String {
- if let balance {
- let amountWithCurrency = amount.formatted(balance.scopeInfo,
isNegative: false, useISO: true)
- return String(localized: "Deposit \(amountWithCurrency)", comment:
"Button: amount with currency")
- }
- return subjectTitle(amount) // should never happen
- }
-
- private func subjectTitle(_ amount: Amount) -> String {
-// let amountStr = amount.formatted(scopeInfo, isNegative: false)
- return String(localized: "NavTitle_Deposit_AmountStr",
- defaultValue: "Deposit", comment: "NavTitle: Deposit")
- // defaultValue: "Deposit \(amountStr)", comment:
"NavTitle: Deposit 'amountStr'")
- }
-
- @MainActor
- private func startDeposit() {
- if let paytoUri {
- depositStarted = true // don't run twice
- Task {
- symLog.log("Deposit")
- if let result = try? await model.createDepositGroup(paytoUri,
amount: amountToTransfer) {
- symLog.log(result.transactionId)
- ViewState2.shared.popToRootView(stack.push())
- NotificationCenter.default.post(name: .TransactionDone,
object: nil, userInfo: nil)
- } else {
- depositStarted = false
- }
- }
- }
- }
-
- var body: some View {
-#if PRINT_CHANGES
- let _ = Self._printChanges()
- let _ = symLog.vlog() // just to get the # to compare it with
.onAppear & onDisappear
-#endif
- if depositStarted {
- LoadingView(scopeInfo: nil, message: "Depositing...")
- .navigationBarBackButtonHidden(true)
- .interactiveDismissDisabled() // can only use "Done"
button to dismiss
- } else { Group {
- if let balance {
- let scopeInfo = balance.scopeInfo
- let availableStr = amountAvailable.formatted(scopeInfo,
isNegative: false)
-
- let currencyInfo = controller.info(for: scopeInfo,
controller.currencyTicker)
-// let amountVoiceOver = amountToTransfer.formatted(scopeInfo,
isNegative: false)
- let insufficientLabel = String(localized: "You don't have
enough \(currencyInfo.specs.name).")
-// let insufficientLabel2 = String(localized: "but you only
have \(available) to deposit.")
-
- let disabled = insufficient || amountToTransfer.isZero
-
- Text("Available:\t\(availableStr)")
- .talerFont(.title3)
- .padding(.bottom, 2)
- CurrencyInputView(scope: scopeInfo,
- amount: $amountToTransfer,
- amountLastUsed: amountLastUsed,
- available: nil, // amountAvailable,
- title: minimalistic ? String(localized:
"Amount:")
- : String(localized:
"Amount to deposit:"),
- shortcutAction: nil)
-
- Text(insufficient ? insufficientLabel
- : feeLabel(feeStr))
- .talerFont(.body)
- .foregroundColor(insufficient ? .red
- : (feeAmount?.isZero ??
true) ? WalletColors().secondary(colorScheme, colorSchemeContrast)
-
: .red)
- .padding(4)
- Button(buttonTitle(amountToTransfer)) { startDeposit() }
- .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled || depositStarted))
- .disabled(disabled || depositStarted)
- .accessibilityHint(disabled ? String(localized: "enabled when
amount is non-zero, but not higher than your available amount") : EMPTYSTRING)
- } else { // no balance - Yikes
- Text("No balance. There seems to be a problem with the
database...")
- }
- }
-// .task(id: amountToTransfer.value) {
-// if let amountAvailable {
-// do {
-// insufficient = try amountToTransfer > amountAvailable
-// } catch {
-// print("Yikes❗️ insufficient failed❗️")
-// insufficient = true
-// }
-//
-// if insufficient {
-// announce("\(amountVoiceOver), \(insufficientLabel2)")
-// feeStr = EMPTYSTRING
-// }
-// }
-// if !insufficient {
-// if amountToTransfer.isZero {
-// feeStr = EMPTYSTRING
-// checkDepositResult = nil
-// } else if let paytoUri {
-// if let ppCheck = try? await
model.checkDepositM(paytoUri, amount: amountToTransfer) {
-// if let feeAmount = fee(ppCheck: ppCheck) {
-// feeStr = feeAmount.formatted(scopeInfo,
isNegative: false)
-// let feeLabel = feeLabel(feeStr)
-// announce("\(amountVoiceOver), \(feeLabel)")
-// } else {
-// feeStr = EMPTYSTRING
-// announce(amountVoiceOver)
-// }
-// checkDepositResult = ppCheck
-// } else {
-// checkDepositResult = nil
-// }
-// }
-// }
-// }
- } // else
- } // body
-}
-// MARK: -
-#if DEBUG
-#endif
diff --git a/TalerWallet1/Views/Actions/Banking/DepositAmountV.swift
b/TalerWallet1/Views/Actions/Banking/DepositAmountView.swift
similarity index 60%
copy from TalerWallet1/Views/Actions/Banking/DepositAmountV.swift
copy to TalerWallet1/Views/Actions/Banking/DepositAmountView.swift
index a1c0d58..72ca548 100644
--- a/TalerWallet1/Views/Actions/Banking/DepositAmountV.swift
+++ b/TalerWallet1/Views/Actions/Banking/DepositAmountView.swift
@@ -9,114 +9,8 @@ import SwiftUI
import taler_swift
import SymLog
-// Called from DepositIbanV
-struct DepositAmountV: View {
- private let symLog = SymLogV(0)
- let stack: CallStack
- @Binding var selectedBalance: Balance?
- @Binding var amountLastUsed: Amount
- let paytoUri: String?
-
- @EnvironmentObject private var controller: Controller
- @EnvironmentObject private var model: WalletModel
-
- @State private var balanceIndex = 0
- @State private var balance: Balance? = nil // nil only when balances
== []
- @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING)
// Update currency when used
- @State private var amountAvailable = Amount.zero(currency: EMPTYSTRING)
// GetMaxPeerPushAmount
-
- @MainActor
- private func viewDidLoad() async {
- let balances = controller.balances
- if let selectedBalance {
- if selectedBalance.available.isZero {
- // find another balance
- balance = Balance.firstNonZero(balances)
- } else {
- balance = selectedBalance
- }
- } else {
- balance = Balance.firstNonZero(balances)
- }
- if let balance {
- balanceIndex = balances.firstIndex(of: balance) ?? 0
- } else {
- balanceIndex = 0
- balance = (balances.count > 0) ? balances[0] : nil
- }
- }
-
- @MainActor
- private func newBalance() async {
- // runs whenever the user changes the exchange via ScopePicker, or on
new currencyInfo
- symLog.log("❗️ task \(balanceIndex)")
- if let balance {
- let scope = balance.scopeInfo
- amountToTransfer.setCurrency(scope.currency)
- do {
- amountAvailable = try await model.getMaxDepositAmount(scope)
- } catch {
- // TODO: Error
- amountAvailable = balance.available
- }
- }
- }
-
- var body: some View {
-#if PRINT_CHANGES
- let _ = Self._printChanges()
-#endif
- let count = controller.balances.count
- let _ = symLog.log("count = \(count)")
- let navTitle = String(localized: "NavTitle_Deposit_Currency",
- defaultValue: "Deposit", // \(currencySymbol)",
- comment: "NavTitle: Deposit 'currencySymbol'")
- let scrollView = ScrollView {
- if count > 0 {
- ScopePicker(value: $balanceIndex,
- onlyNonZero: true)
// can only send what exists
- { index in
- balanceIndex = index
- balance = controller.balances[index]
- }
- .padding(.horizontal)
- .padding(.bottom, 4)
- }
- DepositAmountContent(stack: stack.push(),
- balance: $balance,
- balanceIndex: $balanceIndex,
- amountLastUsed: $amountLastUsed,
- amountToTransfer: $amountToTransfer,
- amountAvailable: amountAvailable,
- paytoUri: paytoUri)
- } // ScrollView
- .navigationTitle(navTitle)
- .frame(maxWidth: .infinity, alignment: .leading)
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
- .onAppear {
- DebugViewC.shared.setViewID(VIEW_DEPOSIT, stack: stack.push())
- symLog.log("❗️ \(navTitle) onAppear")
- }
- .onDisappear {
- symLog.log("❗️ \(navTitle) onDisappear")
- }
- .task { await viewDidLoad() }
- .task(id: balanceIndex + (1000 * controller.currencyTicker)) {
await newBalance() }
-
- if #available(iOS 16.0, *) {
- if #available(iOS 16.4, *) {
- scrollView.toolbar(.hidden, for: .tabBar)
- .scrollBounceBehavior(.basedOnSize)
- } else {
- scrollView.toolbar(.hidden, for: .tabBar)
- }
- } else {
- scrollView
- }
- }
-}
-// MARK: -
-struct DepositAmountContent: View {
+// Called when tapping [Withdraw]
+struct DepositAmountView: View {
private let symLog = SymLogV(0)
let stack: CallStack
@Binding var balance: Balance?
@@ -139,6 +33,17 @@ struct DepositAmountContent: View {
@State private var depositStarted = false
@State private var exchange: Exchange? = nil
// wg. noFees
+ public static func navTitle(_ currency: String = EMPTYSTRING,
+ _ condition: Bool = false
+ ) -> String {
+ condition ? String(localized: "NavTitle_Deposit_Currency",
+ defaultValue: "Deposit \(currency)",
+ comment: "NavTitle: Deposit 'currency'")
+ : String(localized: "NavTitle_Deposit",
+ defaultValue: "Deposit",
+ comment: "NavTitle: Deposit")
+ }
+
private func feeLabel(_ feeString: String) -> String {
feeString.count > 0 ? String(localized: "+ \(feeString) fee")
: EMPTYSTRING
@@ -154,6 +59,7 @@ struct DepositAmountContent: View {
: true // TODO: !(feeAmount?.isZero
?? false)
}
+ @MainActor
private func computeFeeDeposit(_ amount: Amount) async ->
ComputeFeeResult? {
if amount.isZero {
return ComputeFeeResult.zero()
@@ -178,16 +84,9 @@ struct DepositAmountContent: View {
private func buttonTitle(_ amount: Amount) -> String {
if let balance {
let amountWithCurrency = amount.formatted(balance.scopeInfo,
isNegative: false, useISO: true)
- return String(localized: "Deposit \(amountWithCurrency)", comment:
"Button: amount with currency")
+ return DepositAmountView.navTitle(amountWithCurrency, true)
}
- return subjectTitle(amount) // should never happen
- }
-
- private func subjectTitle(_ amount: Amount) -> String {
-// let amountStr = amount.formatted(scopeInfo, isNegative: false)
- return String(localized: "NavTitle_Deposit_AmountStr",
- defaultValue: "Deposit", comment: "NavTitle: Deposit")
- // defaultValue: "Deposit \(amountStr)", comment:
"NavTitle: Deposit 'amountStr'")
+ return DepositAmountView.navTitle() // should never happen
}
@MainActor
@@ -226,7 +125,7 @@ struct DepositAmountContent: View {
let insufficientLabel = String(localized: "You don't have
enough \(currencyInfo.specs.name).")
// let insufficientLabel2 = String(localized: "but you only
have \(available) to deposit.")
- let disabled = insufficient || amountToTransfer.isZero
+ let disabled = insufficient || amountToTransfer.isZero
Text("Available:\t\(availableStr)")
.talerFont(.title3)
@@ -238,13 +137,14 @@ struct DepositAmountContent: View {
title: minimalistic ? String(localized:
"Amount:")
: String(localized:
"Amount to deposit:"),
shortcutAction: nil)
+ .padding(.horizontal)
Text(insufficient ? insufficientLabel
: feeLabel(feeStr))
.talerFont(.body)
- .foregroundColor(insufficient ? .red
+ .foregroundColor(insufficient ? WalletColors().attention
: (feeAmount?.isZero ??
true) ? WalletColors().secondary(colorScheme, colorSchemeContrast)
-
: .red)
+
: WalletColors().negative)
.padding(4)
Button(buttonTitle(amountToTransfer)) { startDeposit() }
.buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled || depositStarted))
@@ -254,6 +154,14 @@ struct DepositAmountContent: View {
Text("No balance. There seems to be a problem with the
database...")
}
}
+ .onAppear {
+ DebugViewC.shared.setViewID(VIEW_DEPOSIT, stack: stack.push())
+ symLog.log("❗️ onAppear")
+ }
+ .onDisappear {
+ symLog.log("❗️ onDisappear")
+ }
+
// .task(id: amountToTransfer.value) {
// if let amountAvailable {
// do {
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-ios] 188/204: regional exchange baseURL, (continued)
- [taler-taler-ios] 188/204: regional exchange baseURL, gnunet, 2024/12/05
- [taler-taler-ios] 182/204: L10N helper, gnunet, 2024/12/05
- [taler-taler-ios] 184/204: don't add to knownBankAccounts, gnunet, 2024/12/05
- [taler-taler-ios] 190/204: timeToPay w.i.p., gnunet, 2024/12/05
- [taler-taler-ios] 191/204: layout, legal hint, gnunet, 2024/12/05
- [taler-taler-ios] 194/204: A11y, gnunet, 2024/12/05
- [taler-taler-ios] 136/204: Available for transfer, gnunet, 2024/12/05
- [taler-taler-ios] 192/204: layout, gnunet, 2024/12/05
- [taler-taler-ios] 196/204: Nav header, gnunet, 2024/12/05
- [taler-taler-ios] 189/204: AccountPicker, gnunet, 2024/12/05
- [taler-taler-ios] 142/204: DepositAmountView,
gnunet <=
- [taler-taler-ios] 153/204: products, gnunet, 2024/12/05
- [taler-taler-ios] 161/204: DepositWireTypesForCurrency, gnunet, 2024/12/05
- [taler-taler-ios] 150/204: layout improvement, gnunet, 2024/12/05
- [taler-taler-ios] 152/204: fix badge, gnunet, 2024/12/05
- [taler-taler-ios] 157/204: fix flicker, gnunet, 2024/12/05
- [taler-taler-ios] 198/204: BankEditView, gnunet, 2024/12/05
- [taler-taler-ios] 164/204: amountLabel, gnunet, 2024/12/05
- [taler-taler-ios] 171/204: translations for GNU Taler, gnunet, 2024/12/05
- [taler-taler-ios] 175/204: layout, gnunet, 2024/12/05
- [taler-taler-ios] 177/204: common.scopes.first, gnunet, 2024/12/05