diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListScreen.kt b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListScreen.kt index 7f64d6db..26bef0be 100644 --- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListScreen.kt +++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListScreen.kt @@ -98,6 +98,8 @@ fun ExchangeListScreen( var addInProgress by remember { mutableStateOf(false) } var addErrorMessage by remember { mutableStateOf(null) } var exchangeToDelete by remember { mutableStateOf(null) } + // null while unknown; when the check fails, assume the exchange is in use + var exchangeInUse by remember { mutableStateOf(null) } val addErrorText = stringResource(R.string.exchange_add_error) @@ -167,7 +169,11 @@ fun ExchangeListScreen( devMode = devMode, onAction = { action -> if (action == ExchangeAction.Delete) { - exchangeToDelete = exchange + scope.launch { + exchangeInUse = exchangeManager + .hasResources(exchange.exchangeBaseUrl) ?: true + exchangeToDelete = exchange + } } else { handleExchangeAction( scope = scope, @@ -204,6 +210,8 @@ fun ExchangeListScreen( if (exchangeToDelete != null) { DeleteExchangeDialog( + inUse = exchangeInUse ?: true, + currency = exchangeToDelete?.currency, onDismiss = { exchangeToDelete = null }, @@ -382,21 +390,38 @@ fun AddExchangeDialog( @Composable fun DeleteExchangeDialog( + inUse: Boolean, + currency: String?, onDismiss: () -> Unit, onConfirm: (purge: Boolean) -> Unit, ) { - var purge by remember { mutableStateOf(false) } + // deleting an exchange that is in use needs a purge, which destroys its coins: + // say so, and require an explicit acknowledgement + var acknowledged by remember { mutableStateOf(false) } AlertDialog( onDismissRequest = onDismiss, title = { Text(stringResource(R.string.exchange_delete)) }, text = { - Row(verticalAlignment = Alignment.CenterVertically) { - Checkbox(checked = purge, onCheckedChange = { purge = it }) - Text(stringResource(R.string.exchange_delete_force)) + Column { + if (inUse) { + Text(stringResource(R.string.exchange_delete_in_use, currency ?: "")) + Row( + modifier = Modifier.padding(top = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Checkbox(checked = acknowledged, onCheckedChange = { acknowledged = it }) + Text(stringResource(R.string.exchange_delete_in_use_ack)) + } + } else { + Text(stringResource(R.string.exchange_delete_unused)) + } } }, confirmButton = { - TextButton(onClick = { onConfirm(purge) }) { + TextButton( + onClick = { onConfirm(inUse) }, + enabled = !inUse || acknowledged, + ) { Text(stringResource(R.string.transactions_delete)) } }, diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt index 5dfc8b62..7eea04a3 100644 --- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt +++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt @@ -43,6 +43,11 @@ data class ExchangeListResponse( val exchanges: List, ) +@Serializable +data class ExchangeResourcesResponse( + val hasResources: Boolean, +) + class ExchangeManager( private val api: WalletBackendApi, private val scope: CoroutineScope, @@ -152,6 +157,22 @@ class ExchangeManager( } } + /** + * Whether the wallet still holds coins or withdrawals of this exchange, + * i.e. whether deleting it needs a purge. Null if that could not be checked. + */ + suspend fun hasResources(exchangeUrl: String): Boolean? { + var result: Boolean? = null + api.request("getExchangeResources", ExchangeResourcesResponse.serializer()) { + put("exchangeBaseUrl", exchangeUrl) + }.onError { + Log.e(TAG, "Error getExchangeResources: $it") + }.onSuccess { + result = it.hasResources + } + return result + } + fun findExchangeForCurrency(currency: String): Flow = flow { emit(findExchangeByCurrency(currency)) } diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml index 89750709..fee29a66 100644 --- a/wallet/src/main/res/values/strings.xml +++ b/wallet/src/main/res/values/strings.xml @@ -441,6 +441,9 @@ GNU Taler is immune to many types of fraud such as credit card data theft, phish Enter address of payment service Delete payment service Force deletion (purge) + This wallet holds no digital cash or withdrawals from this payment service. + This payment service is in use. Deleting it permanently removes all %1$s of this payment service and their transaction history from this wallet. This cannot be undone. + I understand that this digital cash will be lost. Coin: %s (used %d time) Coin: %s (used %d times)