taler-ios

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

commit 93fc94c554e2e3b819090e552d1f4d40c170aa8a
parent 4ae2fddf0403975d3f116a06101b9d57783c972f
Author: Marc Stibane <marc@taler.net>
Date:   Wed, 23 Jul 2025 08:24:24 +0200

tx history

Diffstat:
MTalerWallet1/Views/OIM/OIMtransactions.swift | 169++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 120 insertions(+), 49 deletions(-)

diff --git a/TalerWallet1/Views/OIM/OIMtransactions.swift b/TalerWallet1/Views/OIM/OIMtransactions.swift @@ -17,6 +17,34 @@ enum OIMtransactionsState { case historyTapped } + +struct OIMhistoryItem: View { + let talerTX: TalerTransaction + + @Environment(\.colorScheme) private var colorScheme + @Environment(\.colorSchemeContrast) private var colorSchemeContrast + + var body: some View { + let common = talerTX.common + let value = common.amountEffective.valueStr + let incoming = common.incoming() + let isDark = colorScheme == .dark + let increasedContrast = colorSchemeContrast == .increased + let badge = TransactionIconBadge(from: talerTX, isDark: isDark, increasedContrast) + .talerFont(.largeTitle) + let amount = Text("\(value)") + .talerFont(.title1) + VStack { + if incoming { + badge + amount + } else { + amount + badge + } + } + } +} // MARK: - @available(iOS 16.4, *) struct OIMtransactions: View { @@ -24,6 +52,7 @@ struct OIMtransactions: View { // let decimal: Int // 0 for ¥,HUF; 2 for $,€,£; 3 for ﷼,₯ (arabic) let balance: Balance // this is the currency to be used let cash: OIMcash + let history: [TalerTransaction] @Environment(\.dismiss) var dismiss // pop back once @EnvironmentObject private var controller: Controller @@ -34,73 +63,114 @@ struct OIMtransactions: View { @State private var viewState: OIMtransactionsState = .chestIsOpen // @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 + @State private var talerTXs: [TalerTransaction] = [] 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 + let delay0 = hideHistoryItems(Animation.talerDelay0) + DispatchQueue.main.asyncAfter(deadline: .now() + delay0) { + let delay = cash.flyOneByOne(to: .idle) // back to center + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + print("closeHistory", delay) + withAnimation(.basic1) { + viewState = .chestIsOpen + } + DispatchQueue.main.asyncAfter(deadline: .now() + Animation.talerDuration2) { + var transaction = Transaction() + transaction.disablesAnimations = true + withTransaction(transaction) { + dismiss() + } + } } - DispatchQueue.main.asyncAfter(deadline: .now() + Animation.talerDuration2) { - var transaction = Transaction() - transaction.disablesAnimations = true - withTransaction(transaction) { - dismiss() + } + } + + @discardableResult + func hideHistoryItems(_ interval: TimeInterval = 0) -> TimeInterval { + var delay = 0.0 + var count = talerTXs.count + while count > 0 { + if interval > 0 { + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + withAnimation { + talerTXs.removeLast() + return // Conflicting arguments to generic parameter 'Result' ('Void' vs …) + } } + delay += interval + } else { + talerTXs.removeLast() } + count -= 1 } + return delay + } + + @discardableResult + func showHistoryItems(_ interval: TimeInterval = 0) -> TimeInterval { + var delay = 0.0 + for talerTX in history { + if interval > 0 { + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + withAnimation { + talerTXs.append(talerTX) + } + } + delay += interval + } else { + talerTXs.append(talerTX) + } + } + return delay } var body: some View { var debugTick = 0 // let _ = Self._printChanges() - let sidePosition = HStack { - Spacer() - Color.clear - .frame(width: 80, height: 80) - .matchedGeometryEffect(id: OIMSIDE, in: wrapper.namespace, isSource: true) - } - OIMbackground() { - ZStack(alignment: .top) { - VStack { - OIMtitleView(cash: cash, - amount: available, - history: true, //viewState == .historyShown, - secondAmount: nil) - Spacer() - - ZStack { - sidePosition -// let scaleMoney = viewState == .chestIsOpen - OIMlineView(stack: stack.push(), - cash: cash, - amountVal: $availableVal, - canEdit: false) -// .opacity(isOpen ? 1 : INVISIBLE) -// .scaleEffect(scaleMoney ? 0.6 : 1.0) - .onTapGesture { - closeHistory() - } - } - Spacer() - } // title, money - - VStack { - Spacer() - HStack(spacing: 30) { - ZStack { + let sidePosition = Color.clear + .frame(width: 80, height: 80) + .matchedGeometryEffect(id: OIMSIDE, in: wrapper.namespace, isSource: true) + OIMbackground() { + VStack { + OIMtitleView(cash: cash, + amount: available, + history: true, //viewState == .historyShown, + secondAmount: nil) + Spacer(minLength: 0) + ZStack { + HStack { + ScrollView(.horizontal) { + LazyHStack { + ForEach(talerTXs) { talerTX in + OIMhistoryItem(talerTX: talerTX) + .flippedLeftRight() + .padding(.horizontal) +// .transition(.backslide) + Spacer() + } } - + //.border(.red) + }.flippedLeftRight() + sidePosition + .padding(.leading, 35) + }// .border(.blue) + OIMlineView(stack: stack.push(), + cash: cash, + amountVal: $availableVal, + canEdit: false) +// .opacity(isOpen ? 1 : INVISIBLE) +// .scaleEffect(scaleMoney ? 0.6 : 1.0) + .onTapGesture { + closeHistory() } - Spacer() - } // two chests - } + } + Spacer(minLength: 0) + } // title, HStack } .onAppear { available = balance.available @@ -108,6 +178,7 @@ struct OIMtransactions: View { cash.update2(availableVal) // set cash to available cash.setTarget(.history) debugTick += 1 + showHistoryItems(Animation.talerDelay0) } .onDisappear { // cash.moveBack()