Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d659dfe
purse ui for the cash card
filvecchiato Nov 3, 2026
1f53cfe
Merge remote-tracking branch 'origin/hosts/ios-funding-2-core' into h…
filvecchiato Nov 4, 2026
811f87b
Merge remote-tracking branch 'origin/hosts/ios-funding-2-core' into h…
filvecchiato Nov 4, 2026
a636146
Merge branch 'hosts/ios-funding-2-core' into hosts/ios-funding-3a-purse
filvecchiato Nov 4, 2026
1a7612f
Merge remote-tracking branch 'origin/hosts/ios-funding-2-core' into h…
filvecchiato Nov 4, 2026
47846de
delete unused coinage breakdown view
filvecchiato Nov 4, 2026
f0a30b4
clear purse title view below ios 26
filvecchiato Nov 4, 2026
8955609
drop get/send and wallet card strings left unused
filvecchiato Nov 4, 2026
dedba0a
drop unread ready balance and logo from balance card
filvecchiato Nov 4, 2026
876ffa3
keep only purse motion 3a uses
filvecchiato Nov 4, 2026
ae61576
move purse motion, scroll and split bar tests to purse part
filvecchiato Nov 4, 2026
e80a2ad
add funding strings purse uses
filvecchiato Nov 4, 2026
4bef84c
Merge branch 'hosts/ios-funding-2-core' into hosts/ios-funding-3a-purse
filvecchiato Nov 5, 2026
417b248
Merge branch 'hosts/ios-funding-2-core' into hosts/ios-funding-3a-purse
filvecchiato Nov 5, 2026
2df5931
Merge branch 'hosts/ios-funding-2-core' into hosts/ios-funding-3a-purse
filvecchiato Nov 5, 2026
ad6337f
Merge branch 'hosts/ios-funding-2-core' into hosts/ios-funding-3a-purse
filvecchiato Nov 5, 2026
0716c94
Merge branch 'hosts/ios-funding-2-core' into hosts/ios-funding-3a-purse
filvecchiato Nov 5, 2026
fb97ca1
Merge remote-tracking branch 'origin/hosts/ios-funding-2-core' into h…
filvecchiato Nov 6, 2026
4706e97
Merge remote-tracking branch 'origin/hosts/ios-funding-2-core' into h…
filvecchiato Nov 6, 2026
f64af1e
format purse panel
filvecchiato Nov 6, 2026
b5f5fd2
Merge remote-tracking branch 'origin/hosts/ios-funding-2-core' into h…
filvecchiato Nov 6, 2026
03c6fdb
Merge remote-tracking branch 'origin/hosts/ios-funding-2-core' into HEAD
filvecchiato Nov 6, 2026
d065064
Merge remote-tracking branch 'origin/funding/host-gaps' into HEAD
filvecchiato Nov 6, 2026
1b2872e
Merge branch 'restack/ios-funding-2-core' into HEAD
filvecchiato Nov 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,138 +2,127 @@ import SwiftUI
import DesignSystem
import ExternalAccessibility

