taler-android

Android apps for GNU Taler (wallet, PoS, cashier)
Log | Files | Refs | README | LICENSE

commit 84e5efcef482e432f01be7bbf0f24d9a097aff38
parent b202bbfd7c234c1b03c69749db88d3def896b3ab
Author: Iván Ávalos <avalos@disroot.org>
Date:   Thu, 20 Aug 2026 17:39:01 +0200

[wallet] allow exporting sqlite3 DB from settings

Diffstat:
Mwallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt | 2+-
Mwallet/src/main/java/net/taler/wallet/main/MainActivity.kt | 2+-
Mwallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt | 3++-
Mwallet/src/main/java/net/taler/wallet/settings/SettingsScreen.kt | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mwallet/src/main/res/values-de/strings.xml | 2++
Mwallet/src/main/res/values-fr/strings.xml | 2++
Mwallet/src/main/res/values/strings.xml | 2++
7 files changed, 74 insertions(+), 22 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt @@ -29,7 +29,7 @@ import net.taler.wallet.backend.TalerErrorCode.NONE import org.json.JSONObject import java.io.File -private const val WALLET_DB = "talerwalletdb.sqlite3" +const val WALLET_DB = "talerwalletdb.sqlite3" @OptIn(DelicateCoroutinesApi::class) class WalletBackendApi( diff --git a/wallet/src/main/java/net/taler/wallet/main/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/main/MainActivity.kt @@ -190,7 +190,7 @@ class MainActivity : FragmentActivity() { confirmButton = { Button(onClick = { showDbExportConfirm = false - dbExportLauncher.launch("talerwalletdb.sqlite3") + dbExportLauncher.launch("taler-wallet-db-${System.currentTimeMillis()}.sqlite3") }) { Text(stringResource(R.string.wallet_export_database_confirm)) } diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt b/wallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt @@ -31,6 +31,7 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import net.taler.wallet.R import net.taler.wallet.backend.TalerErrorInfo +import net.taler.wallet.backend.WALLET_DB import net.taler.wallet.main.ViewMode import net.taler.wallet.backend.WalletBackendApi import net.taler.wallet.backend.WalletResponse.Error @@ -194,7 +195,7 @@ class SettingsManager( scope.launch(Dispatchers.IO) { try { context.contentResolver.openOutputStream(uri, "wt")?.use { outputStream -> - val dbFile = File(context.filesDir, "talerwalletdb.sqlite3") + val dbFile = File(context.filesDir, WALLET_DB) dbFile.inputStream().use { it.copyTo(outputStream) } } ?: onDbExportError() } catch (e: Exception) { diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsScreen.kt b/wallet/src/main/java/net/taler/wallet/settings/SettingsScreen.kt @@ -53,6 +53,8 @@ import androidx.compose.material.icons.filled.DomainAdd import androidx.compose.material.icons.filled.LocalAtm import androidx.compose.material.icons.filled.Memory import androidx.compose.material.icons.filled.VideoLibrary +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -60,10 +62,14 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Switch import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector @@ -131,6 +137,10 @@ fun SettingsScreen( settingsManager.importDb(it) } } + val rawDbExportLauncher = rememberLauncherForActivityResult(CreateDocument("application/octet-stream")) { uri -> + uri?.let { settingsManager.exportRawDb(it) } + } + var pendingDbExport by remember { mutableStateOf<DbExportType?>(null) } val biometricEnrollLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { @@ -233,7 +243,14 @@ fun SettingsScreen( title = stringResource(R.string.settings_db_export), summary = stringResource(R.string.settings_db_export_summary), icon = ImageVector.vectorResource(R.drawable.ic_unarchive), - onClick = { dbExportLauncher.launch("taler-wallet-db-${System.currentTimeMillis()}.json") } + onClick = { pendingDbExport = DbExportType.Json } + ) + + SettingsItem( + title = stringResource(R.string.settings_db_export_raw), + summary = stringResource(R.string.settings_db_export_raw_summary), + icon = ImageVector.vectorResource(R.drawable.ic_database), + onClick = { pendingDbExport = DbExportType.Raw } ) SettingsItem( @@ -253,6 +270,24 @@ fun SettingsScreen( } ) + if (model.databaseBackend != WalletDatabaseBackend.Sqlite) SettingsItem( + title = stringResource(R.string.settings_migrate_db), + summary = stringResource(R.string.settings_migrate_db_summary), + icon = Icons.Default.Memory, + onClick = { + MaterialAlertDialogBuilder(context) + .setMessage(R.string.settings_dialog_migrate_db_message) + .setNegativeButton(R.string.settings_migrate_db) { _, _ -> + model.enableMigrateNativeDb { onShowError(it) } + scope.launch { snackbarHostState.showSnackbar(migrateDoneMessage) } + } + .setPositiveButton(R.string.cancel) { _, _ -> + scope.launch { snackbarHostState.showSnackbar(migrateCanceledMessage) } + } + .show() + } + ) + SettingsItem( title = stringResource(R.string.settings_version_app), summary = "${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR} ${BuildConfig.VERSION_CODE})", @@ -292,24 +327,6 @@ fun SettingsScreen( } ) - if (model.databaseBackend != WalletDatabaseBackend.Sqlite) SettingsItem( - title = stringResource(R.string.settings_migrate_db), - summary = stringResource(R.string.settings_migrate_db_summary), - icon = Icons.Default.Memory, - onClick = { - MaterialAlertDialogBuilder(context) - .setMessage(R.string.settings_dialog_migrate_db_message) - .setNegativeButton(R.string.settings_migrate_db) { _, _ -> - model.enableMigrateNativeDb { onShowError(it) } - scope.launch { snackbarHostState.showSnackbar(migrateDoneMessage) } - } - .setPositiveButton(R.string.cancel) { _, _ -> - scope.launch { snackbarHostState.showSnackbar(migrateCanceledMessage) } - } - .show() - } - ) - SettingsItem( title = stringResource(R.string.settings_reset), summary = stringResource(R.string.settings_reset_summary), @@ -329,6 +346,32 @@ fun SettingsScreen( .show() } ) + + pendingDbExport?.let { exportType -> + AlertDialog( + onDismissRequest = { pendingDbExport = null }, + title = { Text(stringResource(R.string.wallet_export_database)) }, + text = { Text(stringResource(R.string.wallet_export_database_warning)) }, + confirmButton = { + Button(onClick = { + pendingDbExport = null + when (exportType) { + DbExportType.Json -> + dbExportLauncher.launch("taler-wallet-db-${System.currentTimeMillis()}.json") + DbExportType.Raw -> + rawDbExportLauncher.launch("taler-wallet-db-${System.currentTimeMillis()}.sqlite3") + } + }) { + Text(stringResource(R.string.wallet_export_database_confirm)) + } + }, + dismissButton = { + TextButton(onClick = { pendingDbExport = null }) { + Text(stringResource(R.string.cancel)) + } + } + ) + } } } } @@ -497,3 +540,5 @@ private fun promptAuthEnrollment(onPromptEnrollment: (Intent) -> Unit) { onPromptEnrollment(intent) } } + +private enum class DbExportType { Json, Raw } diff --git a/wallet/src/main/res/values-de/strings.xml b/wallet/src/main/res/values-de/strings.xml @@ -128,6 +128,8 @@ <string name="withdraw_manual_ready_receiver">Empfänger</string> <string name="exchange_delete_force">Löschung erzwingen (bereinigen)</string> <string name="settings_db_export_summary">Interne Datenbank speichern</string> + <string name="settings_db_export_raw">Rohdatenbank exportieren</string> + <string name="settings_db_export_raw_summary">Rohe SQLite-Datenbankdatei speichern</string> <string name="settings_db_clear_error">Fehler beim Bereinigen der Datenbank</string> <string name="settings_alert_reset_canceled">Zurücksetzen abgebrochen</string> <string name="exchange_not_contacted">Zahlungsdienstleister nicht kontaktiert</string> diff --git a/wallet/src/main/res/values-fr/strings.xml b/wallet/src/main/res/values-fr/strings.xml @@ -265,6 +265,8 @@ <string name="exchange_tos_forget">Refuser les conditions d\'utilisation</string> <string name="exchange_tos_view">Voir les conditions d\'utilisation</string> <string name="settings_db_export_summary">Sauver la base de donnée interne</string> + <string name="settings_db_export_raw">Exporter la base de données brute</string> + <string name="settings_db_export_raw_summary">Sauver le fichier brut de la base de données SQLite</string> <string name="settings_db_import_summary">Restauration de la base de données à partir d\'un fichier</string> <string name="settings_dialog_reset_message">Voulez-vous vraiment réinitialiser le portefeuille et perdre toutes les pièces et tous les achats ?</string> <string name="transaction_preparing_kyc">KYC requis, préparation du test</string> diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml @@ -505,6 +505,8 @@ GNU Taler is immune to many types of fraud such as credit card data theft, phish <string name="settings_db_export_message">Exporting database, please wait until confirmation</string> <string name="settings_db_export_success">Database exported to file</string> <string name="settings_db_export_summary">Save internal database</string> + <string name="settings_db_export_raw">Export raw database</string> + <string name="settings_db_export_raw_summary">Save raw SQLite database file</string> <string name="settings_db_import">Import database</string> <string name="settings_db_import_error">Error importing database</string> <string name="settings_db_import_message">Importing database, please wait until confirmation</string>