diff --git a/Flipcash/Core/Screens/Main/AddMoney/AddMoneyProcessingViewModel.swift b/Flipcash/Core/Screens/Main/AddMoney/AddMoneyProcessingViewModel.swift index f6bfae25d..4d90bb41b 100644 --- a/Flipcash/Core/Screens/Main/AddMoney/AddMoneyProcessingViewModel.swift +++ b/Flipcash/Core/Screens/Main/AddMoney/AddMoneyProcessingViewModel.swift @@ -33,7 +33,9 @@ final class AddMoneyProcessingViewModel { case .processing: return "This Will Take a Minute" case .success: - return "\(input.amount.nativeAmount.formatted()) of USDF" + // No "of " here: adding money always lands in the reserve, so + // "$1.00 of Dollars" only restates what the amount already says. + return input.amount.nativeAmount.formatted() case .failed: return "Something Went Wrong" } diff --git a/Flipcash/Core/Screens/Main/Buy/USDCDepositEducationScreen.swift b/Flipcash/Core/Screens/Main/Buy/USDCDepositEducationScreen.swift index b596df971..7c3ee95e4 100644 --- a/Flipcash/Core/Screens/Main/Buy/USDCDepositEducationScreen.swift +++ b/Flipcash/Core/Screens/Main/Buy/USDCDepositEducationScreen.swift @@ -9,8 +9,8 @@ import SwiftUI import FlipcashCore import FlipcashUI -/// Pre-flight for the USDC → USDF conversion: explains that incoming Solana -/// USDC is auto-converted 1:1 to USDF on receipt. Pass `onDepositOtherCurrencies` +/// Pre-flight for the USDC → Dollars conversion: explains that incoming Solana +/// USDC is auto-converted 1:1 to Dollars on receipt. Pass `onDepositOtherCurrencies` /// to expose a subtle escape hatch below Next. struct USDCDepositEducationScreen: View { @@ -33,16 +33,16 @@ struct USDCDepositEducationScreen: View { VStack(spacing: 24) { Spacer() - ConversionGraphic() + ConversionGraphic(from: .usdcOnSolana, to: .dollars) .accessibilityElement(children: .ignore) - .accessibilityLabel("Convert USDC to USDF") + .accessibilityLabel("Convert USDC to Dollars") VStack(spacing: 8) { Text("Deposit USDC") .font(.appTextLarge) .foregroundStyle(Color.textMain) - Text("Your Solana USDC will be converted 1:1 to USD on Flipcash (USDF)") + Text("Your USDC will be converted 1:1 to Dollars on Flipcash") .font(.appTextMedium) .foregroundStyle(Color.textSecondary) .multilineTextAlignment(.center) @@ -68,22 +68,3 @@ struct USDCDepositEducationScreen: View { .toolbarTitleDisplayMode(.inline) } } - -private struct ConversionGraphic: View { - var body: some View { - HStack(spacing: 16) { - BadgedIcon( - icon: Image.asset(.buyUSDC), - badge: Image.asset(.buySolana) - ) - - Image.system(.arrowRight) - .foregroundStyle(Color.textSecondary) - - Image.asset(.buyFlipcash) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 100, height: 100) - } - } -} diff --git a/Flipcash/Core/Screens/Main/Currency Swap/SwapProcessingViewModel.swift b/Flipcash/Core/Screens/Main/Currency Swap/SwapProcessingViewModel.swift index 89f71028a..f1e472b39 100644 --- a/Flipcash/Core/Screens/Main/Currency Swap/SwapProcessingViewModel.swift +++ b/Flipcash/Core/Screens/Main/Currency Swap/SwapProcessingViewModel.swift @@ -25,6 +25,10 @@ class SwapProcessingViewModel { case .success: if let exchangedFiat { switch swapType { + case .convert where targetMint == .usdf: + // Converting into the reserve would read "$1.00 of Dollars" — + // the amount alone already says it. + return exchangedFiat.nativeAmount.formatted() case .buyWithReserves, .buyWithCurrency, .convert: // Convert names its destination via `currencyName`, so the // same "X of " reads correctly there too. @@ -94,8 +98,9 @@ class SwapProcessingViewModel { private let swapId: SwapId private let swapType: SwapType - /// The token being bought — analytics-only; nil on the sell path, where - /// `amount.mint` already names the subject token. + /// The token being bought, or a convert's destination; nil on the sell path, + /// where `amount.mint` already names the subject token. Feeds analytics, and + /// the success title's check for a conversion landing in the reserve. private let targetMint: PublicKey? private let currencyName: String private let amount: ExchangedFiat diff --git a/Flipcash/Core/Screens/Settings/Withdraw/WithdrawIntroScreen.swift b/Flipcash/Core/Screens/Settings/Withdraw/WithdrawIntroScreen.swift index 5df5a480d..ba611838c 100644 --- a/Flipcash/Core/Screens/Settings/Withdraw/WithdrawIntroScreen.swift +++ b/Flipcash/Core/Screens/Settings/Withdraw/WithdrawIntroScreen.swift @@ -16,7 +16,7 @@ struct WithdrawIntroScreen: View { VStack(spacing: 24) { Spacer() - ConversionGraphic() + ConversionGraphic(from: .dollars, to: .usdcOnSolana) .accessibilityElement(children: .ignore) .accessibilityLabel("Convert Dollars to USDC") @@ -44,22 +44,3 @@ struct WithdrawIntroScreen: View { .toolbarTitleDisplayMode(.inline) } } - -private struct ConversionGraphic: View { - var body: some View { - HStack(spacing: 16) { - Image.asset(.buyDollars) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 100, height: 100) - - Image.system(.arrowRight) - .foregroundStyle(Color.textSecondary) - - BadgedIcon( - icon: Image.asset(.buyUSDC), - badge: Image.asset(.buySolana) - ) - } - } -} diff --git a/FlipcashUI/Sources/FlipcashUI/Views/ConversionGraphic.swift b/FlipcashUI/Sources/FlipcashUI/Views/ConversionGraphic.swift new file mode 100644 index 000000000..f00956b40 --- /dev/null +++ b/FlipcashUI/Sources/FlipcashUI/Views/ConversionGraphic.swift @@ -0,0 +1,67 @@ +// +// ConversionGraphic.swift +// FlipcashUI +// + +import SwiftUI + +/// A coin face `ConversionGraphic` can show on either side of the arrow. +public enum ConversionCoin { + /// The gold "Dollars" coin — Flipcash's own reserve currency. + case dollars + + /// The USDC coin with the Solana badge on its bottom-trailing corner. + case usdcOnSolana +} + +/// The "converted 1:1" education art: two coins separated by an arrow. +/// +/// Composed here rather than shipped as one flattened asset so the same art serves both +/// directions — Dollars → USDC when withdrawing, and the inverse when adding money from +/// another wallet. +public struct ConversionGraphic: View { + + private let from: ConversionCoin + private let to: ConversionCoin + + public init(from: ConversionCoin, to: ConversionCoin) { + self.from = from + self.to = to + } + + public var body: some View { + HStack(spacing: 16) { + coin(from) + + Image.system(.arrowRight) + .foregroundStyle(Color.textSecondary) + + coin(to) + } + } + + @ViewBuilder + private func coin(_ coin: ConversionCoin) -> some View { + switch coin { + case .dollars: + Image.asset(.buyDollars) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 100, height: 100) + + case .usdcOnSolana: + // Badge is an overlay, so the coin still lays out as a flat 100pt square. + BadgedIcon( + icon: Image.asset(.buyUSDC), + badge: Image.asset(.buySolana) + ) + } + } +} + +#Preview { + VStack(spacing: 40) { + ConversionGraphic(from: .dollars, to: .usdcOnSolana) + ConversionGraphic(from: .usdcOnSolana, to: .dollars) + } +}