Simplify Manual source UI to just the default currency

The manual rate source only ever prices the default currency, so the
currency selector, additional currency rows, and the "updated" part
of the status line no longer make sense for it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
This commit is contained in:
2026-09-09 08:56:24 +03:00
co-authored by Claude Sonnet 5
parent f21bdd48f8
commit dda836274c
3 changed files with 39 additions and 25 deletions
+21 -15
View File
@@ -111,18 +111,24 @@ struct ContentView: View {
} }
Section(IosLocalizationKt.localizedString(resource: MR.strings.shared.currencies_section_title)) { Section(IosLocalizationKt.localizedString(resource: MR.strings.shared.currencies_section_title)) {
Button( if !state.isManualSource {
state.selectedCurrencyCodes.count <= 1 Button(
? IosLocalizationKt.localizedString(resource: MR.strings.shared.add_currency) state.selectedCurrencyCodes.count <= 1
: IosLocalizationKt.localizedFormattedString( ? IosLocalizationKt.localizedString(resource: MR.strings.shared.add_currency)
resource: MR.strings.shared.currencies_selected_count, : IosLocalizationKt.localizedFormattedString(
args: [state.selectedCurrencyCodes.count] resource: MR.strings.shared.currencies_selected_count,
) args: [state.selectedCurrencyCodes.count]
) { )
showCurrencyPicker = true ) {
showCurrencyPicker = true
}
} }
ForEach(Array(state.fiatRows.enumerated()), id: \.element.code) { index, row in let displayedRows = state.isManualSource
? state.fiatRows.filter { $0.code == state.defaultCurrencyCode }
: state.fiatRows
ForEach(Array(displayedRows.enumerated()), id: \.element.code) { index, row in
amountRow( amountRow(
label: currencyFieldLabel(for: row.code), label: currencyFieldLabel(for: row.code),
value: row.amount, value: row.amount,
@@ -132,12 +138,12 @@ struct ContentView: View {
isPriced: state.pricedCurrencyCodes.contains(row.code), isPriced: state.pricedCurrencyCodes.contains(row.code),
sourceName: state.sourceName, sourceName: state.sourceName,
onMoveUp: index > 0 ? { onMoveUp: index > 0 ? {
var codes = state.fiatRows.map(\.code) var codes = displayedRows.map(\.code)
codes.move(fromOffsets: [index], toOffset: index - 1) codes.move(fromOffsets: [index], toOffset: index - 1)
viewModel.onFiatCurrenciesReordered(codes) viewModel.onFiatCurrenciesReordered(codes)
} : nil, } : nil,
onMoveDown: index < state.fiatRows.count - 1 ? { onMoveDown: index < displayedRows.count - 1 ? {
var codes = state.fiatRows.map(\.code) var codes = displayedRows.map(\.code)
codes.move(fromOffsets: [index], toOffset: index + 2) codes.move(fromOffsets: [index], toOffset: index + 2)
viewModel.onFiatCurrenciesReordered(codes) viewModel.onFiatCurrenciesReordered(codes)
} : nil } : nil
@@ -145,14 +151,14 @@ struct ContentView: View {
.deleteDisabled(row.code == state.defaultCurrencyCode) .deleteDisabled(row.code == state.defaultCurrencyCode)
} }
.onMove { indices, newOffset in .onMove { indices, newOffset in
var codes = state.fiatRows.map(\.code) var codes = displayedRows.map(\.code)
codes.move(fromOffsets: indices, toOffset: newOffset) codes.move(fromOffsets: indices, toOffset: newOffset)
viewModel.onFiatCurrenciesReordered(codes) viewModel.onFiatCurrenciesReordered(codes)
} }
#if os(iOS) #if os(iOS)
.onDelete { indexSet in .onDelete { indexSet in
for index in indexSet { for index in indexSet {
viewModel.onFiatCurrencyToggled(state.fiatRows[index].code) viewModel.onFiatCurrencyToggled(displayedRows[index].code)
} }
} }
#endif #endif
@@ -10,6 +10,7 @@ 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 { fun ConverterUiState.statusLine(): String {
if (isManualSource) return if (sourceName.isEmpty()) "" else "via $sourceName"
val updated = lastUpdated?.let { "updated ${it.toDateTimeString()}" } ?: "loading rates…" val updated = lastUpdated?.let { "updated ${it.toDateTimeString()}" } ?: "loading rates…"
return if (sourceName.isEmpty()) updated else "via $sourceName, $updated" return if (sourceName.isEmpty()) updated else "via $sourceName, $updated"
} }
@@ -311,18 +311,25 @@ fun PriceScreen(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text(stringResource(MR.strings.currencies_section_title), style = MaterialTheme.typography.titleMedium) Text(stringResource(MR.strings.currencies_section_title), style = MaterialTheme.typography.titleMedium)
OutlinedButton(onClick = { showCurrencyPicker = true }) { if (!state.isManualSource) {
Text( OutlinedButton(onClick = { showCurrencyPicker = true }) {
if (state.selectedFiatCurrencies.size <= 1) { Text(
stringResource(MR.strings.add_currency) if (state.selectedFiatCurrencies.size <= 1) {
} else { stringResource(MR.strings.add_currency)
stringResource(MR.strings.currencies_selected_count, state.selectedFiatCurrencies.size) } else {
}, stringResource(MR.strings.currencies_selected_count, state.selectedFiatCurrencies.size)
) },
)
}
} }
} }
state.selectedFiatCurrencies.forEachIndexed { index, code -> val displayedCurrencies = if (state.isManualSource) {
listOf(state.defaultCurrencyCode)
} else {
state.selectedFiatCurrencies
}
displayedCurrencies.forEachIndexed { index, code ->
key(code) { key(code) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@@ -350,7 +357,7 @@ fun PriceScreen(
CurrencyRowMenu( CurrencyRowMenu(
code = code, code = code,
canMoveUp = index > 0, canMoveUp = index > 0,
canMoveDown = index < state.selectedFiatCurrencies.lastIndex, canMoveDown = index < displayedCurrencies.lastIndex,
canRemove = code != state.defaultCurrencyCode, canRemove = code != state.defaultCurrencyCode,
onMoveUp = { onMoveUp = {
viewModel.onFiatCurrenciesReordered( viewModel.onFiatCurrenciesReordered(