commit 2f5143cf79f5c969368b33f8776c13b8b78412b1
parent ad4af19d80b899f9c3515121fc3ca7371a789e9f
Author: Marc Stibane <marc@taler.net>
Date: Wed, 23 Jul 2025 09:06:58 +0200
for history
Diffstat:
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