taler-android

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

commit 19a70ef20a1b5dd17633c4200a0c1a3c6724d1f3
parent 3e96a4baf7bc38ee1b1e03d7087297b9e66ce2bb
Author: Iván Ávalos <avalos@disroot.org>
Date:   Thu, 20 Aug 2026 10:45:25 +0200

[wallet] add raw DB export to init error screen

Diffstat:
Mwallet/src/main/java/net/taler/wallet/main/MainActivity.kt | 29++++++++++++++++++++++++++++-
Mwallet/src/main/java/net/taler/wallet/main/WalletInitErrorScreen.kt | 23+++++------------------
Mwallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt | 27++++++++++++++++++++++++++-
Awallet/src/main/res/drawable/ic_database.xml | 10++++++++++
Mwallet/src/main/res/values-de/strings.xml | 3+++
Mwallet/src/main/res/values-fr/strings.xml | 3+++
Mwallet/src/main/res/values/strings.xml | 3+++
7 files changed, 78 insertions(+), 20 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/main/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/main/MainActivity.kt @@ -44,10 +44,12 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -124,6 +126,10 @@ class MainActivity : FragmentActivity() { val logExportLauncher = rememberLauncherForActivityResult(CreateDocument("text/plain")) { uri -> uri?.let { model.settingsManager.exportLogcat(it) } } + val dbExportLauncher = rememberLauncherForActivityResult(CreateDocument("application/octet-stream")) { uri -> + uri?.let { model.settingsManager.exportRawDb(it) } + } + var showDbExportConfirm by remember { mutableStateOf(false) } LaunchedEffect(initError) { if (initError == null) { @@ -141,7 +147,7 @@ class MainActivity : FragmentActivity() { model = model, error = error, onExportLogs = { logExportLauncher.launch("taler-wallet-logcat.txt") }, - onRetry = { model.startWallet() }, + onExportDb = { showDbExportConfirm = true }, ) } ?: run { WalletNavHost( @@ -175,6 +181,27 @@ class MainActivity : FragmentActivity() { onDismiss = { errorInfo = null } ) } + + if (showDbExportConfirm) { + AlertDialog( + onDismissRequest = { showDbExportConfirm = false }, + title = { Text(stringResource(R.string.wallet_export_database)) }, + text = { Text(stringResource(R.string.wallet_export_database_warning)) }, + confirmButton = { + Button(onClick = { + showDbExportConfirm = false + dbExportLauncher.launch("talerwalletdb.sqlite3") + }) { + Text(stringResource(R.string.wallet_export_database_confirm)) + } + }, + dismissButton = { + TextButton(onClick = { showDbExportConfirm = false }) { + Text(stringResource(R.string.cancel)) + } + } + ) + } } } diff --git a/wallet/src/main/java/net/taler/wallet/main/WalletInitErrorScreen.kt b/wallet/src/main/java/net/taler/wallet/main/WalletInitErrorScreen.kt @@ -18,7 +18,6 @@ package net.taler.wallet.main import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -26,39 +25,27 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Refresh -import androidx.compose.material.icons.rounded.ErrorOutline import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.Json import net.taler.wallet.BottomInsetsSpacer import net.taler.wallet.R import net.taler.wallet.backend.TalerErrorInfo -import net.taler.wallet.compose.CopyToClipboardButton import net.taler.wallet.compose.ErrorComposable -import net.taler.wallet.compose.ExpandableCard import net.taler.wallet.compose.GlobalScaffold -import net.taler.wallet.compose.ShareButton @OptIn(ExperimentalSerializationApi::class) @Composable @@ -66,7 +53,7 @@ fun WalletInitErrorScreen( model: MainViewModel, error: TalerErrorInfo, onExportLogs: () -> Unit, - onRetry: () -> Unit, + onExportDb: () -> Unit, modifier: Modifier = Modifier, ) { val devMode by model.devMode.observeAsState(false) @@ -110,15 +97,15 @@ fun WalletInitErrorScreen( Button( modifier = Modifier.fillMaxWidth(), - onClick = onRetry, + onClick = onExportDb, ) { Icon( - Icons.Default.Refresh, + painterResource(R.drawable.ic_database), contentDescription = null, modifier = Modifier.size(ButtonDefaults.IconSize), ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) - Text(stringResource(R.string.transactions_retry)) + Text(stringResource(R.string.wallet_export_database)) } BottomInsetsSpacer() diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt b/wallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt @@ -29,7 +29,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject import net.taler.wallet.R import net.taler.wallet.backend.TalerErrorInfo import net.taler.wallet.main.ViewMode @@ -39,6 +38,7 @@ import net.taler.wallet.backend.WalletResponse.Success import net.taler.wallet.balances.BalanceManager import net.taler.wallet.main.TAG import org.json.JSONObject +import java.io.File class SettingsManager( private val context: Context, @@ -185,6 +185,31 @@ class SettingsManager( } } + fun exportRawDb(uri: Uri?) { + if (uri == null) { + onDbExportError() + return + } + + scope.launch(Dispatchers.IO) { + try { + context.contentResolver.openOutputStream(uri, "wt")?.use { outputStream -> + val dbFile = File(context.filesDir, "talerwalletdb.sqlite3") + dbFile.inputStream().use { it.copyTo(outputStream) } + } ?: onDbExportError() + } catch (e: Exception) { + Log.e(SettingsManager::class.simpleName, "Error exporting raw db: ", e) + withContext(Dispatchers.Main) { + onDbExportError() + } + return@launch + } + withContext(Dispatchers.Main) { + Toast.makeText(context, R.string.settings_db_export_success, LENGTH_LONG).show() + } + } + } + fun importDb(uri: Uri?) { if (uri == null) { onDbImportError() diff --git a/wallet/src/main/res/drawable/ic_database.xml b/wallet/src/main/res/drawable/ic_database.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M480,840Q329,840 224.5,793.5Q120,747 120,680L120,280Q120,214 225.5,167Q331,120 480,120Q629,120 734.5,167Q840,214 840,280L840,680Q840,747 735.5,793.5Q631,840 480,840ZM480,361Q569,361 659,335.5Q749,310 760,281Q749,252 659.5,226Q570,200 480,200Q389,200 301.5,225.5Q214,251 200,281Q214,311 301.5,336Q389,361 480,361ZM480,560Q522,560 561,556Q600,552 635.5,544.5Q671,537 702.5,526Q734,515 760,501L760,381Q734,395 702.5,406Q671,417 635.5,424.5Q600,432 561,436Q522,440 480,440Q438,440 398,436Q358,432 322.5,424.5Q287,417 256,406Q225,395 200,381L200,501Q225,515 256,526Q287,537 322.5,544.5Q358,552 398,556Q438,560 480,560ZM480,760Q526,760 573.5,753Q621,746 661,734.5Q701,723 728,708.5Q755,694 760,679L760,581Q734,595 702.5,606Q671,617 635.5,624.5Q600,632 561,636Q522,640 480,640Q438,640 398,636Q358,632 322.5,624.5Q287,617 256,606Q225,595 200,581L200,680Q205,695 231.5,709Q258,723 298,734.5Q338,746 386,753Q434,760 480,760Z"/> +</vector> diff --git a/wallet/src/main/res/values-de/strings.xml b/wallet/src/main/res/values-de/strings.xml @@ -403,6 +403,9 @@ <string name="wallet_init_error_title">Initialisierungsfehler</string> <string name="wallet_init_error_message">Beim Starten der Wallet ist ein Fehler aufgetreten. Dies kann nach einem App-Update oder bei inkompatiblen Wallet-Daten passieren. Bitte versuche es erneut, und falls das Problem bestehen bleibt, exportiere die Protokolle und melde dieses Problem den Entwicklern.</string> <string name="wallet_export_logs">Protokolle exportieren</string> + <string name="wallet_export_database">Datenbank exportieren</string> + <string name="wallet_export_database_warning">Achtung: Diese Datei enthält vertrauliche Daten, mit denen andere auf Ihr Geld zugreifen könnten. Exportieren Sie sie nur an einen sicheren Ort und teilen Sie sie nur mit jemandem, dem Sie vertrauen.</string> + <string name="wallet_export_database_confirm">Trotzdem exportieren</string> <string name="receive_peer_create_button_amount">%1$s anfordern</string> <string name="send_peer_create_button_amount">%1$s übertragen</string> <string name="send_deposits_no_currencies_error">Es sind keine bekannten Währungen für Einzahlungen verfügbar.</string> diff --git a/wallet/src/main/res/values-fr/strings.xml b/wallet/src/main/res/values-fr/strings.xml @@ -364,6 +364,9 @@ <string name="wallet_init_error_title">Erreur d\'initialisation</string> <string name="wallet_init_error_message">Une erreur est survenue lors du démarrage du portefeuille. Cela peut arriver après une mise à jour de l\'application ou si les données du portefeuille sont incompatibles. Veuillez réessayer et, si le problème persiste, exportez les journaux et signalez ce problème aux développeurs.</string> <string name="wallet_export_logs">Exporter les journaux</string> + <string name="wallet_export_database">Exporter la base de données</string> + <string name="wallet_export_database_warning">Attention : ce fichier contient des données sensibles qui pourraient donner à d\'autres personnes accès à votre argent. Exportez-le uniquement vers un endroit sûr et partagez-le avec une personne de confiance.</string> + <string name="wallet_export_database_confirm">Exporter quand même</string> <string name="save">Sauvegarder</string> <string name="warning">Avertissement</string> <string name="biometric_prompt_title">Déverrouillez pour utiliser le portefeuille</string> diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml @@ -67,6 +67,9 @@ GNU Taler is immune to many types of fraud such as credit card data theft, phish <string name="error_export">Export error diagnostics</string> <string name="wallet_init_error_title">Initialization error</string> <string name="wallet_init_error_message">An error occurred while starting the wallet. This can happen after an app update or if the wallet data is incompatible. Please retry, and if the problem persists, export the logs and report this issue to the developers.</string> + <string name="wallet_export_database">Export database</string> + <string name="wallet_export_database_warning">Warning: This file contains sensitive data that could grant others access to your money. Only export it to a safe location and share it with someone you trust.</string> + <string name="wallet_export_database_confirm">Export anyway</string> <string name="wallet_export_logs">Export logs</string> <string name="import_db">Import</string> <string name="language">Language</string>