/// The CASH card: a leather wallet with the balance stamped at its foot.
public struct AssetDetailsBalanceCard: View {
let viewModel: ViewModel
let isUpdating: Bool
let isExpanded: Bool
/// How visible the balance is, so it can fade as the card shrinks into
/// the header.
let balanceOpacity: Double

public init(viewModel: ViewModel, isUpdating: Bool, isExpanded: Bool = false) {
public init(viewModel: ViewModel, isUpdating: Bool, isExpanded: Bool = false, balanceOpacity: Double = 1) {
self.viewModel = viewModel
self.isUpdating = isUpdating
self.isExpanded = isExpanded
self.balanceOpacity = balanceOpacity
}

/// The card is a leather wallet, so it has the wallet's own proportions and outline rather
/// than a bordered rectangle's.
public var body: some View {
content
CashCardFace()
.overlay(alignment: .topLeading) { updatingLabel }
.overlay(alignment: .bottomLeading) { balance.opacity(balanceOpacity) }
.accessibilityId(AccessibilityID.Wallet.cashCard)
.aspectRatio(Constants.wallet.aspectRatio, contentMode: .fit)
}

/// The total, which sits at the foot of the card in both of its states.
private func total(_ balance: String) -> some View {
DSAmount(amount: balance, symbol: viewModel.symbol, typography: .headlineMedium)
.shimmering(active: isUpdating)
.accessibilityId(AccessibilityID.Wallet.totalBalance)
@ViewBuilder
private var updatingLabel: some View {
if isUpdating {
SwiftUI.Label {
Text(.walletCardUpdatingBalance)
.textStyle(.body14Regular())
} icon: {
SpinningUpdateIcon()
}
.foregroundStyle(.white)
.shadow(color: .black.opacity(0.25), radius: 1, y: 1)
.padding(.top, Constants.balanceInset.bottom)
.padding(.leading, Constants.balanceInset.leading)
}
}

private var content: some View {
ZStack(alignment: .leading) {
Image(.walletLeather)
.resizable()
.scaledToFit()
.walletLeather(Constants.wallet)

VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 5) {
Image(uiImage: viewModel.logo ?? .cashLogo)
.resizable()
.scaledToFit()
.frame(height: Constants.logoHeight)

Spacer()

if !isExpanded, let balance = viewModel.balance {
DSAmount(amount: balance, symbol: viewModel.symbol, typography: .titleLarge)
.foregroundStyle(Color.fgStaticWhite)
.transition(.opacity)
.accessibilityId(AccessibilityID.Wallet.cashCardBalance)
}
}
.animation(.easeInOut, value: isExpanded)
Spacer()

if isUpdating {
SwiftUI.Label {
Text(.walletCardUpdatingBalance)
.textStyle(.body14Regular())
} icon: {
SpinningUpdateIcon()
}
.foregroundStyle(.white)
}

if isExpanded, let readyBalance = viewModel.readyBalance, let balance = viewModel.balance {
VStack(alignment: .leading, spacing: DSSpacings.small) {
VStack(alignment: .leading, spacing: 0) {
Text(.walletCardReady)
.typography(.bodyMedium)
.foregroundStyle(Color.fgStaticWhite)
Text(readyBalance)
.typography(.bodyMedium)
}

VStack(alignment: .leading, spacing: 0) {
Text(.walletCardTotalBalance)
.typography(.bodyMedium)
.foregroundStyle(Color.fgStaticWhite)
total(balance)
}
}
} else if let balance = viewModel.balance {
total(balance)
@ViewBuilder
private var balance: some View {
if let amount = viewModel.balance {
HStack(alignment: .firstTextBaseline, spacing: Constants.unitSpacing) {
Text(verbatim: amount)
.font(.system(size: 30, weight: .semibold))
.monospacedDigit()
.contentTransition(.numericText())
if let symbol = viewModel.symbol {
Text(verbatim: symbol.lowercased())
.font(.system(size: 24, weight: .light).smallCaps())
}
}
.foregroundStyle(Color.white)
.padding(.top, DSSpacings.mediumIncreased)
.padding(.bottom, DSSpacings.mediumIncreased)
.padding(.leading, DSSpacings.large)
.padding(.trailing, 22)
.foregroundStyle(.white)
.shadow(color: .black.opacity(0.25), radius: 1, y: 1)
.shimmering(active: isUpdating)
.padding(.leading, Constants.balanceInset.leading)
.padding(.bottom, Constants.balanceInset.bottom)
.accessibilityElement(children: .combine)
.accessibilityId(isExpanded ? AccessibilityID.Wallet.totalBalance : AccessibilityID.Wallet.cashCardBalance)
}
}
}

/// The card's face on its own, at the wallet's proportions: the leather wallet, lit by the phone's
/// motion. The Purse header draws it as a thumbnail once the card has shrunk away.
public struct CashCardFace: View {
public init() {}

public var body: some View {
Image(.walletLeather)
.resizable()
.scaledToFit()
.walletLeather(CashCardFace.wallet)
.aspectRatio(CashCardFace.aspectRatio, contentMode: .fit)
}

/// The wallet artwork and where its brass button sits.
public static let wallet = WalletLeatherImage.cashWallet
/// The wallet artwork's own proportions.
public static let aspectRatio: CGFloat = wallet.aspectRatio
}

public extension AssetDetailsBalanceCard {
struct ViewModel {
let balance: String?
let readyBalance: String?
let logo: UIImage?
let symbol: String?

public init(balance: String?, readyBalance: String?, logo: UIImage? = nil, symbol: String? = nil) {
public init(balance: String?, symbol: String? = nil) {
self.balance = balance
self.readyBalance = readyBalance
self.logo = logo
self.symbol = symbol
}
}
}

private extension AssetDetailsBalanceCard {
enum Constants {
static let logoHeight: CGFloat = 32
static let wallet = WalletLeatherImage.cashWallet
/// Where the balance sits on the 366 by 239 artwork.
static let balanceInset = (leading: CGFloat(23), bottom: CGFloat(22))
static let unitSpacing: CGFloat = 6
}
}

#Preview {
ZStack {
Color.gray
AssetDetailsBalanceCard(
viewModel: AssetDetailsBalanceCard.ViewModel(balance: "$123", readyBalance: nil, symbol: "CASH"),
viewModel: AssetDetailsBalanceCard.ViewModel(balance: "$123", symbol: "CASH"),
isUpdating: true
)
.padding()
}
}

#Preview("Expanded with Ready balance") {
#Preview("Expanded") {
ZStack {
Color.gray
AssetDetailsBalanceCard(
viewModel: AssetDetailsBalanceCard.ViewModel(balance: "$456", readyBalance: "100", symbol: "CASH"),
viewModel: AssetDetailsBalanceCard.ViewModel(balance: "$424.13", symbol: "CASH"),
isUpdating: false,
isExpanded: true
)
.padding()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1290,17 +1290,6 @@
}
}
},
"wallet.card.ready" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ready"
}
}
}
},
"wallet.card.title" : {
"extractionState" : "manual",
"localizations" : {
Expand All @@ -1312,17 +1301,6 @@
}
}
},
"wallet.card.total.balance" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Total"
}
}
}
},
"wallet.card.updating.balance" : {
"extractionState" : "manual",
"localizations" : {
Expand Down
55 changes: 55 additions & 0 deletions hosts/ios/polkadot-app/Localization/Funding.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@
}
}
},
"activity.currentBalance" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Current balance"
}
}
}
},
"activity.delayed" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -364,6 +375,50 @@
}
}
},
"card.get" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Get"
}
}
}
},
"card.getSubtitle" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Add %1$(symbol)@ via bank, crypto or credit card"
}
}
}
},
"card.send" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Send"
}
}
}
},
"card.sendSubtitle" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Move %1$(symbol)@ to your bank, crypto wallet or contacts"
}
}
}
},
"activity.cancelRequested" : {
"extractionState" : "manual",
"localizations" : {
Expand Down
44 changes: 0 additions & 44 deletions hosts/ios/polkadot-app/Localization/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -218,50 +218,6 @@
}
}
},
"action.get" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Get"
}
}
}
},
"action.get.subtitle" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Add CASH via bank, crypto or credit card"
}
}
}
},
"action.send.cash" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Send"
}
}
}
},
"action.send.subtitle" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Move CASH to your bank, crypto wallet or contacts"
}
}
}
},
"address.copied" : {
"extractionState" : "manual",
"localizations" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,6 @@ final class AssetDetailsPresenter {
.value(for: .current)

view?.didReceiveData(viewModel: .token(balanceViewModel), index: 0)

guard let coinageAmounts, coinageAmounts.hasFundsNotReady else {
view?.didReceive(readyAmount: nil)
return
}

let readyViewModel = balanceViewModelFactory.balanceFromPrice(
coinageAmounts.availableNow,
priceData: price
)
.value(for: .current)

view?.didReceive(readyAmount: readyViewModel)
}
}

Expand Down Expand Up @@ -221,6 +208,7 @@ private extension AssetDetailsPresenter {
availableNowBalance: formatted(from: amounts.availableNow, as: figureInfo),
gainingPrivacyBalance: formatted(from: amounts.gainingPrivacy, as: figureInfo),
symbol: chainAsset.asset.digitalDollarDisplayInfo.symbol,
amounts: amounts,
strip: strip,
traces: traces
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import Products
protocol AssetDetailsViewProtocol: ControllerBackedProtocol {
func didSetCards(viewModels: [WalletCardCreateViewModel])
func didReceiveData(viewModel: WalletCardDataViewModel, index: Int)
func didReceive(readyAmount: BalanceViewModelProtocol?)
func didReceive(paymentAsset: PaymentAssetViewModelProtocol)
func didReceive(isRecoveryInProgress: Bool)
func didShowBackupNotification()
Expand Down
Loading
Loading