zcash-android-wallet-sdk/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ext/ui/ZatoshiExt.kt

91 lines
3.4 KiB
Kotlin

@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)
}