diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift index f44e724..ebe6d1b 100644 --- a/iosApp/iosApp/ContentView.swift +++ b/iosApp/iosApp/ContentView.swift @@ -238,7 +238,9 @@ struct ContentView: View { pricedCurrencyCodes: state.pricedCurrencyCodes, sourceName: state.sourceName, localeCurrencyCode: state.localeCurrencyCode, - onToggle: { viewModel.onFiatCurrencyToggled($0) } + selectedCount: state.selectedCurrencyCodes.count, + onToggle: { viewModel.onFiatCurrencyToggled($0) }, + onReset: { viewModel.onSelectedCurrenciesReset() } ) } .environment(\.openURL, OpenURLAction { url in diff --git a/iosApp/iosApp/ConverterViewModel.swift b/iosApp/iosApp/ConverterViewModel.swift index 9fb7370..35b6eb4 100644 --- a/iosApp/iosApp/ConverterViewModel.swift +++ b/iosApp/iosApp/ConverterViewModel.swift @@ -39,6 +39,10 @@ final class ConverterViewModel: ObservableObject { bridge.onFiatCurrenciesReordered(newOrder: newOrder) } + func onSelectedCurrenciesReset() { + bridge.onSelectedCurrenciesReset() + } + func onSourceSelected(_ name: String) { bridge.onSourceSelected(name: name) } diff --git a/iosApp/iosApp/CurrencyPickerSheet.swift b/iosApp/iosApp/CurrencyPickerSheet.swift index 92de1f9..eaf6987 100644 --- a/iosApp/iosApp/CurrencyPickerSheet.swift +++ b/iosApp/iosApp/CurrencyPickerSheet.swift @@ -8,10 +8,13 @@ struct CurrencyPickerSheet: View { let pricedCurrencyCodes: [String] let sourceName: String let localeCurrencyCode: String? + let selectedCount: Int let onToggle: (String) -> Void + let onReset: () -> Void @Environment(\.dismiss) private var dismiss @State private var searchQuery = "" + @State private var showResetConfirmation = false private func matches(_ info: CurrencyInfo) -> Bool { SystemCurrenciesKt.matchesCurrencySearch(info: info, query: searchQuery) @@ -60,6 +63,16 @@ struct CurrencyPickerSheet: View { .navigationBarTitleDisplayMode(.inline) #endif .toolbar { + if selectedCount > 1 { + ToolbarItem(placement: .cancellationAction) { + Button( + IosLocalizationKt.localizedString(resource: MR.strings.shared.reset_selected_currencies_button), + role: .destructive + ) { + showResetConfirmation = true + } + } + } ToolbarItem(placement: .confirmationAction) { Button(IosLocalizationKt.localizedString(resource: MR.strings.shared.done)) { dismiss() } } @@ -74,6 +87,23 @@ struct CurrencyPickerSheet: View { text: $searchQuery, prompt: IosLocalizationKt.localizedString(resource: MR.strings.shared.search_currencies_placeholder) ) + .alert( + IosLocalizationKt.localizedString(resource: MR.strings.shared.reset_selected_currencies_confirmation_title), + isPresented: $showResetConfirmation + ) { + Button( + IosLocalizationKt.localizedString(resource: MR.strings.shared.reset_selected_currencies_button), + role: .destructive + ) { + onReset() + } + Button(IosLocalizationKt.localizedString(resource: MR.strings.shared.cancel), role: .cancel) {} + } message: { + Text(IosLocalizationKt.localizedFormattedString( + resource: MR.strings.shared.reset_selected_currencies_confirmation_message, + args: [currentCurrency.code] + )) + } #if os(macOS) // macOS sizes a .sheet() to its content's ideal size rather than the parent window's // size (unlike iOS, which presents modally full-size); without an explicit frame here, diff --git a/shared/src/appleMain/kotlin/xyz/tyiu/satsprice/IosPriceViewModel.kt b/shared/src/appleMain/kotlin/xyz/tyiu/satsprice/IosPriceViewModel.kt index 1db6127..357b116 100644 --- a/shared/src/appleMain/kotlin/xyz/tyiu/satsprice/IosPriceViewModel.kt +++ b/shared/src/appleMain/kotlin/xyz/tyiu/satsprice/IosPriceViewModel.kt @@ -63,6 +63,7 @@ class IosPriceViewModel { fun onFiatAmountChanged(code: String, value: String) = viewModel.onFiatAmountChanged(code, value) fun onFiatCurrencyToggled(code: String) = viewModel.onFiatCurrencyToggled(code) fun onFiatCurrenciesReordered(newOrder: List) = viewModel.onFiatCurrenciesReordered(newOrder) + fun onSelectedCurrenciesReset() = viewModel.onSelectedCurrenciesReset() fun onSourceSelected(name: String) = viewModel.onSourceSelected(name) fun onManualRateChanged(value: String) = viewModel.onManualRateChanged(value) fun onManualSatsPerCurrencyChanged(value: String) = viewModel.onManualSatsPerCurrencyChanged(value) 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 d52c34c..f1e7183 100644 --- a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceScreen.kt +++ b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceScreen.kt @@ -27,6 +27,7 @@ import androidx.compose.material.icons.filled.KeyboardDoubleArrowUp import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator @@ -120,6 +121,7 @@ fun PriceScreen( CurrencyPickerScreen( state = state, onToggle = viewModel::onFiatCurrencyToggled, + onReset = viewModel::onSelectedCurrenciesReset, onDone = { showCurrencyPicker = false }, ) return @@ -501,8 +503,32 @@ private fun CurrencyRowMenu( private fun CurrencyPickerScreen( state: ConverterUiState, onToggle: (String) -> Unit, + onReset: () -> Unit, onDone: () -> Unit, ) { + var showResetConfirmation by remember { mutableStateOf(false) } + + if (showResetConfirmation) { + AlertDialog( + onDismissRequest = { showResetConfirmation = false }, + title = { Text(stringResource(MR.strings.reset_selected_currencies_confirmation_title)) }, + text = { + Text(stringResource(MR.strings.reset_selected_currencies_confirmation_message, state.defaultCurrencyCode)) + }, + confirmButton = { + TextButton( + onClick = { + showResetConfirmation = false + onReset() + }, + ) { Text(stringResource(MR.strings.reset_selected_currencies_button)) } + }, + dismissButton = { + TextButton(onClick = { showResetConfirmation = false }) { Text(stringResource(MR.strings.cancel)) } + }, + ) + } + Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { Column( modifier = Modifier @@ -515,7 +541,14 @@ private fun CurrencyPickerScreen( verticalAlignment = Alignment.CenterVertically, ) { Text(stringResource(MR.strings.currencies_section_title), style = MaterialTheme.typography.headlineSmall) - TextButton(onClick = onDone) { Text(stringResource(MR.strings.done)) } + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + if (state.selectedFiatCurrencies.size > 1) { + TextButton(onClick = { showResetConfirmation = true }) { + Text(stringResource(MR.strings.reset_selected_currencies_button)) + } + } + TextButton(onClick = onDone) { Text(stringResource(MR.strings.done)) } + } } var searchQuery by remember { mutableStateOf("") } diff --git a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceViewModel.kt b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceViewModel.kt index 1ec75ba..3549183 100644 --- a/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceViewModel.kt +++ b/shared/src/commonMain/kotlin/xyz/tyiu/satsprice/ui/PriceViewModel.kt @@ -207,6 +207,16 @@ class PriceViewModel( persistSelectionIfChanged(_uiState.value.selectedFiatCurrencies) } + /** Removes every selected currency except the pinned [defaultCurrencyCode]. */ + fun onSelectedCurrenciesReset() { + _uiState.update { state -> + if (state.selectedFiatCurrencies == listOf(defaultCurrencyCode)) return@update state + val newState = state.copy(selectedFiatCurrencies = listOf(defaultCurrencyCode)) + rates?.let { recomputeFromKnownField(newState, it) } ?: newState + } + persistSelectionIfChanged(_uiState.value.selectedFiatCurrencies) + } + /** * Reorders the selected currencies to [newOrder]. Any code in [newOrder] that isn't * currently selected is ignored, and any currently-selected code missing from [newOrder] diff --git a/shared/src/commonMain/moko-resources/base/strings.xml b/shared/src/commonMain/moko-resources/base/strings.xml index bb6fbb8..442d3b2 100644 --- a/shared/src/commonMain/moko-resources/base/strings.xml +++ b/shared/src/commonMain/moko-resources/base/strings.xml @@ -3,6 +3,7 @@ Bitcoin BTC BTC to %1$s + Cancel Clear search Currencies %1$d selected @@ -22,6 +23,9 @@ Priced Currencies Refresh Remove + Reset + This keeps %1$s, but removes every other currency you\'ve added. + Remove all selected currencies? Retry Sats Search currencies