taler-android

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

PromptPaymentFragment.kt (7226B)


      1 /*
      2  * This file is part of GNU Taler
      3  * (C) 2025 Taler Systems S.A.
      4  *
      5  * GNU Taler is free software; you can redistribute it and/or modify it under the
      6  * terms of the GNU General Public License as published by the Free Software
      7  * Foundation; either version 3, or (at your option) any later version.
      8  *
      9  * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
     10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11  * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License along with
     14  * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15  */
     16 
     17 package net.taler.wallet.payment
     18 
     19 import android.graphics.Bitmap
     20 import android.os.Bundle
     21 import android.util.Log
     22 import android.view.LayoutInflater
     23 import android.view.View
     24 import android.view.ViewGroup
     25 import androidx.compose.runtime.getValue
     26 import androidx.compose.runtime.livedata.observeAsState
     27 import androidx.compose.ui.platform.ComposeView
     28 import androidx.core.os.bundleOf
     29 import androidx.fragment.app.Fragment
     30 import androidx.fragment.app.activityViewModels
     31 import androidx.lifecycle.lifecycleScope
     32 import androidx.navigation.fragment.findNavController
     33 import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG
     34 import com.google.android.material.snackbar.Snackbar
     35 import kotlinx.coroutines.launch
     36 import net.taler.common.showError
     37 import net.taler.wallet.main.MainViewModel
     38 import net.taler.wallet.R
     39 import net.taler.wallet.main.TAG
     40 import net.taler.wallet.compose.LoadingScreen
     41 import net.taler.wallet.compose.TalerSurface
     42 import net.taler.wallet.showError
     43 
     44 class PromptPaymentFragment: Fragment(), ProductImageClickListener {
     45     private val model: MainViewModel by activityViewModels()
     46     private val paymentManager by lazy { model.paymentManager }
     47     private val transactionManager by lazy { model.transactionManager }
     48 
     49     override fun onCreateView(
     50         inflater: LayoutInflater,
     51         container: ViewGroup?,
     52         savedInstanceState: Bundle?
     53     ): View? = ComposeView(requireContext()).apply {
     54         setContent {
     55             TalerSurface {
     56                 val payStatus by paymentManager.payStatus.observeAsState(PayStatus.None)
     57                 when(val status = payStatus) {
     58                     is PayStatus.None,
     59                     is PayStatus.Loading,
     60                     is PayStatus.Prepared -> LoadingScreen()
     61                     is PayStatus.Checked -> {} // does not apply, only used for templates
     62                     is PayStatus.Choices -> {
     63                         PromptPaymentComposable(status,
     64                             onConfirm = { index, useDonau ->
     65                                 paymentManager.confirmPay(
     66                                     transactionId = status.transactionId,
     67                                     choiceIndex = index,
     68                                     useDonau = useDonau,
     69                                 )
     70                             },
     71                             onCancel = {
     72                                 transactionManager.abortTransaction(
     73                                     status.transactionId,
     74                                     onSuccess = {
     75                                         Snackbar.make(
     76                                             requireView(),
     77                                             getString(R.string.payment_aborted),
     78                                             LENGTH_LONG
     79                                         ).show()
     80                                         findNavController().popBackStack()
     81                                     },
     82                                     onError = { error ->
     83                                         Log.e(TAG, "Error abortTransaction $error")
     84                                         if (model.devMode.value == false) {
     85                                             showError(error.userFacingMsg)
     86                                         } else {
     87                                             showError(error)
     88                                         }
     89                                     }
     90                                 )
     91                             },
     92                             onClickImage = { bitmap ->
     93                                 onImageClick(bitmap)
     94                             },
     95                             checkDonauStatus = { index ->
     96                                 status.choices.find { it.choiceIndex == index }?.let { choice ->
     97                                     paymentManager.checkDonauForChoice(choice)
     98                                 } ?: DonauStatus.Unavailable
     99                             },
    100                             onSetupDonau = { donauBaseUrl ->
    101                                 findNavController().navigate(
    102                                     R.id.action_main_to_setDonau,
    103                                     bundleOf(
    104                                         "donauBaseUrl" to donauBaseUrl,
    105                                         "saveShouldExit" to true,
    106                                     ),
    107                                 )
    108                             },
    109                         )
    110                     }
    111 
    112                     else -> {}
    113                 }
    114             }
    115         }
    116     }
    117 
    118     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    119         super.onViewCreated(view, savedInstanceState)
    120         paymentManager.payStatus.observe(viewLifecycleOwner) { status ->
    121             when (status) {
    122                 is PayStatus.Success -> {
    123                     paymentManager.resetPayStatus()
    124                     navigateToTransaction(status.transactionId)
    125                     if (status.automaticExecution) {
    126                         Snackbar.make(requireView(), R.string.payment_automatic_execution, LENGTH_LONG).show()
    127                     }
    128                 }
    129 
    130                 is PayStatus.AlreadyPaid -> {
    131                     paymentManager.resetPayStatus()
    132                     navigateToTransaction(status.transactionId)
    133                     Snackbar.make(requireView(), R.string.payment_already_paid, LENGTH_LONG).show()
    134                 }
    135 
    136                 is PayStatus.Pending -> {
    137                     paymentManager.resetPayStatus()
    138                     navigateToTransaction(status.transactionId)
    139                     if (status.error != null) {
    140                         if (model.devMode.value == true) {
    141                             showError(status.error)
    142                         } else {
    143                             showError(status.error.userFacingMsg)
    144                         }
    145                     }
    146                 }
    147 
    148                 else -> {}
    149             }
    150         }
    151     }
    152 
    153     override fun onImageClick(image: Bitmap) {
    154         val f = ProductImageFragment.new(image)
    155         f.show(parentFragmentManager, "image")
    156     }
    157 
    158     private fun navigateToTransaction(id: String?) {
    159         lifecycleScope.launch {
    160             if (id != null && transactionManager.selectTransaction(id)) {
    161                 findNavController().navigate(R.id.action_global_transactionPayment)
    162             } else {
    163                 findNavController().navigate(R.id.action_global_main)
    164             }
    165         }
    166     }
    167 }
    168