taler-ios

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

IconBadge.swift (8068B)


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