taler-android

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

commit 2fe368be5d91991a57daebc809d64f6c13a29377
parent e7090de2cbd07f99c82ac0268b8cf5355392cb4e
Author: Iván Ávalos <avalos@disroot.org>
Date:   Fri, 13 Feb 2026 15:25:15 +0100

[wallet] share taler:// link with wallet from other apps + template fixes

Diffstat:
Mwallet/src/main/AndroidManifest.xml | 5+++++
Mwallet/src/main/java/net/taler/wallet/main/MainActivity.kt | 10++++++++++
Mwallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt | 44++++++++++++++++++++++++++++++++------------
3 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/wallet/src/main/AndroidManifest.xml b/wallet/src/main/AndroidManifest.xml @@ -80,6 +80,11 @@ tools:ignore="AppLinkUrlError" /> <data android:scheme="payto" /> </intent-filter> + <intent-filter> + <action android:name="android.intent.action.SEND" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="text/plain" /> + </intent-filter> </activity> <activity diff --git a/wallet/src/main/java/net/taler/wallet/main/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/main/MainActivity.kt @@ -17,7 +17,9 @@ 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 import android.os.Build @@ -272,6 +274,14 @@ class MainActivity : AppCompatActivity(), OnPreferenceStartFragmentCallback { handleTalerUri(uri, "intent") } + if (intent.action == ACTION_SEND) { + if (intent.type == "text/plain") { + intent.getStringExtra(EXTRA_TEXT)?.let { uri -> + handleTalerUri(uri, "intent") + } + } + } + if (intent.action == NfcAdapter.ACTION_NDEF_DISCOVERED) { val messages: Array<NdefMessage> = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, NdefMessage::class.java) diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt @@ -21,6 +21,9 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -32,13 +35,16 @@ import net.taler.wallet.R import net.taler.wallet.compose.TalerSurface import net.taler.wallet.compose.collectAsStateLifecycleAware import net.taler.wallet.showError +import androidx.core.net.toUri +import net.taler.wallet.balances.BalanceState +import net.taler.wallet.compose.ErrorComposable +import net.taler.wallet.compose.LoadingScreen class PayTemplateFragment : Fragment() { private val model: MainViewModel by activityViewModels() private lateinit var uriString: String private lateinit var uri: Uri - private val currencies by lazy { model.balanceManager.getCurrencies() } override fun onCreateView( inflater: LayoutInflater, @@ -46,22 +52,36 @@ class PayTemplateFragment : Fragment() { savedInstanceState: Bundle?, ): View { uriString = arguments?.getString("uri") ?: error("no amount passed") - uri = Uri.parse(uriString) + uri = uriString.toUri() val payStatusFlow = model.paymentManager.payStatus.asFlow() return ComposeView(requireContext()).apply { setContent { - val payStatus = payStatusFlow.collectAsStateLifecycleAware(initial = PayStatus.None) + val payStatus = payStatusFlow.collectAsStateLifecycleAware(PayStatus.None) + val balanceState by model.balanceManager.state.observeAsState(BalanceState.None) + val devMode by model.devMode.observeAsState(false) TalerSurface { - PayTemplateComposable( - currencies = currencies, - payStatus = payStatus.value, - onCreateAmount = model::createAmount, - onSubmit = this@PayTemplateFragment::createOrder, - onError = { this@PayTemplateFragment.showError(it) }, - getCurrencySpec = model.exchangeManager::getSpecForCurrency, - ) + when (val state = balanceState) { + is BalanceState.None, is BalanceState.Loading -> LoadingScreen() + is BalanceState.Error -> ErrorComposable(state.error, devMode = devMode) + is BalanceState.Success -> PayTemplateComposable( + currencies = state.balances.map { it.currency }, + payStatus = payStatus.value, + onCreateAmount = model::createAmount, + onSubmit = this@PayTemplateFragment::createOrder, + onError = { this@PayTemplateFragment.showError(it) }, + getCurrencySpec = model.exchangeManager::getSpecForCurrency, + ) + } + + LaunchedEffect(balanceState) { + balanceState + } + + LaunchedEffect(Unit) { + model.balanceManager.loadAssets() + } } } } @@ -84,7 +104,7 @@ class PayTemplateFragment : Fragment() { } is PayStatus.Checked -> { - val usableCurrencies = currencies + val usableCurrencies = model.balanceManager.getCurrencies() .intersect(payStatus.supportedCurrencies.toSet()) .toList() if (!payStatus.details.isTemplateEditable(usableCurrencies)) {