taler-ios

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

commit 84bca0d96683014666b7049b7faf07d33cce2ddf
parent ad147644f1d5708b8b134bd9c61953d580da3c58
Author: Marc Stibane <marc@taler.net>
Date:   Sun, 13 Oct 2024 19:06:24 +0200

arrrow names & icons

Diffstat:
MTalerWallet1/Controllers/PublicConstants.swift | 50++++++++++++++++++++++++++++++++++++++------------
MTalerWallet1/Model/Transaction.swift | 53++++++++++++++++++++++++++++++++++++++++++++---------
MTalerWallet1/Views/HelperViews/IconBadge.swift | 74++++++++++++++++++++++++++++++++++++--------------------------------------
MTalerWallet1/Views/Transactions/TransactionSummaryV.swift | 2+-
4 files changed, 119 insertions(+), 60 deletions(-)

diff --git a/TalerWallet1/Controllers/PublicConstants.swift b/TalerWallet1/Controllers/PublicConstants.swift @@ -35,18 +35,44 @@ public let DONE_INCOMING = "plus.circle.fill" // 􀁌 􀁍 public let DONE_OUTGOING = "minus.circle" // 􀁎 􀁏 1.0 (iOS 13) public let ICONNAME_FILL = ".fill" -public let ICONNAME_DUMMY = "taler.circle" // 􀀀 􀀁 -public let ICONNAME_WITHDRAWAL = "taler.down" // 􁾬 􁾭 -public let ICONNAME_DEPOSIT = "taler.up" // 􁾨 􁾩 -public let ICONNAME_REFUND = "taler.turn.up.backward" // 􀰚 􀰛 -public let ICONNAME_PAYMENT = "taler.turn.up.forward" // 􀉐 􀰟 -public let ICONNAME_INCOMING_P2P = "taler.backward" // 􁉈 􁉅 -public let ICONNAME_OUTGOING_P2P = "taler.forward" // 􁉆 􁉇 -public let ICONNAME_REFRESH = "taler.counterclockwise" // 􁹠 no fill variant! -//public let ICONNAME_REFRESH1 = "arrow.counterclockwise.circle" // 􀚃 􀚄 -//public let ICONNAME_REFRESH2 = "arrow.counterclockwise.square" // 􂅟 􂅠 -public let ICONNAME_RECOUP = "taler.exclamationmark.circle" // 􀁞 􀁟 -public let ICONNAME_DENOMLOSS = "taler.exclamationmark.triangle" // 􀇾 􀇿 +public let ICONNAME_DUMMY = "taler.dummy" // 􀀀 􀀁 +public let SYSTEM_DUMMY1 = "circle" // 􀀀 􀀁 1.0 (iOS 13) + +public let ICONNAME_WITHDRAWAL = "taler.withdrawal" // 􁾬 􁾭 +public let SYSTEM_WITHDRAWAL5 = "arrowshape.down" // 􁾬 􁾭 5.0 (iOS 17) +public let FALLBACK_WITHDRAWAL = "arrow.down" // 􀄩 1.0 (iOS 13) no fill variant! +// "arrow.down.to.line" // 􀅀 1.0 (iOS 13) + +public let ICONNAME_DEPOSIT = "taler.deposit" // 􁾨 􁾩 +public let SYSTEM_DEPOSIT5 = "arrowshape.up" // 􁾨 􁾩 5.0 (iOS 17) +public let FALLBACK_DEPOSIT = "arrow.up" // 􀄨 1.0 (iOS 13) no fill variant! +// "arrow.up.to.line" // 􀄿 1.0 (iOS 13) + +public let ICONNAME_REFUND = "taler.refund" // 􀰚 􀰛 +public let SYSTEM_REFUND2 = "arrowshape.turn.up.backward" // 􀰚 􀰛 2.0 (iOS 14) +public let ICONNAME_PAYMENT = "taler.payment" // 􀉐 􀰟 +public let SYSTEM_PAYMENT2 = "arrowshape.turn.up.forward" // 􀉐 􀰟 2.0 (iOS 14) + +public let ICONNAME_INCOMING = "taler.incoming" // 􁉈 􁉅 +public let SYSTEM_INCOMING4 = "arrowshape.backward" // 􁉈 􁉅 4.0 (iOS 16) +public let FALLBACK_INCOMING = "arrow.backward" // 􀰌 2.0 (iOS 14) no fill variant! +// "arrow.backward.to.line" // 􁂊 3.0 (iOS 15) + +public let ICONNAME_OUTGOING = "taler.outgoing" // 􁉆 􁉇 +public let SYSTEM_OUTGOING4 = "arrowshape.forward" // 􁉆 􁉇 4.0 (iOS 16) +public let FALLBACK_OUTGOING = "arrow.forward" // 􀰑 2.0 (iOS 14) no fill variant! +// "arrow.forward.to.line" // 􁂎 3.0 (iOS 15) + +public let ICONNAME_REFRESH = "taler.refresh" // 􀎀 􁣛 +public let SYSTEM_REFRESH6 = "arrow.trianglehead.counterclockwise" // 􀎀 6.0 (iOS 18) +public let SYSTEM_REFRESH6_fill = "checkmark.arrow.trianglehead.counterclockwise" // 􁣛 6.0 (iOS 18) +public let FALLBACK_REFRESH = "arrow.counterclockwise" // 􁹠 1.0 (iOS 13) no fill variant! +//public let SYSTEM_REFRESH1 = "arrow.counterclockwise.circle" // 􀚃 􀚄 +//public let SYSTEM_REFRESH2 = "arrow.counterclockwise.square" // 􂅟 􂅠 +public let ICONNAME_RECOUP = "taler.recoup" // 􀁞 􀁟 +public let SYSTEM_RECOUP1 = "exclamationmark.circle" // 􀁞 􀁟 1.0 (iOS 13) +public let ICONNAME_DENOMLOSS = "taler.denomloss" // 􀇾 􀇿 +public let SYSTEM_DENOMLOSS1 = "exclamationmark.triangle" // 􀇾 􀇿 1.0 (iOS 13) public let HTTPS = "https://" //public let DEMOBANK = HTTPS + "bAnK.dEmO.tAlEr.nEt" // should be weird to read, but still work diff --git a/TalerWallet1/Model/Transaction.swift b/TalerWallet1/Model/Transaction.swift @@ -9,6 +9,7 @@ import Foundation import AnyCodable import taler_swift import SymLog +import SwiftUI enum TransactionTypeError: Error { case unknownTypeError @@ -228,24 +229,58 @@ enum TransactionType: String, Codable { var isP2pOutgoing: Bool { isSendCoins || isPayInvoice} var isP2pIncoming: Bool { isSendInvoice || isRcvCoins} var isIncoming : Bool { isP2pIncoming || isWithdrawal || isRefund } - func iconName(_ done: Bool = false) -> String { - let iconName = switch self { + var iconName: String { + switch self { case .dummy: ICONNAME_DUMMY case .withdrawal: ICONNAME_WITHDRAWAL case .deposit: ICONNAME_DEPOSIT case .payment: ICONNAME_PAYMENT case .refund: ICONNAME_REFUND case .refresh: ICONNAME_REFRESH - case .peerPushDebit: ICONNAME_OUTGOING_P2P - case .scanPushCredit: ICONNAME_INCOMING_P2P - case .peerPullCredit: ICONNAME_INCOMING_P2P - case .scanPullDebit: ICONNAME_OUTGOING_P2P + case .peerPushDebit: ICONNAME_OUTGOING + case .scanPushCredit: ICONNAME_INCOMING + case .peerPullCredit: ICONNAME_INCOMING + case .scanPullDebit: ICONNAME_OUTGOING case .recoup: ICONNAME_RECOUP case .denomLoss: ICONNAME_DENOMLOSS } - return isRefresh ? iconName // refresh has no fill - : done ? iconName + ICONNAME_FILL - : iconName + } + var sysIconName: String { + switch self { + case .dummy: SYSTEM_DUMMY1 + case .withdrawal: SYSTEM_WITHDRAWAL5 + case .deposit: SYSTEM_DEPOSIT5 + case .payment: SYSTEM_PAYMENT2 + case .refund: SYSTEM_REFUND2 + case .refresh: SYSTEM_REFRESH6 + case .peerPushDebit: SYSTEM_OUTGOING4 + case .scanPushCredit: SYSTEM_INCOMING4 + case .peerPullCredit: SYSTEM_INCOMING4 + case .scanPullDebit: SYSTEM_OUTGOING4 + case .recoup: SYSTEM_RECOUP1 + case .denomLoss: SYSTEM_DENOMLOSS1 + } + } + func icon(_ done: Bool = false) -> Image { + // try assets first + let name = done ? iconName + ICONNAME_FILL : iconName + if UIImage(named: name) != nil { return Image(name) } + + // fallback to system icons + let sysName = isRefresh ? (done ? SYSTEM_REFRESH6_fill : SYSTEM_REFRESH6) + : (done ? sysIconName + ICONNAME_FILL : sysIconName) + if UIImage(systemName: sysName) != nil { return Image(systemName: sysName) } +// .symbolVariant(done ? .fill : .none) + + // on older iOS Versions, fallback to simpler icons + if isRefresh { return Image(systemName: FALLBACK_REFRESH) } + if isDeposit { return Image(systemName: FALLBACK_DEPOSIT) } + if isWithdrawal { return Image(systemName: FALLBACK_WITHDRAWAL) } + if isP2pOutgoing { return Image(systemName: FALLBACK_OUTGOING) } + if isP2pIncoming { return Image(systemName: FALLBACK_INCOMING) } + + // finally, there's always dummy + return Image(systemName: SYSTEM_DUMMY1) } } diff --git a/TalerWallet1/Views/HelperViews/IconBadge.swift b/TalerWallet1/Views/HelperViews/IconBadge.swift @@ -15,16 +15,16 @@ struct PendingIconBadge: View { let needsKYC: Bool var body: some View { - let imageName = incoming && done ? DONE_INCOMING - : incoming ? PENDING_INCOMING - // since the money already left the wallet, show DONE - : DONE_OUTGOING // PENDING_OUTGOING - IconBadge(imageName: imageName, - isPending: true, - foreColor: foreColor, - shouldConfirm: shouldConfirm, - needsKYC: needsKYC, - wideIconName: nil) + let image = incoming && done ? Image(DONE_INCOMING) // "plus.circle.fill" + : incoming ? Image(PENDING_INCOMING) // "plus" + // since the money already left the wallet, show DONE and not PENDING_OUTGOING + : Image(DONE_OUTGOING) // "minus.circle" + IconBadge(image: image, + done: false, + foreColor: foreColor, + shouldConfirm: shouldConfirm, + needsKYC: needsKYC, + wideIcon: nil) } } // MARK: - @@ -37,13 +37,13 @@ struct TransactionIconBadge: View { let needsKYC: Bool var body: some View { - let imageName = type.iconName(done) - IconBadge(imageName: imageName, - isPending: false, - foreColor: foreColor, - shouldConfirm: shouldConfirm, - needsKYC: needsKYC, - wideIconName: nil) + IconBadge(image: type.icon(done), + done: true, + foreColor: foreColor, + shouldConfirm: shouldConfirm, + needsKYC: needsKYC, + wideIcon: TransactionType.refund.icon()) + // "arrowshape.turn.up.backward" is wider than all others } } // MARK: - @@ -53,38 +53,36 @@ struct ButtonIconBadge: View { let done: Bool var body: some View { - let imageName = type.iconName(done) - IconBadge(imageName: imageName, - isPending: false, - foreColor: foreColor, - shouldConfirm: false, - needsKYC: false, - wideIconName: ICONNAME_INCOMING_P2P) + IconBadge(image: type.icon(done), + done: true, + foreColor: foreColor, + shouldConfirm: false, + needsKYC: false, + wideIcon: TransactionType.peerPushDebit.icon()) + // button never is payment or refund } } // MARK: - struct IconBadge: View { - let imageName: String - let isPending: Bool + let image: Image + let done: Bool let foreColor:Color -// let pending: Bool let shouldConfirm: Bool let needsKYC: Bool - let wideIconName: String? + let wideIcon: Image? + + @ScaledMetric var spacing = 8 // relative to fontSize var body: some View { - HStack(alignment: .top, spacing: -8) { // TODO: adapt spacing to dynamic fontsize - let image = isPending ? Image(systemName: imageName) - : Image(imageName) + HStack(alignment: .top, spacing: -spacing) { ZStack { - // "taler.turn.up.backward" is wider than all others - // ZStack centers the main icon, and the badge will always be at the same position - Image(wideIconName ?? ICONNAME_REFUND) - .foregroundColor(.clear) - image - .foregroundColor(foreColor) + if let wideIcon { + wideIcon.foregroundColor(.clear) + } + image.foregroundColor(foreColor) }.talerFont(.title) - if wideIconName == nil { + if wideIcon == nil { + // ZStack centers the main icon, so the badge will always be at the same position let badgeName = needsKYC ? NEEDS_KYC : CONFIRM_BANK Image(systemName: badgeName) diff --git a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift @@ -149,7 +149,7 @@ struct TransactionSummaryV: View { : majorState let statusT = Text(state) .multilineTextAlignment(.trailing) - let imageT = Text(Image(common.type.iconName())) + let imageT = Text(common.type.icon()) .accessibilityHidden(true) let prefixT = Text("Status:") let vLayout = VStack(alignment: .leading, spacing: 0) {