diff --git a/app/src/main/java/com/electricdreams/numo/PaymentRequestActivity.kt b/app/src/main/java/com/electricdreams/numo/PaymentRequestActivity.kt index b2663ee1..bba95a9e 100644 --- a/app/src/main/java/com/electricdreams/numo/PaymentRequestActivity.kt +++ b/app/src/main/java/com/electricdreams/numo/PaymentRequestActivity.kt @@ -318,10 +318,14 @@ class PaymentRequestActivity : AppCompatActivity() { val entryUnit: String val enteredAmount: Long + // Get current preferred currency to help resolve ambiguous symbols (like "kr" for SEK/NOK) + val currentCurrencyCode = CurrencyManager.getInstance(this).getCurrentCurrency() + val currentCurrency = Amount.Currency.fromCode(currentCurrencyCode) + if (tipAmountSats > 0 && baseAmountSats > 0) { // Tip is present - use base amounts for accounting // Parse base formatted amount to get the original entry unit - val parsedBase = Amount.parse(baseFormattedAmount) + val parsedBase = Amount.parse(baseFormattedAmount, currentCurrency) if (parsedBase != null) { entryUnit = if (parsedBase.currency == Currency.BTC) "sat" else parsedBase.currency.name enteredAmount = parsedBase.value @@ -333,7 +337,7 @@ class PaymentRequestActivity : AppCompatActivity() { Log.d(TAG, "Creating pending payment with tip: base=$enteredAmount $entryUnit, tip=$tipAmountSats sats, total=$paymentAmount sats") } else { // No tip - parse the formatted amount string - val parsedAmount = Amount.parse(formattedAmountString) + val parsedAmount = Amount.parse(formattedAmountString, currentCurrency) if (parsedAmount != null) { entryUnit = if (parsedAmount.currency == Currency.BTC) "sat" else parsedAmount.currency.name enteredAmount = parsedAmount.value diff --git a/app/src/main/java/com/electricdreams/numo/core/model/Amount.kt b/app/src/main/java/com/electricdreams/numo/core/model/Amount.kt index 6f23714b..598f17be 100644 --- a/app/src/main/java/com/electricdreams/numo/core/model/Amount.kt +++ b/app/src/main/java/com/electricdreams/numo/core/model/Amount.kt @@ -25,7 +25,10 @@ data class Amount( USD("$"), EUR("€"), GBP("£"), - JPY("¥"); + JPY("¥"), + DKK("kr."), + SEK("kr"), + NOK("kr"); /** * Get the appropriate locale for formatting this currency. @@ -37,6 +40,9 @@ data class Amount( GBP -> Locale.UK // Period decimal: £4.20 JPY -> Locale.JAPAN // No decimals: ¥420 BTC -> Locale.US // Comma thousand separator: ₿1,000 + DKK -> Locale("da", "DK") // Comma decimal: DKK 100,00 + SEK -> Locale("sv", "SE") // Comma decimal: SEK 100,00 + NOK -> Locale("nb", "NO") // Comma decimal: NOK 100,00 } companion object { @@ -115,17 +121,39 @@ data class Amount( * Handles formats like "$0.25", "€1,50", "₿24", "¥100", etc. * Accepts both period and comma as decimal separators for input flexibility. * Returns null if parsing fails. + * + * @param formatted The formatted string to parse (e.g. "$10.50") + * @param defaultCurrency Optional default currency to use if the symbol is ambiguous (e.g. "kr" could be SEK or NOK). */ @JvmStatic - fun parse(formatted: String): Amount? { + @JvmOverloads + fun parse(formatted: String, defaultCurrency: Currency? = null): Amount? { if (formatted.isEmpty()) return null - // Find the currency by the first character (symbol) - val symbol = formatted.take(1) - val currency = Currency.fromSymbol(symbol) ?: return null + // Find matching currencies by matching the start of the string + // We sort by symbol length descending to match longest symbols first (e.g. "kr." vs "kr") + val matchingCurrencies = Currency.entries + .filter { formatted.startsWith(it.symbol) } + .sortedByDescending { it.symbol.length } + + if (matchingCurrencies.isEmpty()) return null + + // If we have multiple matches (e.g. SEK and NOK both use "kr"), try to use the default currency + // Otherwise, pick the first one (which is deterministic but might be wrong if ambiguous) + // Note: Since we sorted by length, "kr." (DKK) will come before "kr" (SEK/NOK), which is correct behavior. + // The ambiguity is mainly between SEK and NOK. + val currency = if (matchingCurrencies.size > 1 && defaultCurrency != null) { + if (matchingCurrencies.contains(defaultCurrency)) { + defaultCurrency + } else { + matchingCurrencies.first() + } + } else { + matchingCurrencies.first() + } // Extract the numeric part (remove symbol) - var numericPart = formatted.drop(1).trim() + var numericPart = formatted.drop(currency.symbol.length).trim() // Normalize the input: handle both comma and period as decimal separators // First, determine if comma is used as thousand separator or decimal separator diff --git a/app/src/main/java/com/electricdreams/numo/core/util/CurrencyManager.kt b/app/src/main/java/com/electricdreams/numo/core/util/CurrencyManager.kt index d6cb5208..aba82719 100644 --- a/app/src/main/java/com/electricdreams/numo/core/util/CurrencyManager.kt +++ b/app/src/main/java/com/electricdreams/numo/core/util/CurrencyManager.kt @@ -24,6 +24,9 @@ class CurrencyManager private constructor(context: Context) { const val CURRENCY_EUR = "EUR" const val CURRENCY_GBP = "GBP" const val CURRENCY_JPY = "JPY" + const val CURRENCY_DKK = "DKK" + const val CURRENCY_SEK = "SEK" + const val CURRENCY_NOK = "NOK" // Default currency is USD private const val DEFAULT_CURRENCY = CURRENCY_USD @@ -68,6 +71,9 @@ class CurrencyManager private constructor(context: Context) { CURRENCY_GBP -> "£" CURRENCY_JPY -> "¥" CURRENCY_USD -> "$" + CURRENCY_DKK -> "kr." + CURRENCY_SEK -> "kr" + CURRENCY_NOK -> "kr" else -> "$" } @@ -93,7 +99,8 @@ class CurrencyManager private constructor(context: Context) { /** Check if a currency code is valid and supported. */ fun isValidCurrency(currencyCode: String?): Boolean { return when (currencyCode) { - CURRENCY_USD, CURRENCY_EUR, CURRENCY_GBP, CURRENCY_JPY -> true + CURRENCY_USD, CURRENCY_EUR, CURRENCY_GBP, CURRENCY_JPY, + CURRENCY_DKK, CURRENCY_SEK, CURRENCY_NOK -> true else -> false } } diff --git a/app/src/main/java/com/electricdreams/numo/core/util/ReceiptPrinter.kt b/app/src/main/java/com/electricdreams/numo/core/util/ReceiptPrinter.kt index e8ed35af..6d806cd8 100644 --- a/app/src/main/java/com/electricdreams/numo/core/util/ReceiptPrinter.kt +++ b/app/src/main/java/com/electricdreams/numo/core/util/ReceiptPrinter.kt @@ -284,8 +284,18 @@ class ReceiptPrinter(private val context: Context) { // Bitcoin price at time of transaction data.bitcoinPrice?.let { price -> - val formattedPrice = String.format(Locale.US, "$%,.2f", price) - sb.appendLine(leftRight("BTC/USD Rate:", formattedPrice)) + val priceCurrencyCode = data.basket?.currency ?: data.enteredCurrency + val priceCurrency = if (priceCurrencyCode.equals("BTC", ignoreCase = true) || priceCurrencyCode.equals("sat", ignoreCase = true)) { + Amount.Currency.USD + } else { + Amount.Currency.fromCode(priceCurrencyCode) + } + + // Format price using Amount class + val priceMinorUnits = kotlin.math.round(price * 100).toLong() + val formattedPrice = Amount(priceMinorUnits, priceCurrency).toString() + + sb.appendLine(leftRight("BTC/${priceCurrency.name} Rate:", formattedPrice)) } sb.appendLine() @@ -590,10 +600,22 @@ class ReceiptPrinter(private val context: Context) { $tipSectionHtml - ${data.bitcoinPrice?.let { """ + ${data.bitcoinPrice?.let { price -> + val priceCurrencyCode = data.basket?.currency ?: data.enteredCurrency + val priceCurrency = if (priceCurrencyCode.equals("BTC", ignoreCase = true) || priceCurrencyCode.equals("sat", ignoreCase = true)) { + Amount.Currency.USD + } else { + Amount.Currency.fromCode(priceCurrencyCode) + } + + // Format price using Amount class + val priceMinorUnits = kotlin.math.round(price * 100).toLong() + val formattedPrice = Amount(priceMinorUnits, priceCurrency).toString() + + """
- BTC/USD Rate: - ${String.format(Locale.US, "$%,.2f", it)} + BTC/${priceCurrency.name} Rate: + $formattedPrice
""" } ?: ""} diff --git a/app/src/main/java/com/electricdreams/numo/core/worker/BitcoinPriceWorker.kt b/app/src/main/java/com/electricdreams/numo/core/worker/BitcoinPriceWorker.kt index 76315751..19b1d483 100644 --- a/app/src/main/java/com/electricdreams/numo/core/worker/BitcoinPriceWorker.kt +++ b/app/src/main/java/com/electricdreams/numo/core/worker/BitcoinPriceWorker.kt @@ -101,6 +101,9 @@ class BitcoinPriceWorker private constructor(context: Context) { CurrencyManager.CURRENCY_EUR, CurrencyManager.CURRENCY_GBP, CurrencyManager.CURRENCY_JPY, + CurrencyManager.CURRENCY_DKK, + CurrencyManager.CURRENCY_SEK, + CurrencyManager.CURRENCY_NOK, ) for (currency in supportedCurrencies) { diff --git a/app/src/main/java/com/electricdreams/numo/feature/history/TransactionDetailActivity.kt b/app/src/main/java/com/electricdreams/numo/feature/history/TransactionDetailActivity.kt index e9f86d5b..cca2fad2 100644 --- a/app/src/main/java/com/electricdreams/numo/feature/history/TransactionDetailActivity.kt +++ b/app/src/main/java/com/electricdreams/numo/feature/history/TransactionDetailActivity.kt @@ -133,40 +133,22 @@ class TransactionDetailActivity : AppCompatActivity() { val amountSubtitleText: TextView = findViewById(R.id.detail_amount_subtitle) val amountValueText: TextView = findViewById(R.id.detail_amount_value) - // Parse basket to determine display mode - val basket = CheckoutBasket.fromJson(checkoutBasketJson) - val showSatsAsPrimary = basket?.let { - it.hasMixedPriceTypes() || it.getFiatItems().isEmpty() - } ?: (entry.getEntryUnit() == "sat") - // Use BASE amount (excluding tip) for display - this is what was sold val baseAmountSats = entry.getBaseAmountSats() val baseSatAmount = Amount(baseAmountSats, Amount.Currency.BTC) - - if (showSatsAsPrimary) { - // Primary: Sats (base amount) - amountText.text = baseSatAmount.toString() - amountValueText.text = baseSatAmount.toString() - - // Secondary: Fiat equivalent - if (entry.enteredAmount > 0 && entry.getEntryUnit() != "sat") { - val entryCurrency = Amount.Currency.fromCode(entry.getEntryUnit()) - val fiatAmount = Amount(entry.enteredAmount, entryCurrency) - amountSubtitleText.text = "≈ $fiatAmount" - amountSubtitleText.visibility = View.VISIBLE - } else { - amountSubtitleText.visibility = View.GONE - } - } else { - // Primary: Fiat (entered amount - which is the base amount) + + // Amount is ALWAYS the settlement one in sats (per user request) + amountText.text = baseSatAmount.toString() + amountValueText.text = baseSatAmount.toString() + + // Secondary: Fiat equivalent (if applicable) + if (entry.enteredAmount > 0 && entry.getEntryUnit() != "sat") { val entryCurrency = Amount.Currency.fromCode(entry.getEntryUnit()) val fiatAmount = Amount(entry.enteredAmount, entryCurrency) - amountText.text = fiatAmount.toString() - amountValueText.text = fiatAmount.toString() - - // Secondary: Sats paid (base amount, not total) - amountSubtitleText.text = baseSatAmount.toString() + amountSubtitleText.text = "≈ $fiatAmount" amountSubtitleText.visibility = View.VISIBLE + } else { + amountSubtitleText.visibility = View.GONE } // Date @@ -227,7 +209,7 @@ class TransactionDetailActivity : AppCompatActivity() { if (entry.getEntryUnit() != "sat") { val entryCurrency = Amount.Currency.fromCode(entry.getEntryUnit()) val enteredAmount = Amount(entry.enteredAmount, entryCurrency) - enteredAmountText.text = enteredAmount.toString() + enteredAmountText.text = enteredAmount.toStringWithoutSymbol() enteredAmountRow.visibility = View.VISIBLE enteredAmountDivider.visibility = View.VISIBLE } else { @@ -242,7 +224,26 @@ class TransactionDetailActivity : AppCompatActivity() { val btcPrice = entry.bitcoinPrice if (btcPrice != null && btcPrice > 0) { - val formattedPrice = String.format(Locale.US, "$%,.2f", btcPrice) + // Determine the correct currency for the Bitcoin price. + // 1. If entry unit is a fiat currency, use that. + // 2. If available, check the checkout basket currency. + // 3. Fallback to USD (default behavior). + val currencyCode = if (entry.getEntryUnit() != "sat" && entry.getEntryUnit() != "BTC") { + entry.getEntryUnit() + } else { + val basket = CheckoutBasket.fromJson(checkoutBasketJson) + basket?.currency ?: "USD" + } + + val currency = Amount.Currency.fromCode(currencyCode) + // If we somehow still resolved to BTC (e.g. basket had "SAT"), force USD for price display + val priceCurrency = if (currency == Amount.Currency.BTC) Amount.Currency.USD else currency + + // Format price using Amount class to respect locale and currency symbol + // Amount expects minor units (cents), so multiply by 100 + val priceMinorUnits = kotlin.math.round(btcPrice * 100).toLong() + val formattedPrice = Amount(priceMinorUnits, priceCurrency).toString() + bitcoinPriceText.text = formattedPrice bitcoinPriceRow.visibility = View.VISIBLE bitcoinPriceDivider.visibility = View.VISIBLE diff --git a/app/src/main/java/com/electricdreams/numo/feature/settings/CurrencySettingsActivity.kt b/app/src/main/java/com/electricdreams/numo/feature/settings/CurrencySettingsActivity.kt index 2e3448ae..60b2c29d 100644 --- a/app/src/main/java/com/electricdreams/numo/feature/settings/CurrencySettingsActivity.kt +++ b/app/src/main/java/com/electricdreams/numo/feature/settings/CurrencySettingsActivity.kt @@ -15,6 +15,9 @@ class CurrencySettingsActivity : AppCompatActivity() { private lateinit var radioEur: RadioButton private lateinit var radioGbp: RadioButton private lateinit var radioJpy: RadioButton + private lateinit var radioDkk: RadioButton + private lateinit var radioSek: RadioButton + private lateinit var radioNok: RadioButton private lateinit var currencyManager: CurrencyManager override fun onCreate(savedInstanceState: Bundle?) { @@ -30,6 +33,9 @@ class CurrencySettingsActivity : AppCompatActivity() { radioEur = findViewById(R.id.radio_eur) radioGbp = findViewById(R.id.radio_gbp) radioJpy = findViewById(R.id.radio_jpy) + radioDkk = findViewById(R.id.radio_dkk) + radioSek = findViewById(R.id.radio_sek) + radioNok = findViewById(R.id.radio_nok) setSelectedCurrency(currencyManager.getCurrentCurrency()) @@ -45,6 +51,9 @@ class CurrencySettingsActivity : AppCompatActivity() { CurrencyManager.CURRENCY_GBP -> radioGbp.isChecked = true CurrencyManager.CURRENCY_JPY -> radioJpy.isChecked = true CurrencyManager.CURRENCY_USD -> radioUsd.isChecked = true + CurrencyManager.CURRENCY_DKK -> radioDkk.isChecked = true + CurrencyManager.CURRENCY_SEK -> radioSek.isChecked = true + CurrencyManager.CURRENCY_NOK -> radioNok.isChecked = true else -> radioUsd.isChecked = true } } @@ -55,6 +64,9 @@ class CurrencySettingsActivity : AppCompatActivity() { R.id.radio_eur -> CurrencyManager.CURRENCY_EUR R.id.radio_gbp -> CurrencyManager.CURRENCY_GBP R.id.radio_jpy -> CurrencyManager.CURRENCY_JPY + R.id.radio_dkk -> CurrencyManager.CURRENCY_DKK + R.id.radio_sek -> CurrencyManager.CURRENCY_SEK + R.id.radio_nok -> CurrencyManager.CURRENCY_NOK else -> CurrencyManager.CURRENCY_USD } } diff --git a/app/src/main/java/com/electricdreams/numo/feature/tips/TipSelectionActivity.kt b/app/src/main/java/com/electricdreams/numo/feature/tips/TipSelectionActivity.kt index 72bf81f3..5e24bfcf 100644 --- a/app/src/main/java/com/electricdreams/numo/feature/tips/TipSelectionActivity.kt +++ b/app/src/main/java/com/electricdreams/numo/feature/tips/TipSelectionActivity.kt @@ -132,6 +132,20 @@ class TipSelectionActivity : AppCompatActivity() { if (entryCurrency != Currency.BTC) { enteredAmountFiat = parsedAmount.value } + } else { + // Fallback parsing with current system currency if implicit parsing fails + // (e.g. for ambiguous symbols like "kr") + val currencyManager = com.electricdreams.numo.core.util.CurrencyManager.getInstance(this) + val currentCurrencyCode = currencyManager.getCurrentCurrency() + val currentCurrency = Amount.Currency.fromCode(currentCurrencyCode) + val parsedWithContext = Amount.parse(formattedAmount, currentCurrency) + + if (parsedWithContext != null) { + entryCurrency = parsedWithContext.currency + if (entryCurrency != Currency.BTC) { + enteredAmountFiat = parsedWithContext.value + } + } } // Set default for custom input based on entry currency @@ -838,8 +852,7 @@ class TipSelectionActivity : AppCompatActivity() { } val totalFiat = (enteredAmountFiat / 100.0) + tipFiat // Format as currency - val symbol = entryCurrency.symbol - "${symbol}${String.format("%.2f", totalFiat)}" + Amount(kotlin.math.round(totalFiat * 100).toLong(), entryCurrency).toString() } else { formattedAmount } diff --git a/app/src/main/res/layout/activity_currency_settings.xml b/app/src/main/res/layout/activity_currency_settings.xml index 03191649..f516b26c 100644 --- a/app/src/main/res/layout/activity_currency_settings.xml +++ b/app/src/main/res/layout/activity_currency_settings.xml @@ -120,6 +120,45 @@ android:paddingHorizontal="24dp" android:text="@string/currency_settings_option_jpy" android:textAppearance="@style/Text.BodyBold" /> + + + + + + diff --git a/app/src/main/res/values-es/strings_settings.xml b/app/src/main/res/values-es/strings_settings.xml index 5fe28039..9b358b82 100644 --- a/app/src/main/res/values-es/strings_settings.xml +++ b/app/src/main/res/values-es/strings_settings.xml @@ -24,6 +24,9 @@ Euro (EUR) Libra esterlina (GBP) Yen japonés (JPY) + Corona danesa (DKK) + Corona sueca (SEK) + Corona noruega (NOK) Mints diff --git a/app/src/main/res/values/strings_settings.xml b/app/src/main/res/values/strings_settings.xml index 9aab49fe..f496831d 100644 --- a/app/src/main/res/values/strings_settings.xml +++ b/app/src/main/res/values/strings_settings.xml @@ -24,6 +24,9 @@ Euro (EUR) British Pound (GBP) Japanese Yen (JPY) + Danish Krone (DKK) + Swedish Krona (SEK) + Norwegian Krone (NOK) Mints diff --git a/app/src/test/java/com/electricdreams/numo/core/model/AmountTest.kt b/app/src/test/java/com/electricdreams/numo/core/model/AmountTest.kt new file mode 100644 index 00000000..b03b3f09 --- /dev/null +++ b/app/src/test/java/com/electricdreams/numo/core/model/AmountTest.kt @@ -0,0 +1,103 @@ +package com.electricdreams.numo.core.model + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import java.util.Locale + +class AmountTest { + + @Test + fun `parse handles single character symbols`() { + val usd = Amount.parse("$10.50") + assertEquals(Amount.Currency.USD, usd?.currency) + assertEquals(1050L, usd?.value) + + val eur = Amount.parse("€10,50") + assertEquals(Amount.Currency.EUR, eur?.currency) + assertEquals(1050L, eur?.value) + + val gbp = Amount.parse("£10.50") + assertEquals(Amount.Currency.GBP, gbp?.currency) + assertEquals(1050L, gbp?.value) + + val jpy = Amount.parse("¥100") + assertEquals(Amount.Currency.JPY, jpy?.currency) + assertEquals(10000L, jpy?.value) // JPY stored as cents (100 * 100) + } + + @Test + fun `parse handles multi-character symbols`() { + val dkk = Amount.parse("kr. 100,50") + assertEquals(Amount.Currency.DKK, dkk?.currency) + assertEquals(10050L, dkk?.value) + + // DKK "kr." is unique, so it should be found without hint + val dkk2 = Amount.parse("kr.100,50") + assertEquals(Amount.Currency.DKK, dkk2?.currency) + } + + @Test + fun `parse handles ambiguous symbols with default currency`() { + // "kr" is ambiguous between SEK and NOK + // Without default, it might pick the first one (SEK in enum order if sorted by length equal) + // Wait, DKK is "kr.", SEK is "kr", NOK is "kr". + + // Test SEK preference + val sek = Amount.parse("kr 100,50", Amount.Currency.SEK) + assertEquals(Amount.Currency.SEK, sek?.currency) + assertEquals(10050L, sek?.value) + + // Test NOK preference + val nok = Amount.parse("kr 100,50", Amount.Currency.NOK) + assertEquals(Amount.Currency.NOK, nok?.currency) + assertEquals(10050L, nok?.value) + } + + @Test + fun `parse returns first match if ambiguous and no default provided`() { + val result = Amount.parse("kr 100,50") + // It should match either SEK or NOK. + // Logic sorts by length desc. "kr" length 2. + // Filter matches SEK and NOK. + // Returns first. + assert(result?.currency == Amount.Currency.SEK || result?.currency == Amount.Currency.NOK) + } + + @Test + fun `parse handles multi-character symbols without space`() { + val dkk = Amount.parse("kr.100,50") + assertEquals(Amount.Currency.DKK, dkk?.currency) + assertEquals(10050L, dkk?.value) + } + + @Test + fun `parse returns null for invalid input`() { + assertNull(Amount.parse("")) + assertNull(Amount.parse("INVALID")) + assertNull(Amount.parse("XYZ 100")) + } + + @Test + fun `toString formats correctly`() { + // Force US locale for consistent testing of USD + val usd = Amount(1050, Amount.Currency.USD) + // Locale.US uses period + assertEquals("$10.50", usd.toString()) + + // DKK uses comma + val dkk = Amount(1050, Amount.Currency.DKK) + // Locale("da", "DK") uses comma for decimal and period for thousands + // We expect "kr.10,50" or "kr. 10,50" depending on NumberFormat implementation + // Broad check for prefix and suffix + val dkkStr = dkk.toString() + assert(dkkStr.startsWith("kr.")) + assert(dkkStr.contains("10,50")) + + // SEK uses comma + val sek = Amount(1050, Amount.Currency.SEK) + val sekStr = sek.toString() + assert(sekStr.startsWith("kr")) + assert(sekStr.contains("10,50")) + } +} diff --git a/app/src/test/java/com/electricdreams/numo/core/util/CurrencyManagerTest.kt b/app/src/test/java/com/electricdreams/numo/core/util/CurrencyManagerTest.kt index f659eea0..9ec27ca9 100644 --- a/app/src/test/java/com/electricdreams/numo/core/util/CurrencyManagerTest.kt +++ b/app/src/test/java/com/electricdreams/numo/core/util/CurrencyManagerTest.kt @@ -109,4 +109,35 @@ class CurrencyManagerTest { currencyManager.setPreferredCurrency("USD") assertEquals("https://api.coinbase.com/v2/prices/BTC-USD/spot", currencyManager.getCoinbaseApiUrl()) } + + @Test + fun `isValidCurrency supports Nordic currencies`() { + assertTrue(currencyManager.isValidCurrency("DKK")) + assertTrue(currencyManager.isValidCurrency("SEK")) + assertTrue(currencyManager.isValidCurrency("NOK")) + } + + @Test + fun `getCurrentSymbol returns correct symbols for Nordic currencies`() { + currencyManager.setPreferredCurrency("DKK") + assertEquals("kr.", currencyManager.getCurrentSymbol()) + + currencyManager.setPreferredCurrency("SEK") + assertEquals("kr", currencyManager.getCurrentSymbol()) + + currencyManager.setPreferredCurrency("NOK") + assertEquals("kr", currencyManager.getCurrentSymbol()) + } + + @Test + fun `getCoinbaseApiUrl returns correct URL for Nordic currencies`() { + currencyManager.setPreferredCurrency("DKK") + assertEquals("https://api.coinbase.com/v2/prices/BTC-DKK/spot", currencyManager.getCoinbaseApiUrl()) + + currencyManager.setPreferredCurrency("SEK") + assertEquals("https://api.coinbase.com/v2/prices/BTC-SEK/spot", currencyManager.getCoinbaseApiUrl()) + + currencyManager.setPreferredCurrency("NOK") + assertEquals("https://api.coinbase.com/v2/prices/BTC-NOK/spot", currencyManager.getCoinbaseApiUrl()) + } }