taler-android

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

commit 2d5de16d5e5f472cb46724036c27b3e18e79088a
parent 5c2fdb6efaa0690ea4ff1e54ace4ca4c540e00c6
Author: Iván Ávalos <avalos@disroot.org>
Date:   Thu, 23 Jul 2026 14:30:23 +0200

[wallet] navigation + NFC handling improvements

Diffstat:
Mwallet/src/main/java/net/taler/wallet/WalletNavHost.kt | 20+-------------------
Mwallet/src/main/java/net/taler/wallet/main/MainActivity.kt | 31++++++++++++++++++-------------
Mwallet/src/main/java/net/taler/wallet/payment/PayTotpComposable.kt | 12++++++------
3 files changed, 25 insertions(+), 38 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/WalletNavHost.kt b/wallet/src/main/java/net/taler/wallet/WalletNavHost.kt @@ -25,9 +25,6 @@ import androidx.compose.animation.slideOutHorizontally import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager @@ -71,7 +68,6 @@ fun WalletNavHost( navController: NavHostController, model: MainViewModel, modifier: Modifier = Modifier, - launchUri: String?, onScanQr: () -> Unit, onFulfillPayment: (url: String) -> Unit, onShowError: (TalerErrorInfo) -> Unit, @@ -79,11 +75,7 @@ fun WalletNavHost( val context = LocalContext.current val focusManager = LocalFocusManager.current val keyboardController = LocalSoftwareKeyboardController.current - val startDestination = if (launchUri != null) { - WalletDestination.HandleUri(launchUri) - } else { - WalletDestination.Main - } + val startDestination = WalletDestination.Main val onNavigate: NavigateCallback = { dest, popupToStart -> if (popupToStart) { @@ -109,16 +101,6 @@ fun WalletNavHost( } } - val previousLaunchUri = remember { mutableStateOf(launchUri) } - - LaunchedEffect(launchUri) { - val prev = previousLaunchUri.value - previousLaunchUri.value = launchUri - if (launchUri != null && prev != launchUri) { - navController.navigate(WalletDestination.HandleUri(launchUri)) - } - } - NavHost( navController = navController, startDestination = startDestination, diff --git a/wallet/src/main/java/net/taler/wallet/main/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/main/MainActivity.kt @@ -18,7 +18,6 @@ package net.taler.wallet.main import android.content.Intent import android.content.Intent.ACTION_SEND -import android.content.Intent.ACTION_VIEW import android.content.Intent.EXTRA_TEXT import android.nfc.NdefMessage import android.nfc.NfcAdapter @@ -48,7 +47,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -74,7 +73,6 @@ import com.google.zxing.client.android.Intents.Scan.SCAN_TYPE import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanOptions import com.journeyapps.barcodescanner.ScanOptions.QR_CODE -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import net.taler.common.EventObserver import net.taler.lib.android.TalerNfcService @@ -92,7 +90,7 @@ import net.taler.wallet.ui.theme.TalerTheme class MainActivity : FragmentActivity() { private val model: MainViewModel by viewModels() - private val launchIntentUri = MutableStateFlow<String?>(null) + private var pendingLaunchUri: String? = null private var nav: NavController? = null private lateinit var biometricPrompt: BiometricPrompt private lateinit var promptInfo: BiometricPrompt.PromptInfo @@ -121,11 +119,10 @@ class MainActivity : FragmentActivity() { val errorSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = !devMode) val authenticated by model.authenticated.collectAsState() val biometricEnabled by model.settingsManager.getBiometricLockEnabled(this).collectAsState(false) - val launchUri by launchIntentUri.collectAsState(null) - DisposableEffect(Unit) { - onDispose { - launchIntentUri.value = null + LaunchedEffect(Unit) { + pendingLaunchUri?.let { uri -> + nav?.navigate(WalletDestination.HandleUri(uri)) } } @@ -134,7 +131,6 @@ class MainActivity : FragmentActivity() { navController = navController, model = model, modifier = Modifier.fillMaxSize(), - launchUri = launchUri, onScanQr = { model.scanCode() }, onFulfillPayment = { url: String -> launchInAppBrowser(this@MainActivity, url) }, onShowError = { errorInfo = it } @@ -259,14 +255,23 @@ class MainActivity : FragmentActivity() { private fun handleIntents(intent: Intent?) { if (intent == null) return - if (intent.action == ACTION_VIEW) intent.dataString?.let { uri -> - launchIntentUri.value = uri + fun emitUri(uri: String) { + if (nav != null) { + nav?.navigate(WalletDestination.HandleUri(uri)) + } else { + pendingLaunchUri = uri + } + } + + // Check data URI first regardless of action + intent.dataString?.let { uri -> + emitUri(uri) } if (intent.action == ACTION_SEND) { if (intent.type == "text/plain") { intent.getStringExtra(EXTRA_TEXT)?.let { uri -> - launchIntentUri.value = uri + emitUri(uri) } } } @@ -284,7 +289,7 @@ class MainActivity : FragmentActivity() { messages.forEach { message -> message.records?.forEach { record -> record.toUri()?.let { uri -> - launchIntentUri.value = uri.toString() + emitUri(uri.toString()) } } } diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTotpComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTotpComposable.kt @@ -67,7 +67,7 @@ fun PayTotpComposable( ) { val context = LocalContext.current val activity = context as? Activity - val nfcAdapter = remember(enableNfc) { if (enableNfc) NfcAdapter.getDefaultAdapter(context) else null } + val nfcAdapter = remember { NfcAdapter.getDefaultAdapter(context) } var nfcDone by remember { mutableStateOf(false) } if (enableNfc) { @@ -107,12 +107,12 @@ fun PayTotpComposable( } }, NFC_READER_FLAGS, null) } + } - DisposableEffect(activity) { - onDispose { - if (activity != null) { - nfcAdapter?.disableReaderMode(activity) - } + DisposableEffect(enableNfc) { + onDispose { + if (enableNfc) { + nfcAdapter?.disableReaderMode(activity ?: return@onDispose) } } }