taler-ios

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

commit 54403a382dd0302559d591d7e66e1f11ed818c34
parent 4f50ba3a4a431cafe51d2ca091ccc866f7444e6b
Author: Marc Stibane <marc@taler.net>
Date:   Fri, 13 Sep 2024 09:22:25 +0200

balances & selectedBalance, move action navigation to MainView

Diffstat:
MTalerWallet1/Views/Balances/BalancesListView.swift | 64+++-------------------------------------------------------------
MTalerWallet1/Views/Balances/BalancesPendingRowV.swift | 5+++++
MTalerWallet1/Views/Balances/BalancesSectionView.swift | 4++++
MTalerWallet1/Views/Banking/DepositIbanV.swift | 2++
MTalerWallet1/Views/Banking/ManualWithdraw.swift | 2++
MTalerWallet1/Views/Main/MainView.swift | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
MTalerWallet1/Views/Sheets/QRSheet.swift | 8+++++++-
MTalerWallet1/Views/Sheets/URLSheet.swift | 15++++++++++-----
MTalerWallet1/Views/Sheets/WithdrawExchangeV.swift | 8+++++++-
MTalerWallet1/Views/Transactions/TransactionsListView.swift | 5++++-
10 files changed, 121 insertions(+), 90 deletions(-)

diff --git a/TalerWallet1/Views/Balances/BalancesListView.swift b/TalerWallet1/Views/Balances/BalancesListView.swift @@ -15,6 +15,7 @@ struct BalancesListView: View { private let symLog = SymLogV(0) let stack: CallStack @Binding var balances: [Balance] + @Binding var selectedBalance: Balance? // @Binding var shouldReloadPending: Int @Binding var shouldReloadBalances: Int let cameraAction: () -> Void @@ -24,10 +25,8 @@ struct BalancesListView: View { @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic @State private var lastReloadedBalances = 0 - @State private var actionSelected: Int? = nil @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING) // Update currency when used @State private var summary: String = "" - @State private var myExchange: Exchange? = nil /// runs on MainActor if called in some Task {} @discardableResult @@ -52,51 +51,6 @@ struct BalancesListView: View { let _ = Self._printChanges() let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear #endif - let scope = ScopeInfo(type: ScopeInfo.ScopeInfoType.exchange, - noFees: false, - url: DEMOEXCHANGE, - currency: DEMOCURRENCY) - let sendDest = LazyView { - SendAmount(stack: stack.push("\(Self.className())()"), - balances: balances, -// currencyInfo: $currencyInfo, -// amountAvailable: amountAvailable, - available: nil, - amountToTransfer: $amountToTransfer, // with correct currency - summary: $summary, - scopeInfo: scope, - cameraAction: cameraAction) - } - - let requestDest = LazyView { - RequestPayment(stack: stack.push("\(Self.className())()"), -// currencyInfo: $currencyInfo, - amountToTransfer: $amountToTransfer, // with correct currency - summary: $summary, - scopeInfo: scope, - cameraAction: cameraAction) - } - - let depositDest = LazyView { - DepositIbanV(stack: stack.push(), -// currencyInfo: $currencyInfo, - feeLabel: nil, - feeIsNotZero: nil, -// amountAvailable: amountAvailable, -// depositIBAN: $depositIBAN, -// accountHolder: $accountHolder, - amountToTransfer: $amountToTransfer) - } - - let manualWithdrawDest = LazyView { - ManualWithdraw(stack: stack.push(), -// currencyInfo: $currencyInfo, - isSheet: false, - scopeInfo: scope, - exchange: $myExchange, - amountToTransfer: $amountToTransfer) - } - Group { // necessary for .backslide transition (bug in SwiftUI) let count = balances.count if balances.isEmpty { @@ -105,6 +59,7 @@ struct BalancesListView: View { List(balances, id: \.self) { balance in BalancesSectionView(stack: stack.push("\(balance.scopeInfo.currency)"), balance: balance, // this is the currency to be used + selectedBalance: $selectedBalance, sectionCount: count, amountToTransfer: $amountToTransfer, // does still have the wrong currency summary: $summary, @@ -114,24 +69,11 @@ struct BalancesListView: View { .onAppear() { DebugViewC.shared.setViewID(VIEW_BALANCES, stack: stack.push("onAppear")) controller.frontendState = 0 // neutral + selectedBalance = nil } .listStyle(myListStyle.style).anyView } } - .background( Group { - NavigationLink(destination: sendDest, tag: 1, selection: $actionSelected) - { EmptyView() }.frame(width: 0).opacity(0).hidden() - NavigationLink(destination: requestDest, tag: 2, selection: $actionSelected) - { EmptyView() }.frame(width: 0).opacity(0).hidden() - NavigationLink(destination: depositDest, tag: 3, selection: $actionSelected) - { EmptyView() }.frame(width: 0).opacity(0).hidden() - NavigationLink(destination: manualWithdrawDest, tag: 4, selection: $actionSelected) - { EmptyView() }.frame(width: 0).opacity(0).hidden() - }) - .onNotification(.SendAction) { actionSelected = 1 } - .onNotification(.RequestAction) { actionSelected = 2 } - .onNotification(.DepositAction) { actionSelected = 3 } - .onNotification(.WithdrawAction) { actionSelected = 4 } #if REFRESHABLE .refreshable { // already async symLog.log("refreshing balances") diff --git a/TalerWallet1/Views/Balances/BalancesPendingRowV.swift b/TalerWallet1/Views/Balances/BalancesPendingRowV.swift @@ -11,6 +11,7 @@ struct BalancesPendingRowV: View { let stack: CallStack @Binding var currencyInfo: CurrencyInfo let balance: Balance + @Binding var selectedBalance: Balance? // <- return here the balance when we go to Transactions @Binding var pendingTransactions: [Transaction] let reloadPending: (_ stack: CallStack) async -> () let reloadOneAction: ((_ transactionId: String, _ viewHandles: Bool) async throws -> Transaction)? @@ -61,6 +62,8 @@ struct BalancesPendingRowV: View { if let reloadOneAction { let destination = LazyView { TransactionsListView(stack: stack.push(), + balance: balance, + selectedBalance: $selectedBalance, currencyInfo: $currencyInfo, navTitle: String(localized: "Pending", comment: "ViewTitle of TransactionList"), scopeInfo: balance.scopeInfo, @@ -83,6 +86,7 @@ fileprivate struct BalancesPendingRowV_Previews: PreviewProvider { struct BindingViewContainer: View { @State private var previewTransactions: [Transaction] = [] @State private var currencyInfoD: CurrencyInfo = CurrencyInfo.zero(DEMOCURRENCY) + @State private var selectedBalance: Balance? = nil var body: some View { let flags: [BalanceFlag] = [.incomingConfirmation] @@ -96,6 +100,7 @@ fileprivate struct BalancesPendingRowV_Previews: PreviewProvider { stack: CallStack("Preview"), currencyInfo: $currencyInfoD, balance: balance, + selectedBalance: $selectedBalance, pendingTransactions: $previewTransactions, reloadPending: {stack in }, reloadOneAction: nil) diff --git a/TalerWallet1/Views/Balances/BalancesSectionView.swift b/TalerWallet1/Views/Balances/BalancesSectionView.swift @@ -23,6 +23,7 @@ struct BalancesSectionView { private let symLog = SymLogV(0) let stack: CallStack let balance: Balance // this is the currency to be used + @Binding var selectedBalance: Balance? // <- return here the balance when we go to Transactions let sectionCount: Int @Binding var amountToTransfer: Amount // does still have the wrong currency @Binding var summary: String @@ -105,6 +106,8 @@ extension BalancesSectionView: View { let balanceDest = LazyView { TransactionsListView(stack: stack.push("\(Self.className())()"), + balance: balance, + selectedBalance: $selectedBalance, currencyInfo: $currencyInfo, navTitle: String(localized: "Transactions", comment: "ViewTitle of TransactionList"), scopeInfo: scopeInfo, @@ -154,6 +157,7 @@ extension BalancesSectionView: View { stack: stack.push(), currencyInfo: $currencyInfo, balance: balance, + selectedBalance: $selectedBalance, pendingTransactions: $pendingTransactions, reloadPending: loadPending, reloadOneAction: reloadOneAction) diff --git a/TalerWallet1/Views/Banking/DepositIbanV.swift b/TalerWallet1/Views/Banking/DepositIbanV.swift @@ -13,6 +13,8 @@ import SymLog struct DepositIbanV: View { private let symLog = SymLogV(0) let stack: CallStack + let balances: [Balance] + @Binding var selectedBalance: Balance? // @Binding var currencyInfo: CurrencyInfo let feeLabel: String? let feeIsNotZero: Bool? // nil = no fees at all, false = no fee for this tx diff --git a/TalerWallet1/Views/Banking/ManualWithdraw.swift b/TalerWallet1/Views/Banking/ManualWithdraw.swift @@ -14,6 +14,8 @@ import SymLog struct ManualWithdraw: View { private let symLog = SymLogV(0) let stack: CallStack + let balances: [Balance] + @Binding var selectedBalance: Balance? // @Binding var currencyInfo: CurrencyInfo let isSheet: Bool // let exchangeBaseUrl: String diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift @@ -38,6 +38,8 @@ struct MainView: View { @AppStorage("playSoundsI") var playSoundsI: Int = 1 // extension mustn't define this, so it must be here @AppStorage("playSoundsB") var playSoundsB: Bool = false + @State private var balances: [Balance] = [] + @State private var selectedBalance: Balance? = nil @State private var sheetPresented = false @State private var urlToOpen: URL? = nil @State private var showQRScanner: Bool = false @@ -109,6 +111,8 @@ struct MainView: View { Group { if controller.backendState == .ready { Content(logger: logger, stack: stack.push("Content"), + balances: $balances, + selectedBalance: $selectedBalance, talerFontIndex: $talerFontIndex, cameraAction: checkCameraAvailable) .onAppear() { @@ -125,7 +129,9 @@ struct MainView: View { dismissAlertButton }, message: { Text("Please allow camera access in settings.") }) // Scanning QR-codes .sheet(isPresented: $showQRScanner, onDismiss: dismissingSheet) { - let sheet = AnyView(QRSheet(stack: stack.push(".sheet"))) + let sheet = AnyView(QRSheet(stack: stack.push(".sheet"), + balances: $balances, + selectedBalance: $selectedBalance)) Sheet(stack: stack.push(), sheetView: sheet) } // sheet } else if controller.backendState == .error { @@ -148,7 +154,10 @@ struct MainView: View { urlToOpen = url // raise sheet } .sheet(item: $urlToOpen, onDismiss: sheetDismissed) { url in - let sheet = AnyView(URLSheet(stack: stack.push(), urlToOpen: url)) + let sheet = AnyView(URLSheet(stack: stack.push(), + balances: $balances, + selectedBalance: $selectedBalance, + urlToOpen: url)) Sheet(stack: stack.push(), sheetView: sheet) } .sheet(isPresented: $model.showError) { @@ -208,6 +217,8 @@ extension MainView { struct Content: View { let logger: Logger let stack: CallStack + @Binding var balances: [Balance] + @Binding var selectedBalance: Balance? @Binding var talerFontIndex: Int let cameraAction: () -> Void @@ -224,7 +235,6 @@ extension MainView { @State private var shouldReloadBalances = 0 @State private var shouldReloadPending = 0 - @State private var balances: [Balance] = [] @State private var selectedTab: Tab = .balances @State private var showKycAlert: Bool = false @State private var kycURI: URL? @@ -234,6 +244,8 @@ extension MainView { @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING) // Update currency when used @State private var summary: String = "" @State private var showSpendingHint = true + @State private var actionSelected: Int? = nil + @State private var myExchange: Exchange? = nil private var openKycButton: some View { Button("KYC") { @@ -276,6 +288,7 @@ extension MainView { } } + private static func className() -> String {"\(self)"} var body: some View { #if PRINT_CHANGES // "@self" marks that the view value itself has changed, and "@identity" marks that the @@ -299,38 +312,77 @@ extension MainView { selectedTab = .balances } // TODO: check NavigationStack, pop only if necessary - ViewState.shared.popToRootView(nil) +// ViewState.shared.popToRootView(nil) either do this after any of the buttons was operated, or don't do it at all showActionSheet = true } + + let scope = ScopeInfo(type: ScopeInfo.ScopeInfoType.exchange, + noFees: false, + url: DEMOEXCHANGE, + currency: DEMOCURRENCY) + + let sendDest = SendAmount(stack: stack.push("\(Self.className())()"), + balances: balances, + selectedBalance: $selectedBalance, // if nil shows currency picker + amountToTransfer: $amountToTransfer, // with correct currency + summary: $summary, + scopeInfo: scope, + cameraAction: cameraAction) + + let requestDest = RequestPayment(stack: stack.push("\(Self.className())()"), + balances: balances, + selectedBalance: $selectedBalance, + amountToTransfer: $amountToTransfer, // with correct currency + summary: $summary, + scopeInfo: scope, + cameraAction: cameraAction) + + let depositDest = DepositIbanV(stack: stack.push(), + balances: balances, + selectedBalance: $selectedBalance, + feeLabel: nil, + feeIsNotZero: nil, + // depositIBAN: $depositIBAN, + // accountHolder: $accountHolder, + amountToTransfer: $amountToTransfer) + + let manualWithdrawDest = ManualWithdraw(stack: stack.push(), + balances: balances, + selectedBalance: $selectedBalance, + isSheet: false, + scopeInfo: scope, + exchange: $myExchange, + amountToTransfer: $amountToTransfer) + ZStack(alignment: .bottom) { TabView(selection: tabSelection()) { NavigationView { BalancesListView(stack: stack.push(balancesTitle), balances: $balances, + selectedBalance: $selectedBalance, // shouldReloadPending: $shouldReloadPending, shouldReloadBalances: $shouldReloadBalances, cameraAction: cameraAction) .navigationTitle(balancesTitle) + .background( Group { + NavigationLink(destination: sendDest, tag: 1, selection: $actionSelected) + { EmptyView() }.frame(width: 0).opacity(0).hidden() + NavigationLink(destination: requestDest, tag: 2, selection: $actionSelected) + { EmptyView() }.frame(width: 0).opacity(0).hidden() + NavigationLink(destination: depositDest, tag: 3, selection: $actionSelected) + { EmptyView() }.frame(width: 0).opacity(0).hidden() + NavigationLink(destination: manualWithdrawDest, tag: 4, selection: $actionSelected) + { EmptyView() }.frame(width: 0).opacity(0).hidden() + }) + .onNotification(.SendAction) { actionSelected = 1 } + .onNotification(.RequestAction) { actionSelected = 2 } + .onNotification(.DepositAction) { actionSelected = 3 } + .onNotification(.WithdrawAction) { actionSelected = 4 } }.id(viewState.rootViewId) // any change to rootViewId triggers popToRootView behaviour .navigationViewStyle(.stack) .tag(Tab.balances) -// .badge(0) // TODO: set badge if transaction finished in background (not here, but in the overlayed tabView instead) - EmptyView() - .tag(Tab.actions) -// if balances.count > 1 { -// let overviewTitle = Tab.overview.title -// NavigationView { -// OverviewListV(stack: stack.push(overviewTitle), -// balances: $balances, -// shouldReloadPending: $shouldReloadPending, -// shouldReloadBalances: $shouldReloadBalances, -// cameraAction: cameraAction) -// .navigationTitle(overviewTitle) -// }.id(viewState2.rootViewId) // any change to rootViewId triggers popToRootView behaviour -// .navigationViewStyle(.stack) -// .tag(Tab.overview) -// } + EmptyView().tag(Tab.actions) NavigationView { SettingsView(stack: stack.push(), @@ -340,9 +392,13 @@ extension MainView { .navigationViewStyle(.stack) .tag(Tab.settings) } // TabView - .padding(.bottom, 16) +// .ignoresSafeArea(.keyboard, edges: .bottom) +// .padding(.bottom, 10) tabBarView +// .ignoresSafeArea(.keyboard, edges: .bottom) } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .onNotification(.KYCrequired) { notification in // show an alert with the KYC link (button) which opens in Safari if let transition = notification.userInfo?[TRANSACTIONTRANSITION] as? TransactionTransition { diff --git a/TalerWallet1/Views/Sheets/QRSheet.swift b/TalerWallet1/Views/Sheets/QRSheet.swift @@ -10,6 +10,9 @@ import AVFoundation struct QRSheet: View { private let symLog = SymLogV(0) let stack: CallStack + @Binding var balances: [Balance] + @Binding var selectedBalance: Balance? + @State private var scannedCode: String? func codeToURL(_ code: String) -> URL? { @@ -32,7 +35,10 @@ struct QRSheet: View { if let scannedURL = codeToURL(scannedCode!) { let scheme = scannedURL.scheme if scheme?.lowercased() == "taler" { - URLSheet(stack: stack.push(), urlToOpen: scannedURL) + URLSheet(stack: stack.push(), + balances: $balances, + selectedBalance: $selectedBalance, + urlToOpen: scannedURL) } else { // let _ = print(scannedURL) // TODO: error logging ErrorView(errortext: scannedURL.absoluteString) diff --git a/TalerWallet1/Views/Sheets/URLSheet.swift b/TalerWallet1/Views/Sheets/URLSheet.swift @@ -12,7 +12,8 @@ import SymLog struct URLSheet: View { private let symLog = SymLogV(0) let stack: CallStack - let navTitle = String(localized: "Checking Link") + @Binding var balances: [Balance] + @Binding var selectedBalance: Balance? var urlToOpen: URL @AppStorage("shouldShowWarning") var shouldShowWarning: Bool = true @@ -22,6 +23,8 @@ struct URLSheet: View { @State private var showAlert: Bool = false @State private var urlCommand: UrlCommand = .unknown + let navTitle = String(localized: "Checking Link") + var body: some View { #if PRINT_CHANGES let _ = Self._printChanges() @@ -31,12 +34,14 @@ struct URLSheet: View { Group { switch urlCommand { - case .withdraw: + case .termsExchange, // TODO: just check the ToS + .withdraw: WithdrawURIView(stack: stack.push(), url: urlToOpen) case .withdrawExchange: - WithdrawExchangeV(stack: stack.push(), url: urlToOpen) - case .termsExchange: - WithdrawExchangeV(stack: stack.push(), url: urlToOpen) // TODO: just check the ToS + WithdrawExchangeV(stack: stack.push(), + balances: $balances, + selectedBalance: $selectedBalance, + url: urlToOpen) case .pay: PaymentView(stack: stack.push(), url: urlToOpen, template: false, amountToTransfer: $amountToTransfer, summary: $summary, diff --git a/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift b/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift @@ -9,10 +9,12 @@ import SwiftUI import taler_swift import SymLog +// Will be called when a withdraw-exchange QR was scanned struct WithdrawExchangeV: View { private let symLog = SymLogV(0) let stack: CallStack - let navTitle = String(localized: "Checking Link") + @Binding var balances: [Balance] + @Binding var selectedBalance: Balance? var url: URL @EnvironmentObject private var controller: Controller @@ -21,6 +23,8 @@ struct WithdrawExchangeV: View { @State private var exchange: Exchange? = nil @State private var currencyInfo: CurrencyInfo = CurrencyInfo.zero(UNKNOWN) + let navTitle = String(localized: "Checking Link") + var body: some View { #if PRINT_CHANGES let _ = Self._printChanges() @@ -30,6 +34,8 @@ struct WithdrawExchangeV: View { let currency = exchange.scopeInfo.currency Group { ManualWithdraw(stack: stack.push(), + balances: balances, + selectedBalance: $selectedBalance, // currencyInfo: $currencyInfo, isSheet: true, scopeInfo: exchange.scopeInfo, diff --git a/TalerWallet1/Views/Transactions/TransactionsListView.swift b/TalerWallet1/Views/Transactions/TransactionsListView.swift @@ -16,6 +16,8 @@ fileprivate let showUpDown = 25 // show up+down buttons in the menubar if li struct TransactionsListView: View { private let symLog = SymLogV(0) let stack: CallStack + let balance: Balance // this is the currency to be used + @Binding var selectedBalance: Balance? // <- return here the balance when we go to Transactions @Binding var currencyInfo: CurrencyInfo let navTitle: String @@ -65,7 +67,7 @@ struct TransactionsListView: View { } }) } - } // ScrollView + } // ScrollViewReader .navigationTitle(navTitle) .accessibilityHint(String(localized: "Transaction list")) .task { @@ -79,6 +81,7 @@ struct TransactionsListView: View { } .onAppear { DebugViewC.shared.setViewID(VIEW_TRANSACTIONLIST, stack: stack.push()) + selectedBalance = balance // balance fixed for send/request/deposit/withdraw } } }