diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift index ebe6d1b..53759a7 100644 --- a/iosApp/iosApp/ContentView.swift +++ b/iosApp/iosApp/ContentView.swift @@ -37,6 +37,21 @@ struct ContentView: View { : state.fiatRows } + /// Nil for Manual (a manually typed rate has no "last updated" moment to show). Doesn't name + /// the price source — just when the rate was last fetched. + private func statusText(for state: IosConverterState) -> String? { + if state.isManualSource { + return nil + } + if let dateTime = state.lastUpdatedDateTime { + return IosLocalizationKt.localizedFormattedString( + resource: MR.strings.shared.updated_status, + args: [dateTime] + ) + } + return IosLocalizationKt.localizedString(resource: MR.strings.shared.loading_rates_status) + } + #if os(macOS) /// [codes] with [moving] relocated to sit right before [target] — how macOS's manual /// drag-and-drop (see `.dropDestination` above) computes its new currency order, since @@ -56,8 +71,8 @@ struct ContentView: View { Form { Section( footer: Group { - if !state.statusLine.isEmpty { - Text(state.statusLine) + if let statusText = statusText(for: state) { + Text(statusText) } } ) { diff --git a/shared/src/appleMain/kotlin/xyz/tyiu/satsprice/IosPriceViewModel.kt b/shared/src/appleMain/kotlin/xyz/tyiu/satsprice/IosPriceViewModel.kt index 357b116..7c59a8e 100644 --- a/shared/src/appleMain/kotlin/xyz/tyiu/satsprice/IosPriceViewModel.kt +++ b/shared/src/appleMain/kotlin/xyz/tyiu/satsprice/IosPriceViewModel.kt @@ -9,9 +9,9 @@ import xyz.tyiu.satsprice.ui.PriceViewModel import xyz.tyiu.satsprice.ui.currentCurrency import xyz.tyiu.satsprice.ui.defaultCurrencyRate import xyz.tyiu.satsprice.ui.exceedsMaxSupply +import xyz.tyiu.satsprice.ui.lastUpdatedDateTime import xyz.tyiu.satsprice.ui.oneCurrencyToSats import xyz.tyiu.satsprice.ui.selectedOtherCurrencies -import xyz.tyiu.satsprice.ui.statusLine import xyz.tyiu.satsprice.ui.unselectedCurrencies data class FiatRow(val code: String, val amount: String, val rateDisplay: String) @@ -34,7 +34,7 @@ data class IosConverterState( val manualSatsPerCurrencyInput: String, val isLoading: Boolean, val errorMessage: String?, - val statusLine: String, + val lastUpdatedDateTime: String?, val defaultCurrencyRate: String, val oneCurrencyToSats: String, ) @@ -89,7 +89,7 @@ private fun ConverterUiState.toIosState(): IosConverterState = IosConverterState manualSatsPerCurrencyInput = manualSatsPerCurrencyInput, isLoading = isLoading, errorMessage = errorMessage, - statusLine = statusLine(), + lastUpdatedDateTime = lastUpdatedDateTime(), defaultCurrencyRate = defaultCurrencyRate(), oneCurrencyToSats = oneCurrencyToSats(), ) diff --git a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/ConverterUiStateDisplay.kt b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/ConverterUiStateDisplay.kt index 357bbb5..24945ff 100644 --- a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/ConverterUiStateDisplay.kt +++ b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/ConverterUiStateDisplay.kt @@ -11,10 +11,16 @@ import kotlin.time.Instant /** Derived display strings/flags shared between the Compose UI and the iOS SwiftUI bridge. */ -fun ConverterUiState.statusLine(): String { - if (isManualSource) return "" - val updated = lastUpdated?.let { "updated ${it.toDateTimeString()}" } ?: "loading rates…" - return if (sourceName.isEmpty()) updated else "via $sourceName, $updated" +/** + * The current platform's locale-formatted rendering of [ConverterUiState.lastUpdated] — just the + * date/time itself, not the surrounding localized "Updated ..."/"Loading rates…" text, since this + * shared code has no Composable/moko-resources context to resolve a localized string from; the UI + * layer supplies that around whatever this returns. Null while manual (nothing to show — a + * manually typed rate has no "last updated" moment) or before the first fetch completes. + */ +fun ConverterUiState.lastUpdatedDateTime(): String? { + if (isManualSource) return null + return lastUpdated?.toDateTimeString() } fun ConverterUiState.exceedsMaxSupply(): Boolean { diff --git a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceScreen.kt b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceScreen.kt index f1e7183..1ecf2b3 100644 --- a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceScreen.kt +++ b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceScreen.kt @@ -141,8 +141,13 @@ fun PriceScreen( ) { Column(modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) { Text("SatsPrice", style = MaterialTheme.typography.headlineMedium) - val statusLine = state.statusLine() - if (statusLine.isNotEmpty()) { + val statusLine = if (state.isManualSource) { + null + } else { + state.lastUpdatedDateTime()?.let { stringResource(MR.strings.updated_status, it) } + ?: stringResource(MR.strings.loading_rates_status) + } + if (statusLine != null) { Text( text = statusLine, style = MaterialTheme.typography.bodySmall, diff --git a/shared/src/commonMain/moko-resources/base/strings.xml b/shared/src/commonMain/moko-resources/base/strings.xml index 442d3b2..2129553 100644 --- a/shared/src/commonMain/moko-resources/base/strings.xml +++ b/shared/src/commonMain/moko-resources/base/strings.xml @@ -15,6 +15,7 @@ %1$s to Sats Done Exceeds the %1$s maximum supply + Loading rates… Move down Move to bottom Move to top @@ -31,4 +32,5 @@ Search currencies Selected Currencies Unpriced Currencies + Updated %1$s