@file:Suppress("ktlint:filename") package cash.z.ecc.android.sdk.demoapp.ext.ui import cash.z.ecc.android.sdk.demoapp.model.CurrencyConversion import cash.z.ecc.android.sdk.demoapp.model.FiatCurrencyConversionRateState import cash.z.ecc.android.sdk.demoapp.model.Locale import cash.z.ecc.android.sdk.demoapp.model.MonetarySeparators import cash.z.ecc.android.sdk.demoapp.model.toJavaLocale import cash.z.ecc.android.sdk.ext.Conversions import cash.z.ecc.android.sdk.model.Zatoshi import kotlinx.datetime.Clock import java.math.BigDecimal import java.math.MathContext import java.math.RoundingMode import java.text.DecimalFormat import java.text.NumberFormat import java.util.Currency import kotlin.time.Duration fun Zatoshi.toFiatCurrencyState( currencyConversion: CurrencyConversion?, locale: Locale, monetarySeparators: MonetarySeparators, clock: Clock = Clock.System ): FiatCurrencyConversionRateState { if (currencyConversion == null) { return FiatCurrencyConversionRateState.Unavailable } val fiatCurrencyConversionRate = toFiatString(currencyConversion, locale, monetarySeparators) val currentSystemTime = clock.now() val age = currentSystemTime - currencyConversion.timestamp return if (age < Duration.ZERO && age.absoluteValue > FiatCurrencyConversionRateState.FUTURE_CUTOFF_AGE_INCLUSIVE) { // Special case if the device's clock is set to the future. // TODO [#535]: Consider using NTP requests to get the correct time instead of relying on the device's clock. FiatCurrencyConversionRateState.Unavailable } else if (age <= FiatCurrencyConversionRateState.CURRENT_CUTOFF_AGE_INCLUSIVE) { FiatCurrencyConversionRateState.Current(fiatCurrencyConversionRate) } else if (age <= FiatCurrencyConversionRateState.STALE_CUTOFF_AGE_INCLUSIVE) { FiatCurrencyConversionRateState.Stale(fiatCurrencyConversionRate) } else { FiatCurrencyConversionRateState.Unavailable } } fun Zatoshi.toFiatString( currencyConversion: CurrencyConversion, locale: Locale, monetarySeparators: MonetarySeparators ) = convertZatoshiToZecDecimal() .convertZecDecimalToFiatDecimal(BigDecimal(currencyConversion.priceOfZec)) .convertFiatDecimalToFiatString( Currency.getInstance(currencyConversion.fiatCurrency.code), locale.toJavaLocale(), monetarySeparators ) private fun Zatoshi.convertZatoshiToZecDecimal(): BigDecimal { return BigDecimal(value, MathContext.DECIMAL128).divide( Conversions.ONE_ZEC_IN_ZATOSHI, MathContext.DECIMAL128 ).setScale(Conversions.ZEC_FORMATTER.maximumFractionDigits, RoundingMode.HALF_EVEN) } private fun BigDecimal.convertZecDecimalToFiatDecimal(zecPrice: BigDecimal): BigDecimal { return multiply(zecPrice, MathContext.DECIMAL128) } private fun BigDecimal.convertFiatDecimalToFiatString( fiatCurrency: Currency, locale: java.util.Locale, monetarySeparators: MonetarySeparators ): String { return NumberFormat.getCurrencyInstance(locale).apply { currency = fiatCurrency roundingMode = RoundingMode.HALF_EVEN if (this is DecimalFormat) { decimalFormatSymbols.apply { decimalSeparator = monetarySeparators.decimal monetaryDecimalSeparator = monetarySeparators.decimal groupingSeparator = monetarySeparators.grouping } } }.format(this) }