taler-ios

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

commit 7db417ef17060c98b96a6622f47aa498895bd71b
parent 834249a7ca6351f0ec851eceb96ca803a8c1d264
Author: Marc Stibane <marc@taler.net>
Date:   Fri,  9 May 2025 21:38:33 +0000

OIM action buttons

Diffstat:
MTalerWallet1/Views/OIM/OIMView.swift | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
MTalerWallet1/Views/OIM/OIMactionButtons.swift | 43++++++++++++++++++++++++++++++++++++++-----
2 files changed, 117 insertions(+), 43 deletions(-)

diff --git a/TalerWallet1/Views/OIM/OIMView.swift b/TalerWallet1/Views/OIM/OIMView.swift @@ -8,6 +8,9 @@ import SwiftUI import taler_swift +let OIMbuttonSize = 80.0 +let OIMactionSize = 120.0 + // MARK: - struct OIMnavBack<Content: View>: View { let stack: CallStack @@ -36,13 +39,13 @@ struct OIMnavBack<Content: View>: View { dismiss() } } - .frame(width: 66, height: 66) + .frame(width: OIMbuttonSize, height: OIMbuttonSize) Spacer() - OIMsendButton(isGoal: isGoal, + OIMactionButton(type: isGoal ? .goal : .sendP2P, isFinal: isFinal, enabled: !amount.isZero, action: action) - .frame(width: 66, height: 66) + .frame(width: OIMbuttonSize, height: OIMbuttonSize) .matchedGeometryEffect(id: isSending ? "OIMaction" : "OIMaction2", in: wrapper.namespace, isSource: false) } @@ -62,13 +65,14 @@ struct OIMtitleView: View { @EnvironmentObject private var wrapper: NamespaceWrapper var body: some View { - HStack { + HStack(alignment: .top) { // invisible - only serves as point where the selected balance chest moves to OIMbalanceButton(isOpen: true, isSierra: false, isFinal: false) {} - .frame(width: 66, height: 66) + .frame(width: OIMbuttonSize, height: OIMbuttonSize) .disabled(true) .opacity(0.01) .matchedGeometryEffect(id: "OIMnumber", in: wrapper.namespace, isSource: true) + .accessibilityHidden(true) OIMamountV(amount: amount, currencyName: cash.currency.noteBase) @@ -77,11 +81,12 @@ struct OIMtitleView: View { OIMamountV(amount: secondAmount, currencyName: cash.currency.noteBase) } - OIMsendButton(isGoal: false, isFinal: false, enabled: false) {} - .frame(width: 66, height: 66) + OIMactionButton(type: .sendP2P, isFinal: false, enabled: false) {} + .frame(width: OIMbuttonSize, height: OIMbuttonSize) .disabled(true) .opacity(0.01) .matchedGeometryEffect(id: "OIMaction", in: wrapper.namespace, isSource: true) + .accessibilityHidden(true) } } @@ -101,11 +106,17 @@ struct OIMView: View { @StateObject private var cash = OIMcash() @State private var availableVal: UInt64 = 0 @State private var tappedVal: UInt64 = 0 - @State private var sending = false // user tapped on Send @State private var available: Amount? = nil - @State private var isOpen: Int? = nil + @State private var chestOpen: Int? = nil + @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 + + func noAction() { } func sendAction() { + withAnimation(.basicFast) { + showingActions = false // + } // let delay = cash.moveDown() // cash animates itself // withAnimation(.basic1.delay(delay + 0.5)) { @@ -125,10 +136,11 @@ struct OIMView: View { func close() { withAnimation(.basic1) { - isOpen = nil + chestOpen = nil selectedBalance = nil selectedIndex = nil available = nil + showingActions = false } } @@ -139,41 +151,60 @@ struct OIMView: View { let enabled = if let available { !available.isZero } else { false } - let actions = HStack(alignment: .top) { + let topButtons = HStack(alignment: .top) { QRButton(hideTitle: true) { qrButtonTapped = true } .opacity(sending ? 0.01 : 1.0) - .frame(width: 66, height: 66) + .frame(width: OIMbuttonSize, height: OIMbuttonSize) .matchedGeometryEffect(id: "OIMback", in: wrapper.namespace, isSource: true) Spacer() // OIMsendButton(isGoal: false, isFinal: false, enabled: enabled, action: sendAction) -// .frame(width: 66, height: 66) +// .frame(width: OIMbuttonSize, height: OIMbuttonSize) } let maxAvailable = cash.max(available: available?.centValue ?? 0) // let _ = print("maxAvailable", maxAvailable) + let botButtons = HStack() { + let buttons: [OIMactions] = [.deposit, .withdrawal, .requestP2P, .sendP2P].shuffled() + Spacer() + ForEach(buttons, id: \.self) { button in + let action = switch button { + case .sendP2P: sendAction + case .withdrawal: noAction + case .deposit: noAction + case .requestP2P: noAction + case .goal: noAction + } + OIMactionButton(type: button, isFinal: false, + enabled: true, action: action) + .frame(width: OIMactionSize, height: OIMactionSize) + Spacer() + } + } + OIMbackground() { ZStack(alignment: .top) { - actions + topButtons VStack { OIMtitleView(cash: cash, amount: available, isSending: sending, secondAmount: nil) Spacer() + let isOpen = chestOpen != nil OIMlineView(stack: stack.push(), cash: cash, amountVal: $availableVal, tappedVal: $tappedVal, canEdit: false) - .matchedGeometryEffect(id: "OIMline", in: wrapper.namespace, isSource: true) - .onTapGesture { sendAction() } + .opacity(isOpen ? 1.0 : 0.01) + .onTapGesture { close() } Spacer() - } -// .border(.red) - + botButtons + .opacity(showingActions ? 1.0 : 0.01) + } // title, money, buttons VStack { - // this shows the two savings boxes (Euro and Sierra Leone) + // two savings chests (Euro and Sierra Leone) Spacer() HStack(spacing: 30) { // ForEach(controller.balances, id: \.self) { balance in @@ -181,19 +212,24 @@ struct OIMView: View { let balance = controller.balances[0] ForEach(0...1, id: \.self) { index in - let itsMe = isOpen == index - let isClosed = isOpen == nil - let size = isClosed ? 120.0 : 66.0 + let itsMe = chestOpen == index + let isClosed = chestOpen == nil + let size = isClosed ? 160.0 : OIMbuttonSize OIMbalanceButton(isOpen: itsMe, isSierra: index > 0, isFinal: false) { if itsMe { close() - } else { withAnimation(.basic1) { - isOpen = index - selectedIndex = index - cash.currency = index == 0 ? OIMeuros : OIMleones - selectedBalance = balance - available = balance.available - } } + } else { + withAnimation(.basic1) { + chestOpen = index + selectedIndex = index + cash.currency = index == 0 ? OIMeuros : OIMleones + selectedBalance = balance + available = balance.available + } + withAnimation(.basic1.delay(0.3)) { + showingActions = true + } + } } .frame(width: size, height: size) .zIndex(itsMe ? 3 : 0) @@ -205,7 +241,8 @@ struct OIMView: View { } } Spacer() - } // two boxes + } // two chests + VStack { Spacer() OIMcurrencyScroller(stack: stack.push(), @@ -222,17 +259,21 @@ struct OIMView: View { } } } - .task(id: isOpen) { - availableVal = available?.centValue ?? 0 - cash.update(availableVal) // set cash to available -// let maxAvailable = cash.max(available: availableVal) -// print("OIMView.task availableVal", availableVal, maxAvailable) - debugTick += 1 + .task(id: chestOpen) { + if chestOpen != nil { + availableVal = available?.centValue ?? 0 + cash.update(availableVal) // set cash to available + let maxAvailable = cash.max(available: availableVal) + print("OIMView.task availableVal", availableVal, maxAvailable) + debugTick += 1 + } } .onAppear { - if (isOpen != nil) { + showingActions = false + if (chestOpen != nil) { let balance = controller.balances[0] available = balance.available + showingActions = true } availableVal = available?.centValue ?? 0 cash.update(availableVal) // set cash to available diff --git a/TalerWallet1/Views/OIM/OIMactionButtons.swift b/TalerWallet1/Views/OIM/OIMactionButtons.swift @@ -7,15 +7,29 @@ */ import SwiftUI -struct OIMsendButton: View { - let isGoal: Bool +enum OIMactions { + case withdrawal + case deposit + case sendP2P + case requestP2P + case goal +// case scanQR +} + +struct OIMactionButton: View { + let type: OIMactions let isFinal: Bool let enabled: Bool let action: () -> Void var body: some View { - let imageName = isGoal ? "noun-football-goal-4935574" - : "SendMoney" // "SendTaler" + let imageName = switch type { + case .goal: "Goal" + case .sendP2P : "SendMoney" // "SendTaler" + case .withdrawal: "Withdraw" + case .deposit: "Deposit" + case .requestP2P: "Request" + } Button(action: action) { Image(imageName) .resizable() @@ -23,7 +37,26 @@ struct OIMsendButton: View { // .tint(WalletColors().talerColor) .foregroundStyle(WalletColors().talerColor) } - .tagStyle(isFinal ? .prominent : .borderless) + .tagStyle(isFinal ? .bordered : .borderless) + .opacity(enabled ? 1.0 : 0.01) + .disabled(!enabled) + } +} + +struct OIMrequestButton: View { + let enabled: Bool + let action: () -> Void + + var body: some View { + let imageName = "Request.png" // "SendTaler" + Button(action: action) { + Image(imageName) + .resizable() + .scaledToFit() +// .tint(WalletColors().talerColor) + .foregroundStyle(WalletColors().talerColor) + } + .tagStyle(.bordered) .opacity(enabled ? 1.0 : 0.01) .disabled(!enabled) }