taler-ios

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

commit 2f5143cf79f5c969368b33f8776c13b8b78412b1
parent ad4af19d80b899f9c3515121fc3ca7371a789e9f
Author: Marc Stibane <marc@taler.net>
Date:   Wed, 23 Jul 2025 09:06:58 +0200

for history

Diffstat:
MTalerWallet1/Views/OIM/OIMbalances.swift | 83+++++++++++++++++++++++++++++++++++++------------------------------------------
MTalerWallet1/Views/Transactions/TransactionsListView.swift | 142+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
2 files changed, 128 insertions(+), 97 deletions(-)

diff --git a/TalerWallet1/Views/OIM/OIMbalances.swift b/TalerWallet1/Views/OIM/OIMbalances.swift @@ -24,6 +24,7 @@ enum OIMbalancesState { case historyShown case historyTapped } + // MARK: - @available(iOS 16.4, *) struct OIMbalances: View { @@ -38,15 +39,10 @@ struct OIMbalances: View { @StateObject private var cash = OIMcash(OIMeuros) @State private var availableVal: UInt64 = 0 - @State private var tappedVal: UInt64 = 0 + @State private var tappedVal: UInt64 = 0 // unused, canEdit == false @State private var available: Amount? = nil - @State private var chestOpen: Int? = nil @State private var viewState: OIMbalancesState = .chestsClosed -// @State private var showingActions = false // set true after user opened a chest, set false when choosing an action -// @State private var sending = false // after user tapped on Send or on the money - @State private var closing = false // after user tapped on the open chest - - func noAction() { } + @State private var closing = false // debounce tap (on open chest to close it) @State private var balanceIndex: Int? = nil func requestTapped() { @@ -55,17 +51,12 @@ struct OIMbalances: View { func sendTapped() { withAnimation(.basicFast) { -// showingActions = false // viewState = .sendTapped } -// let delay = cash.moveDown() // cash animates itself cash.flyOneByOne(to: .drawer) -// withAnimation(.basic1.delay(delay + 0.5)) { withAnimation(.basic1.delay(0.6)) { -// sending = true // blends in the missing denominations - viewState = .sending + viewState = .sending // go to edit view, blend in missing denominations in drawer } -// DispatchQueue.main.asyncAfter(deadline: .now() + delay + 1) { // cash.delay DispatchQueue.main.asyncAfter(deadline: .now() + 1.2) { let actionType = ActionType(animationDisabled: true) let userinfo = [NOTIFICATIONANIMATION: actionType] @@ -84,10 +75,8 @@ struct OIMbalances: View { DispatchQueue.main.asyncAfter(deadline: .now() + delay) { print("closeChest", delay) withAnimation(.basic1) { - chestOpen = nil selectedBalance = nil available = nil -// showingActions = false viewState = .chestsClosed } closing = false @@ -110,7 +99,6 @@ struct OIMbalances: View { #endif viewState = .chestOpenTapped withAnimation(.basic1) { - chestOpen = index selectedBalance = balance balanceIndex = index viewState = .chestIsOpen @@ -124,18 +112,18 @@ struct OIMbalances: View { } } - func closeHistory() { - withAnimation(.basic1) { - viewState = .historyTapped - } - let delay = cash.flyOneByOne(to: .idle) // back to center - DispatchQueue.main.asyncAfter(deadline: .now() + delay) { - print("closeHistory", delay) - withAnimation(.basic1) { - viewState = .chestIsOpen - } - } - } +// func closeHistory() { +// withAnimation(.basic1) { +// viewState = .historyTapped +// } +// let delay = cash.flyOneByOne(to: .idle) // back to center +// DispatchQueue.main.asyncAfter(deadline: .now() + delay) { +// print("closeHistory", delay) +// withAnimation(.basic1) { +// viewState = .chestIsOpen +// } +// } +// } func openHistory() { viewState = .balanceTapped @@ -159,6 +147,12 @@ struct OIMbalances: View { } } + func initView() { + availableVal = 0 + cash.update2(availableVal) // set cash to 0 + viewState = .chestsClosed + } + var body: some View { var debugTick = 0 // let _ = Self._printChanges() @@ -218,20 +212,14 @@ struct OIMbalances: View { .opacity(isOpen ? 1 : INVISIBLE) // .scaleEffect(scaleMoney ? 0.6 : 1) .onTapGesture { - if viewState == .historyShown { - closeHistory() - } else { - openHistory() - } + openHistory() } } Spacer() -// botButtons -// .opacity(showingActions ? 1.0 : 0.01) - } // title, money, buttons + } // title on top, money in the middle VStack { - // two savings chests (Euro and Sierra Leone) + // three savings chests (Euro, Sierra Leone, Côte d'Ivoire) Spacer() HStack(spacing: 30) { ForEach(Array(controller.balances.enumerated()), id: \.element) { index, balance in @@ -262,7 +250,7 @@ struct OIMbalances: View { } } Spacer() - } // two chests + } // three chests VStack { Spacer() @@ -270,7 +258,7 @@ struct OIMbalances: View { OIMcurrencyDrawer(stack: stack.push(), cash: cash, availableVal: $availableVal, - tappedVal: $tappedVal, + tappedVal: $tappedVal, // unused, since canEdit == false scrollPosition: maxAvailable, canEdit: false) .clipped(antialiased: true) @@ -286,16 +274,23 @@ struct OIMbalances: View { available = selectedBalance.available availableVal = available?.centValue ?? 0 cash.update2(availableVal) // set cash to available -// showingActions = true + if viewState == .historyTapped { + withAnimation(.basic1) { + viewState = .chestIsOpen + } + } } else { - availableVal = 0 - cash.update2(availableVal) // set cash to available + initView() } debugTick += 1 } .onDisappear { - cash.moveBack() -// sending = false + if (selectedBalance != nil) { + cash.moveBack() + viewState = .chestIsOpen + } else { + initView() + } } } } diff --git a/TalerWallet1/Views/Transactions/TransactionsListView.swift b/TalerWallet1/Views/Transactions/TransactionsListView.swift @@ -30,69 +30,105 @@ struct TransactionsListView: View { @Environment(\.colorSchemeContrast) private var colorSchemeContrast @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic @State private var viewId = UUID() + @StateObject private var cash: OIMcash + @Namespace var namespace + init(stack: CallStack, + scope: ScopeInfo, + balance: Balance, + selectedBalance: Binding<Balance?>, + navTitle: String?, + transactions: Binding<[TalerTransaction]>, + reloadAllAction: @escaping (_ stack: CallStack) async -> () + ) { + // SwiftUI ensures that the initialization uses the + // closure only once during the lifetime of the view, so + // later changes to the currency have no effect. + self.stack = stack + self.scope = scope + self.balance = balance + self.navTitle = navTitle + self._transactions = transactions + self.reloadAllAction = reloadAllAction + self._selectedBalance = selectedBalance + let oimCurrency = oimCurrency(balance) + let oimCash = OIMcash(oimCurrency) + self._cash = StateObject(wrappedValue: { oimCash }()) + } var body: some View { #if PRINT_CHANGES let _ = Self._printChanges() let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear #endif - let count = transactions.count - ScrollViewReader { scrollView in - List { - Section { - TransactionsArraySliceV(symLog: symLog, - stack: stack.push(), - scope: scope, - transactions: $transactions, - reloadAllAction: reloadAllAction) - .padding(.leading, ICONLEADING) - } header: { - let header = scope.url?.trimURL ?? scope.currency - Text(header) - .talerFont(.title3) - .foregroundColor(WalletColors().secondary(colorScheme, colorSchemeContrast)) - } - } - .id(viewId) - .listStyle(myListStyle.style).anyView - .refreshable { - controller.hapticNotification(.success) - symLog.log("refreshing") - await reloadAllAction(stack.push()) - } -#if false // SCROLLBUTTONS - .if(count > showUpDown) { view in - view.navigationBarItems(trailing: HStack { - ArrowUpButton { -// print("up") - withAnimation { scrollView.scrollTo(0) } + if transactions.isEmpty { + TransactionsEmptyView(stack: stack.push(), currency: scope.currency) + } else { + Group { + ScrollViewReader { scrollView in + let count = transactions.count + List { + Section { + TransactionsArraySliceV(symLog: symLog, + stack: stack.push(), + scope: scope, + transactions: $transactions, + reloadAllAction: reloadAllAction) + .padding(.leading, ICONLEADING) + } header: { + let header = scope.url?.trimURL ?? scope.currency + Text(header) + .talerFont(.title3) + .foregroundColor(WalletColors().secondary(colorScheme, colorSchemeContrast)) + } } - ArrowDownButton { -// print("down") - withAnimation { scrollView.scrollTo(transactions.count - 1) } + .id(viewId) + .listStyle(myListStyle.style).anyView + .refreshable { + controller.hapticNotification(.success) + symLog.log("refreshing") + await reloadAllAction(stack.push()) + } +#if false // SCROLLBUTTONS + .if(count > showUpDown) { view in + view.navigationBarItems(trailing: HStack { + ArrowUpButton { +// print("up") + withAnimation { scrollView.scrollTo(0) } + } + ArrowDownButton { +// print("down") + withAnimation { scrollView.scrollTo(transactions.count - 1) } + } + }) } - }) - } #endif - } // ScrollViewReader -// .navigationTitle("EURO") // Fake EUR instead of the real Currency -// .navigationTitle("CHF") // Fake CHF instead of the real Currency - .navigationTitle(navTitle ?? scope.currency) - .accessibilityHint(String(localized: "Transaction list", comment: "a11y")) - .task { - symLog.log("❗️.task List❗️") - await reloadAllAction(stack.push()) - } - .overlay { - if transactions.isEmpty { - TransactionsEmptyView(stack: stack.push(), currency: scope.currency) + } // ScrollViewReader +// .navigationTitle("EURO") // Fake EUR instead of the real Currency +// .navigationTitle("CHF") // Fake CHF instead of the real Currency + .navigationTitle(navTitle ?? scope.currency) + .accessibilityHint(String(localized: "Transaction list", comment: "a11y")) + .task { + symLog.log("❗️.task List❗️") + await reloadAllAction(stack.push()) + } + .onAppear { + DebugViewC.shared.setViewID(VIEW_TRANSACTIONLIST, stack: stack.push()) + selectedBalance = balance // balance fixed for send/request/deposit/withdraw + } } - } - .onAppear { - DebugViewC.shared.setViewID(VIEW_TRANSACTIONLIST, stack: stack.push()) - selectedBalance = balance // balance fixed for send/request/deposit/withdraw - } - } +#if OIM + .overlay { if #available(iOS 16.4, *) { + if controller.oimModeActive { + OIMtransactions(stack: stack.push(), + balance: balance, + cash: cash, + history: transactions) + .environmentObject(NamespaceWrapper(namespace)) // keep OIMviews apart + } + } } +#endif + } // not empty + } // body } // MARK: - // used by TransactionsListView, and by BalancesSectionView to show the last 3 transactions