Add support for macOS and backport to older OS versions
This commit is contained in:
@@ -1,78 +0,0 @@
|
||||
package xyz.tyiu.satsprice
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import xyz.tyiu.satsprice.ui.ConverterUiState
|
||||
import xyz.tyiu.satsprice.ui.PriceViewModel
|
||||
import xyz.tyiu.satsprice.ui.defaultCurrencyRate
|
||||
import xyz.tyiu.satsprice.ui.exceedsMaxSupply
|
||||
import xyz.tyiu.satsprice.ui.statusLine
|
||||
|
||||
data class FiatRow(val code: String, val amount: String, val rateDisplay: String)
|
||||
|
||||
data class IosConverterState(
|
||||
val btcAmount: String,
|
||||
val satsAmount: String,
|
||||
val exceedsMaxSupply: Boolean,
|
||||
val fiatRows: List<FiatRow>,
|
||||
val availableCurrencies: List<CurrencyInfo>,
|
||||
val selectedCurrencyCodes: List<String>,
|
||||
val localeCurrencyCode: String?,
|
||||
val defaultCurrencyCode: String,
|
||||
val sourceName: String,
|
||||
val isManualSource: Boolean,
|
||||
val manualRateInput: String,
|
||||
val isLoading: Boolean,
|
||||
val errorMessage: String?,
|
||||
val statusLine: String,
|
||||
val defaultCurrencyRate: String,
|
||||
)
|
||||
|
||||
/**
|
||||
* Swift-facing bridge over [PriceViewModel]. Exposes a flattened, Map-free state shape
|
||||
* (Kotlin/Native's ObjC/Swift export handles `List<DataClass>` far better than `Map<K, V>`)
|
||||
* and observes via a plain callback rather than raw `Flow`, so no extra Swift interop
|
||||
* tooling (e.g. SKIE) is required.
|
||||
*/
|
||||
class IosPriceViewModel {
|
||||
private val viewModel = PriceViewModel()
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||
|
||||
val sourceNames: List<String> get() = viewModel.availableSources
|
||||
|
||||
fun observeState(onChange: (IosConverterState) -> Unit) {
|
||||
scope.launch {
|
||||
viewModel.uiState.collect { state -> onChange(state.toIosState()) }
|
||||
}
|
||||
}
|
||||
|
||||
fun refresh() = viewModel.refresh()
|
||||
fun onBtcAmountChanged(value: String) = viewModel.onBtcAmountChanged(value)
|
||||
fun onSatsAmountChanged(value: String) = viewModel.onSatsAmountChanged(value)
|
||||
fun onFiatAmountChanged(code: String, value: String) = viewModel.onFiatAmountChanged(code, value)
|
||||
fun onFiatCurrencyToggled(code: String) = viewModel.onFiatCurrencyToggled(code)
|
||||
fun onSourceSelected(name: String) = viewModel.onSourceSelected(name)
|
||||
fun onManualRateChanged(value: String) = viewModel.onManualRateChanged(value)
|
||||
}
|
||||
|
||||
private fun ConverterUiState.toIosState(): IosConverterState = IosConverterState(
|
||||
btcAmount = btcAmount,
|
||||
satsAmount = satsAmount,
|
||||
exceedsMaxSupply = exceedsMaxSupply(),
|
||||
fiatRows = selectedFiatCurrencies.map { code ->
|
||||
FiatRow(code, fiatAmounts[code].orEmpty(), rateDisplays[code].orEmpty())
|
||||
},
|
||||
availableCurrencies = availableFiatCurrencies,
|
||||
selectedCurrencyCodes = selectedFiatCurrencies,
|
||||
localeCurrencyCode = localeCurrencyCode,
|
||||
defaultCurrencyCode = defaultCurrencyCode,
|
||||
sourceName = sourceName,
|
||||
isManualSource = isManualSource,
|
||||
manualRateInput = manualRateInput,
|
||||
isLoading = isLoading,
|
||||
errorMessage = errorMessage,
|
||||
statusLine = statusLine(),
|
||||
defaultCurrencyRate = defaultCurrencyRate(),
|
||||
)
|
||||
@@ -1,20 +0,0 @@
|
||||
package xyz.tyiu.satsprice
|
||||
|
||||
import platform.Foundation.*
|
||||
|
||||
actual fun systemCurrencies(): List<CurrencyInfo> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val codes = NSLocale.Companion.ISOCurrencyCodes as List<String>
|
||||
return codes
|
||||
.map { code -> CurrencyInfo(code, NSLocale.currentLocale.localizedStringForCurrencyCode(code) ?: code) }
|
||||
.sortedBy { it.code }
|
||||
}
|
||||
|
||||
actual fun localeCurrencyCode(): String? = NSLocale.currentLocale.currencyCode
|
||||
|
||||
actual fun currencyDecimalDigits(code: String): Int {
|
||||
val formatter = NSNumberFormatter()
|
||||
formatter.numberStyle = NSNumberFormatterCurrencyStyle
|
||||
formatter.currencyCode = code
|
||||
return formatter.maximumFractionDigits.toInt()
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package xyz.tyiu.satsprice.ui
|
||||
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
// PriceScreen.kt is unused on iOS (native SwiftUI is used instead), but this module still
|
||||
// needs an actual to satisfy the expect declaration for this target.
|
||||
actual val screenHorizontalPadding: Dp = 16.dp
|
||||
@@ -1,11 +0,0 @@
|
||||
package xyz.tyiu.satsprice.ui
|
||||
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import dev.icerock.moko.resources.desc.ResourceFormatted
|
||||
import dev.icerock.moko.resources.desc.StringDesc
|
||||
import dev.icerock.moko.resources.desc.desc
|
||||
|
||||
fun localizedString(resource: StringResource): String = resource.desc().localized()
|
||||
|
||||
fun localizedFormattedString(resource: StringResource, args: List<Any>): String =
|
||||
StringDesc.ResourceFormatted(resource, args).localized()
|
||||
Reference in New Issue
Block a user