IconBadge.swift (7723B)
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 let imageBase64: String? 42 43 init(type: TransactionType, foreColor: Color, done: Bool, incoming: Bool, 44 shouldConfirm: Bool, needsKYC: Bool, imageBase64: String? = nil 45 ) { 46 self.type = type 47 self.foreColor = foreColor 48 self.done = done 49 self.incoming = incoming 50 self.shouldConfirm = shouldConfirm 51 self.needsKYC = needsKYC 52 self.imageBase64 = imageBase64 53 } 54 55 init(from transaction: TalerTransaction, isDark: Bool, _ increasedContrast: Bool, 56 imageBase64: String? = nil 57 ) { 58 let common = transaction.common 59 self.type = common.type 60 let done = transaction.isDone 61 self.done = done 62 let incoming = common.isIncoming 63 self.incoming = incoming 64 let needsKYC = transaction.isPendingKYC || transaction.isPendingKYCauth 65 self.needsKYC = needsKYC 66 self.shouldConfirm = transaction.shouldConfirm 67 let pending = transaction.isPending || transaction.common.isFinalizing 68 self.foreColor = .primary 69 70 let doneOrPending = done || pending 71 let isZero = common.amountEffective.isZero 72 let refreshZero = common.type.isRefresh && isZero 73 let textColor = doneOrPending ? .primary 74 : isDark ? .secondary 75 : increasedContrast ? Color(.darkGray) 76 : .secondary // Color(.tertiaryLabel) 77 let foreColor = refreshZero ? textColor 78 : pending ? WalletColors().pendingColor(incoming) 79 : done ? WalletColors().transactionColor(incoming) 80 : WalletColors().uncompletedColor 81 self.foreColor = foreColor 82 self.imageBase64 = imageBase64 83 } 84 85 var body: some View { 86 if let imageBase64, let image = Image(imageBase64: imageBase64) { 87 image 88 .resizable() 89 .aspectRatio(contentMode: .fit) 90 .frame(maxHeight: 40) 91 } else { 92 IconBadge(image: type.icon(done), 93 done: true, 94 foreColor: foreColor, 95 shouldConfirm: shouldConfirm, 96 needsKYC: needsKYC, 97 phase: 0, 98 firstImage: nil, 99 secondImage: nil, 100 wideIcon: TransactionType.refund.icon()) 101 // "arrowshape.turn.up.backward" is wider than all others 102 } 103 } 104 } 105 // MARK: - 106 struct ButtonIconBadge: View { 107 let type: TransactionType 108 let phase: Int 109 let foreColor:Color 110 let done: Bool 111 112 var body: some View { 113 let isSend = type.isSendCoins 114 let isRcve = type.isSendInvoice 115 let isDepo = type.isDeposit 116 let isWthd = type.isWithdrawal 117 let left = ICONNAME_PERSON_LEFT + ICONNAME_FILL 118 let right = ICONNAME_PERSON_RIGHT 119 let bottom = ICONNAME_PERSON_BOTTOM + ICONNAME_FILL 120 let top = ICONNAME_BANK 121 let firstImage = isSend ? Image(left) 122 : isRcve ? Image(right) 123 : isDepo ? Image(bottom) 124 : isWthd ? Image(top) : nil 125 let secondImage = isSend ? Image(right) 126 : isRcve ? Image(left) 127 : isDepo ? Image(top) 128 : isWthd ? Image(bottom) : nil 129 IconBadge(image: type.icon(done), 130 done: true, 131 foreColor: foreColor, 132 shouldConfirm: false, 133 needsKYC: false, 134 phase: phase, 135 firstImage: firstImage, 136 secondImage: secondImage, 137 wideIcon: TransactionType.peerPushDebit.icon()) 138 // button is send/receive/withdraw/deposit, never payment or refund 139 } 140 } 141 // MARK: - 142 struct IconBadge: View { 143 let image: Image 144 let done: Bool 145 let foreColor:Color 146 let shouldConfirm: Bool 147 let needsKYC: Bool 148 let phase: Int 149 let firstImage: Image? 150 let secondImage: Image? 151 let wideIcon: Image? // cheating: ZStack with widest icon to ensure all have the same width 152 // TODO: EqualIconWidth... 153 154 @ScaledMetric var spacing = 6 // relative to fontSize 155 @State private var showFirst = false 156 @State private var showSecond = false 157 @State private var showImage = true 158 159 var body: some View { 160 // let _ = Self._printChanges() 161 HStack(alignment: .top, spacing: -spacing) { 162 ZStack { 163 if let wideIcon { 164 wideIcon.foregroundColor(.clear) 165 } 166 if let firstImage, let secondImage { 167 let duration = 0.66 168 ZStack { 169 image.opacity(showImage ? 1 : 0) 170 .animation(.easeInOut(duration: duration), value: showImage) 171 firstImage.opacity(showFirst ? 1 : 0) 172 .animation(.easeOut(duration: duration), value: showFirst) 173 secondImage.opacity(showSecond ? 1 : 0) 174 .animation(.easeIn(duration: duration), value: showSecond) 175 } .foregroundColor(foreColor) 176 .onChange(of: phase) { phaseVal in 177 switch phaseVal { 178 case 0, 4: showFirst = false; showSecond = false; showImage = true 179 case 2, 3: showFirst = true; showSecond = false; showImage = false 180 case 5, 6: showFirst = false; showSecond = true; showImage = false 181 default: showFirst = false; showSecond = false; showImage = false 182 } 183 } 184 } else { 185 image.foregroundColor(foreColor) 186 } 187 } 188 // ZStack centers the main icon, so the badge will always be at the same position 189 let badgeName = needsKYC ? NEEDS_KYC 190 : CONFIRM_BANK 191 Image(systemName: badgeName) 192 .talerFont(.badge) 193 .foregroundColor(needsKYC ? WalletColors().attention 194 : shouldConfirm ? WalletColors().confirm 195 : .clear) 196 .padding(.top, -2) 197 }.accessibilityHidden(true) 198 } 199 } 200 // MARK: - 201 //#Preview { 202 // IconBadge() 203 //}