Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 12 additions & 2 deletions Bitkit/Components/MoneyText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@ struct MoneyText: View {
private var displayText: String {
if showSymbol {
let baseSymbol = unit == .bitcoin ? "₿" : fiatSymbol
let symbolPart = prefix != nil ? "<accent>\(prefix!) \(baseSymbol)</accent>" : "<accent>\(baseSymbol)</accent>"
return "\(symbolPart) \(formattedValue)"
let isSuffix = unit == .fiat && isFiatSymbolSuffix
if isSuffix {
let prefixPart = prefix != nil ? "<accent>\(prefix!)</accent> " : ""
return "\(prefixPart)\(formattedValue) <accent>\(baseSymbol)</accent>"
} else {
let symbolPart = prefix != nil ? "<accent>\(prefix!) \(baseSymbol)</accent>" : "<accent>\(baseSymbol)</accent>"
return "\(symbolPart) \(formattedValue)"
}
} else {
return prefix != nil ? "<accent>\(prefix!)</accent> \(formattedValue)" : formattedValue
}
Expand Down Expand Up @@ -118,6 +124,10 @@ extension MoneyText {
return converted.symbol
}

private var isFiatSymbolSuffix: Bool {
isSuffixSymbolCurrency(currency.selectedCurrency)
}

private var formattedValue: String {
if hideBalance {
return displayDots
Expand Down
18 changes: 14 additions & 4 deletions Bitkit/Components/NumberPadTextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,28 @@ struct NumberPadTextField: View {

@ViewBuilder
private var primaryDisplayView: some View {
let isSuffix = currency.primaryDisplay == .fiat && isSuffixSymbolCurrency(currency.selectedCurrency)
let symbolText = currency.primaryDisplay == .bitcoin ? "₿" : currency.symbol

HStack(spacing: 6) {
// Symbol
Text(currency.primaryDisplay == .bitcoin ? "₿" : currency.symbol)
.font(.custom(Fonts.extraBold, size: 44))
.foregroundColor(.textSecondary)
if !isSuffix {
Text(symbolText)
.font(.custom(Fonts.extraBold, size: 44))
.foregroundColor(.textSecondary)
}

// Value and placeholder
(Text(viewModel.displayText)
.foregroundColor(.textPrimary)
+ Text(viewModel.getPlaceholder(currency: currency))
.foregroundColor(isFocused ? .textSecondary : .textPrimary))
.font(.custom(Fonts.black, size: 44))

if isSuffix {
Text(symbolText)
.font(.custom(Fonts.extraBold, size: 44))
.foregroundColor(.textSecondary)
}
}
}
}
27 changes: 27 additions & 0 deletions Bitkit/Models/Currency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ struct ConvertedAmount {
let sats: UInt64
let btcValue: Decimal

var isSymbolSuffix: Bool { isSuffixSymbolCurrency(currency) }

init(value: Decimal, formatted: String, symbol: String, currency: String, flag: String, sats: UInt64) {
self.value = value
self.formatted = formatted
Expand All @@ -50,6 +52,11 @@ struct ConvertedAmount {
btcValue = Decimal(sats) / 100_000_000
}

func formattedWithSymbol(withSpace: Bool = false) -> String {
let separator = withSpace ? " " : ""
return isSymbolSuffix ? "\(formatted)\(separator)\(symbol)" : "\(symbol)\(separator)\(formatted)"
}

struct BitcoinDisplayComponents {
let symbol: String
let value: String
Expand All @@ -75,3 +82,23 @@ struct ConvertedAmount {
}
}
}

func isSuffixSymbolCurrency(_ currencyCode: String) -> Bool {
suffixSymbolCurrencies.contains(currencyCode)
}

private let suffixSymbolCurrencies: Set<String> = [
"BGN", // Bulgarian Lev (10,00 лв)
"CHF", // Swiss Franc (10.00 CHF)
"CZK", // Czech Koruna (10,00 Kč)
"DKK", // Danish Krone (10,00 kr)
"HRK", // Croatian Kuna (10,00 kn)
"HUF", // Hungarian Forint (10 000 Ft)
"ISK", // Icelandic Króna (10.000 kr)
"NOK", // Norwegian Krone (10,00 kr)
"PLN", // Polish Złoty (0,35 zł)
"RON", // Romanian Leu (10,00 lei)
"RUB", // Russian Ruble (10,00 ₽)
"SEK", // Swedish Krona (10,00 kr)
"TRY", // Turkish Lira (10,00 ₺)
]
2 changes: 1 addition & 1 deletion Bitkit/ViewModels/Widgets/WeatherViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class WeatherViewModel: ObservableObject {
throw AppError(message: "Currency conversion unavailable", debugMessage: "Failed to convert \(fee) satoshis to fiat currency")
}

return "\(converted.symbol) \(converted.formatted)"
return converted.formattedWithSymbol(withSpace: true)
}

deinit {
Expand Down
4 changes: 2 additions & 2 deletions Bitkit/Views/Wallets/Receive/ReceiveCjitConfirmation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ struct ReceiveCjitConfirmation: View {
guard let converted = currency.convert(sats: entry.networkFeeSat) else {
return String(entry.networkFeeSat)
}
return "\(converted.symbol)\(converted.formatted)"
return converted.formattedWithSymbol()
}

private func formattedServiceFee() -> String {
guard let converted = currency.convert(sats: entry.serviceFeeSat) else {
return String(entry.serviceFeeSat)
}
return "\(converted.symbol)\(converted.formatted)"
return converted.formattedWithSymbol()
}

var receiveAmount: Int {
Expand Down
2 changes: 1 addition & 1 deletion Bitkit/Views/Wallets/Sheets/BoostSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ struct BoostSheet: View {
else {
return ""
}
return "\(converted.symbol)\(converted.formatted)"
return converted.formattedWithSymbol()
}

var body: some View {
Expand Down
114 changes: 114 additions & 0 deletions BitkitTests/CurrencyTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
@testable import Bitkit
import XCTest

final class CurrencyTests: XCTestCase {
// MARK: - isSuffixSymbolCurrency

func testIsSuffixSymbolCurrency_ReturnsTrueForPLN() {
XCTAssertTrue(isSuffixSymbolCurrency("PLN"))
}

func testIsSuffixSymbolCurrency_ReturnsTrueForCZK() {
XCTAssertTrue(isSuffixSymbolCurrency("CZK"))
}

func testIsSuffixSymbolCurrency_ReturnsTrueForSEK() {
XCTAssertTrue(isSuffixSymbolCurrency("SEK"))
}

func testIsSuffixSymbolCurrency_ReturnsTrueForCHF() {
XCTAssertTrue(isSuffixSymbolCurrency("CHF"))
}

func testIsSuffixSymbolCurrency_ReturnsFalseForUSD() {
XCTAssertFalse(isSuffixSymbolCurrency("USD"))
}

func testIsSuffixSymbolCurrency_ReturnsFalseForEUR() {
XCTAssertFalse(isSuffixSymbolCurrency("EUR"))
}

func testIsSuffixSymbolCurrency_ReturnsFalseForGBP() {
XCTAssertFalse(isSuffixSymbolCurrency("GBP"))
}

func testIsSuffixSymbolCurrency_ReturnsFalseForUnknownCurrency() {
XCTAssertFalse(isSuffixSymbolCurrency("XYZ"))
}

// MARK: - ConvertedAmount.isSymbolSuffix

func testConvertedAmount_IsSymbolSuffix_TrueForPLN() {
let converted = ConvertedAmount(
value: 0.35, formatted: "0.35", symbol: "zł",
currency: "PLN", flag: "🇵🇱", sats: 100
)
XCTAssertTrue(converted.isSymbolSuffix)
}

func testConvertedAmount_IsSymbolSuffix_FalseForUSD() {
let converted = ConvertedAmount(
value: 10.50, formatted: "10.50", symbol: "$",
currency: "USD", flag: "🇺🇸", sats: 1000
)
XCTAssertFalse(converted.isSymbolSuffix)
}

// MARK: - ConvertedAmount.formattedWithSymbol

func testFormattedWithSymbol_PrefixCurrency() {
let converted = ConvertedAmount(
value: 10.50, formatted: "10.50", symbol: "$",
currency: "USD", flag: "🇺🇸", sats: 1000
)
XCTAssertEqual(converted.formattedWithSymbol(), "$10.50")
}

func testFormattedWithSymbol_SuffixCurrency() {
let converted = ConvertedAmount(
value: 0.35, formatted: "0.35", symbol: "zł",
currency: "PLN", flag: "🇵🇱", sats: 100
)
XCTAssertEqual(converted.formattedWithSymbol(), "0.35zł")
}

func testFormattedWithSymbol_SuffixCurrencyCZK() {
let converted = ConvertedAmount(
value: 250.00, formatted: "250.00", symbol: "Kč",
currency: "CZK", flag: "🇨🇿", sats: 50000
)
XCTAssertEqual(converted.formattedWithSymbol(), "250.00Kč")
}

func testFormattedWithSymbol_PrefixCurrencyEUR() {
let converted = ConvertedAmount(
value: 10.00, formatted: "10.00", symbol: "€",
currency: "EUR", flag: "🇪🇺", sats: 1000
)
XCTAssertEqual(converted.formattedWithSymbol(), "€10.00")
}

func testFormattedWithSymbol_SuffixCurrencyCHF() {
let converted = ConvertedAmount(
value: 50.00, formatted: "50.00", symbol: "CHF",
currency: "CHF", flag: "🇨🇭", sats: 10000
)
XCTAssertEqual(converted.formattedWithSymbol(), "50.00CHF")
}

func testFormattedWithSymbol_PrefixCurrency_WithSpace() {
let converted = ConvertedAmount(
value: 10.50, formatted: "10.50", symbol: "$",
currency: "USD", flag: "🇺🇸", sats: 1000
)
XCTAssertEqual(converted.formattedWithSymbol(withSpace: true), "$ 10.50")
}

func testFormattedWithSymbol_SuffixCurrency_WithSpace() {
let converted = ConvertedAmount(
value: 0.35, formatted: "0.35", symbol: "zł",
currency: "PLN", flag: "🇵🇱", sats: 100
)
XCTAssertEqual(converted.formattedWithSymbol(withSpace: true), "0.35 zł")
}
}
Loading