Drop the source name from the status line, make it localized
statusLine() used to build the whole "via Coinbase, updated ..."
string in shared code with hardcoded English literals ("updated",
"loading rates…", "via ") — not localizable, since this shared code
has no Composable/moko-resources context to resolve a string from,
and said more than needed (the source is already shown in the Price
Source picker right above it).
Replaced with lastUpdatedDateTime(): String?, which returns only the
locale-formatted date/time (still shared, since that part is genuine
platform-native locale formatting, not translated text) — null for
Manual, or while the first fetch hasn't completed. Each UI layer now
builds the localized "Updated %1$s" / "Loading rates…" text itself
via stringResource()/IosLocalizationKt around that value, using two
new string resources.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
This commit is contained in:
@@ -37,6 +37,21 @@ struct ContentView: View {
|
|||||||
: state.fiatRows
|
: 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)
|
#if os(macOS)
|
||||||
/// [codes] with [moving] relocated to sit right before [target] — how macOS's manual
|
/// [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
|
/// drag-and-drop (see `.dropDestination` above) computes its new currency order, since
|
||||||
@@ -56,8 +71,8 @@ struct ContentView: View {
|
|||||||
Form {
|
Form {
|
||||||
Section(
|
Section(
|
||||||
footer: Group {
|
footer: Group {
|
||||||
if !state.statusLine.isEmpty {
|
if let statusText = statusText(for: state) {
|
||||||
Text(state.statusLine)
|
Text(statusText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import xyz.tyiu.satsprice.ui.PriceViewModel
|
|||||||
import xyz.tyiu.satsprice.ui.currentCurrency
|
import xyz.tyiu.satsprice.ui.currentCurrency
|
||||||
import xyz.tyiu.satsprice.ui.defaultCurrencyRate
|
import xyz.tyiu.satsprice.ui.defaultCurrencyRate
|
||||||
import xyz.tyiu.satsprice.ui.exceedsMaxSupply
|
import xyz.tyiu.satsprice.ui.exceedsMaxSupply
|
||||||
|
import xyz.tyiu.satsprice.ui.lastUpdatedDateTime
|
||||||
import xyz.tyiu.satsprice.ui.oneCurrencyToSats
|
import xyz.tyiu.satsprice.ui.oneCurrencyToSats
|
||||||
import xyz.tyiu.satsprice.ui.selectedOtherCurrencies
|
import xyz.tyiu.satsprice.ui.selectedOtherCurrencies
|
||||||
import xyz.tyiu.satsprice.ui.statusLine
|
|
||||||
import xyz.tyiu.satsprice.ui.unselectedCurrencies
|
import xyz.tyiu.satsprice.ui.unselectedCurrencies
|
||||||
|
|
||||||
data class FiatRow(val code: String, val amount: String, val rateDisplay: String)
|
data class FiatRow(val code: String, val amount: String, val rateDisplay: String)
|
||||||
@@ -34,7 +34,7 @@ data class IosConverterState(
|
|||||||
val manualSatsPerCurrencyInput: String,
|
val manualSatsPerCurrencyInput: String,
|
||||||
val isLoading: Boolean,
|
val isLoading: Boolean,
|
||||||
val errorMessage: String?,
|
val errorMessage: String?,
|
||||||
val statusLine: String,
|
val lastUpdatedDateTime: String?,
|
||||||
val defaultCurrencyRate: String,
|
val defaultCurrencyRate: String,
|
||||||
val oneCurrencyToSats: String,
|
val oneCurrencyToSats: String,
|
||||||
)
|
)
|
||||||
@@ -89,7 +89,7 @@ private fun ConverterUiState.toIosState(): IosConverterState = IosConverterState
|
|||||||
manualSatsPerCurrencyInput = manualSatsPerCurrencyInput,
|
manualSatsPerCurrencyInput = manualSatsPerCurrencyInput,
|
||||||
isLoading = isLoading,
|
isLoading = isLoading,
|
||||||
errorMessage = errorMessage,
|
errorMessage = errorMessage,
|
||||||
statusLine = statusLine(),
|
lastUpdatedDateTime = lastUpdatedDateTime(),
|
||||||
defaultCurrencyRate = defaultCurrencyRate(),
|
defaultCurrencyRate = defaultCurrencyRate(),
|
||||||
oneCurrencyToSats = oneCurrencyToSats(),
|
oneCurrencyToSats = oneCurrencyToSats(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,10 +11,16 @@ import kotlin.time.Instant
|
|||||||
|
|
||||||
/** Derived display strings/flags shared between the Compose UI and the iOS SwiftUI bridge. */
|
/** Derived display strings/flags shared between the Compose UI and the iOS SwiftUI bridge. */
|
||||||
|
|
||||||
fun ConverterUiState.statusLine(): String {
|
/**
|
||||||
if (isManualSource) return ""
|
* The current platform's locale-formatted rendering of [ConverterUiState.lastUpdated] — just the
|
||||||
val updated = lastUpdated?.let { "updated ${it.toDateTimeString()}" } ?: "loading rates…"
|
* date/time itself, not the surrounding localized "Updated ..."/"Loading rates…" text, since this
|
||||||
return if (sourceName.isEmpty()) updated else "via $sourceName, $updated"
|
* 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 {
|
fun ConverterUiState.exceedsMaxSupply(): Boolean {
|
||||||
|
|||||||
@@ -141,8 +141,13 @@ fun PriceScreen(
|
|||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
|
Column(modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
|
||||||
Text("SatsPrice", style = MaterialTheme.typography.headlineMedium)
|
Text("SatsPrice", style = MaterialTheme.typography.headlineMedium)
|
||||||
val statusLine = state.statusLine()
|
val statusLine = if (state.isManualSource) {
|
||||||
if (statusLine.isNotEmpty()) {
|
null
|
||||||
|
} else {
|
||||||
|
state.lastUpdatedDateTime()?.let { stringResource(MR.strings.updated_status, it) }
|
||||||
|
?: stringResource(MR.strings.loading_rates_status)
|
||||||
|
}
|
||||||
|
if (statusLine != null) {
|
||||||
Text(
|
Text(
|
||||||
text = statusLine,
|
text = statusLine,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<string name="currency_to_sats">%1$s to Sats</string>
|
<string name="currency_to_sats">%1$s to Sats</string>
|
||||||
<string name="done">Done</string>
|
<string name="done">Done</string>
|
||||||
<string name="exceeds_max_supply">Exceeds the %1$s maximum supply</string>
|
<string name="exceeds_max_supply">Exceeds the %1$s maximum supply</string>
|
||||||
|
<string name="loading_rates_status">Loading rates…</string>
|
||||||
<string name="move_currency_down_content_description">Move down</string>
|
<string name="move_currency_down_content_description">Move down</string>
|
||||||
<string name="move_currency_to_bottom_content_description">Move to bottom</string>
|
<string name="move_currency_to_bottom_content_description">Move to bottom</string>
|
||||||
<string name="move_currency_to_top_content_description">Move to top</string>
|
<string name="move_currency_to_top_content_description">Move to top</string>
|
||||||
@@ -31,4 +32,5 @@
|
|||||||
<string name="search_currencies_placeholder">Search currencies</string>
|
<string name="search_currencies_placeholder">Search currencies</string>
|
||||||
<string name="selected_currencies_section_title">Selected Currencies</string>
|
<string name="selected_currencies_section_title">Selected Currencies</string>
|
||||||
<string name="unpriced_currencies_section_title">Unpriced Currencies</string>
|
<string name="unpriced_currencies_section_title">Unpriced Currencies</string>
|
||||||
|
<string name="updated_status">Updated %1$s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user