IconBadge.swift (7258B)
1 /* 2 * This file is part of GNU Taler, ©2022-25 Taler Systems S.A. 3 * See LICENSE.md 4 */ 5 /** 6 * @author Marc Stibane 7 */ 8 import SwiftUI 9 10 struct PendingIconBadge: View { 11 let foreColor:Color 12 let done: Bool 13 let incoming: Bool 14 let shouldConfirm: Bool 15 let needsKYC: Bool 16 17 var body: some View { 18 let image = incoming && done ? Image(systemName: DONE_INCOMING) // "plus.circle.fill" 19 : incoming ? Image(systemName: PENDING_INCOMING) // "plus" 20 // since outgoing money already left the wallet, show DONE_ and not PENDING_OUTGOING 21 : Image(systemName: DONE_OUTGOING) // "minus.circle" 22 IconBadge(image: image, 23 done: false, 24 foreColor: foreColor, 25 shouldConfirm: shouldConfirm, 26 needsKYC: needsKYC, 27 phase: 0, 28 firstImage: nil, 29 secondImage: nil, 30 wideIcon: nil) 31 } 32 } 33 // MARK: - 34 struct TransactionIconBadge: View { 35 var type: TransactionType 36 var foreColor: Color 37 let done: Bool 38 let incoming: Bool 39 let shouldConfirm: Bool 40 let needsKYC: Bool 41 42 init(type: TransactionType, foreColor: Color, done: Bool, incoming: Bool, shouldConfirm: Bool, needsKYC: Bool) { 43 self.type = type 44 self.foreColor = foreColor 45 self.done = done 46 self.incoming = incoming 47 self.shouldConfirm = shouldConfirm 48 self.needsKYC = needsKYC 49 } 50 51 init(from transaction: TalerTransaction, isDark: Bool, _ increasedContrast: Bool) { 52 let common = transaction.common 53 self.type = common.type 54 let done = transaction.isDone 55 self.done = done 56 let incoming = common.isIncoming 57 self.incoming = incoming 58 let needsKYC = transaction.isPendingKYC || transaction.isPendingKYCauth 59 self.needsKYC = needsKYC 60 self.shouldConfirm = transaction.shouldConfirm 61 let pending = transaction.isPending || transaction.common.isFinalizing 62 self.foreColor = .primary 63 64 let doneOrPending = done || pending 65 let isZero = common.amountEffective.isZero 66 let refreshZero = common.type.isRefresh && isZero 67 let textColor = doneOrPending ? .primary 68 : isDark ? .secondary 69 : increasedContrast ? Color(.darkGray) 70 : .secondary // Color(.tertiaryLabel) 71 let foreColor = refreshZero ? textColor 72 : pending ? WalletColors().pendingColor(incoming) 73 : done ? WalletColors().transactionColor(incoming) 74 : WalletColors().uncompletedColor 75 self.foreColor = foreColor 76 } 77 78 var body: some View { 79 IconBadge(image: type.icon(done), 80 done: true, 81 foreColor: foreColor, 82 shouldConfirm: shouldConfirm, 83 needsKYC: needsKYC, 84 phase: 0, 85 firstImage: nil, 86 secondImage: nil, 87 wideIcon: TransactionType.refund.icon()) 88 // "arrowshape.turn.up.backward" is wider than all others 89 } 90 } 91 // MARK: - 92 struct ButtonIconBadge: View { 93 let type: TransactionType 94 let phase: Int 95 let foreColor:Color 96 let done: Bool 97 98 var body: some View { 99 let isSend = type.isSendCoins 100 let isRcve = type.isSendInvoice 101 let isDepo = type.isDeposit 102 let isWthd = type.isWithdrawal 103 let left = ICONNAME_PERSON_LEFT + ICONNAME_FILL 104 let right = ICONNAME_PERSON_RIGHT 105 let bottom = ICONNAME_PERSON_BOTTOM + ICONNAME_FILL 106 let top = ICONNAME_BANK 107 let firstImage = isSend ? Image(left) 108 : isRcve ? Image(right) 109 : isDepo ? Image(bottom) 110 : isWthd ? Image(top) : nil 111 let secondImage = isSend ? Image(right) 112 : isRcve ? Image(left) 113 : isDepo ? Image(top) 114 : isWthd ? Image(bottom) : nil 115 IconBadge(image: type.icon(done), 116 done: true, 117 foreColor: foreColor, 118 shouldConfirm: false, 119 needsKYC: false, 120 phase: phase, 121 firstImage: firstImage, 122 secondImage: secondImage, 123 wideIcon: TransactionType.peerPushDebit.icon()) 124 // button is send/receive/withdraw/deposit, never payment or refund 125 } 126 } 127 // MARK: - 128 struct IconBadge: View { 129 let image: Image 130 let done: Bool 131 let foreColor:Color 132 let shouldConfirm: Bool 133 let needsKYC: Bool 134 let phase: Int 135 let firstImage: Image? 136 let secondImage: Image? 137 let wideIcon: Image? // cheating: ZStack with widest icon to ensure all have the same width 138 // TODO: EqualIconWidth... 139 140 @ScaledMetric var spacing = 6 // relative to fontSize 141 @State private var showFirst = false 142 @State private var showSecond = false 143 @State private var showImage = true 144 145 var body: some View { 146 // let _ = Self._printChanges() 147 HStack(alignment: .top, spacing: -spacing) { 148 ZStack { 149 if let wideIcon { 150 wideIcon.foregroundColor(.clear) 151 } 152 if let firstImage, let secondImage { 153 let duration = 0.66 154 ZStack { 155 image.opacity(showImage ? 1 : 0) 156 .animation(.easeInOut(duration: duration), value: showImage) 157 firstImage.opacity(showFirst ? 1 : 0) 158 .animation(.easeOut(duration: duration), value: showFirst) 159 secondImage.opacity(showSecond ? 1 : 0) 160 .animation(.easeIn(duration: duration), value: showSecond) 161 } .foregroundColor(foreColor) 162 .onChange(of: phase) { phaseVal in 163 switch phaseVal { 164 case 0, 4: showFirst = false; showSecond = false; showImage = true 165 case 2, 3: showFirst = true; showSecond = false; showImage = false 166 case 5, 6: showFirst = false; showSecond = true; showImage = false 167 default: showFirst = false; showSecond = false; showImage = false 168 } 169 } 170 } else { 171 image.foregroundColor(foreColor) 172 } 173 } 174 // ZStack centers the main icon, so the badge will always be at the same position 175 let badgeName = needsKYC ? NEEDS_KYC 176 : CONFIRM_BANK 177 Image(systemName: badgeName) 178 .talerFont(.badge) 179 .foregroundColor(needsKYC ? WalletColors().attention 180 : shouldConfirm ? WalletColors().confirm 181 : .clear) 182 .padding(.top, -2) 183 }.accessibilityHidden(true) 184 } 185 } 186 // MARK: - 187 //#Preview { 188 // IconBadge() 189 //}