gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-android] 04/06: [wallet] migrate away from kotlin view exte


From: gnunet
Subject: [taler-taler-android] 04/06: [wallet] migrate away from kotlin view extensions
Date: Thu, 03 Sep 2020 18:42:01 +0200

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a commit to branch master
in repository taler-android.

commit 85c344b358e13d5b78647d191d6129dd11f8bdaf
Author: Torsten Grote <t@grobox.de>
AuthorDate: Thu Sep 3 11:50:13 2020 -0300

    [wallet] migrate away from kotlin view extensions
---
 wallet/build.gradle                                |   5 +-
 .../src/main/java/net/taler/wallet/MainActivity.kt |  39 ++++----
 .../src/main/java/net/taler/wallet/MainFragment.kt |  14 +--
 .../main/java/net/taler/wallet/UriInputFragment.kt |  23 +++--
 .../net/taler/wallet/balances/BalancesFragment.kt  |  20 ++--
 .../taler/wallet/exchanges/ExchangeListFragment.kt |  26 +++---
 .../wallet/exchanges/SelectExchangeFragment.kt     |  29 +++---
 .../taler/wallet/payment/AlreadyPaidFragment.kt    |  10 +-
 .../taler/wallet/payment/ProductImageFragment.kt   |  10 +-
 .../taler/wallet/payment/PromptPaymentFragment.kt  |  56 +++++------
 .../wallet/pending/PendingOperationsFragment.kt    |  11 ++-
 .../net/taler/wallet/settings/SettingsFragment.kt  |   7 +-
 .../transactions/TransactionDetailFragment.kt      | 103 +++------------------
 .../TransactionPaymentFragment.kt}                 |  42 +++++----
 .../transactions/TransactionRefreshFragment.kt     |  56 +++++++++++
 .../transactions/TransactionRefundFragment.kt      |  61 ++++++++++++
 .../transactions/TransactionWithdrawalFragment.kt  |  68 ++++++++++++++
 .../net/taler/wallet/transactions/Transactions.kt  |  17 ++--
 .../wallet/transactions/TransactionsFragment.kt    |  45 ++++-----
 .../net/taler/wallet/withdraw/ErrorFragment.kt     |  21 +++--
 .../wallet/withdraw/ManualWithdrawFragment.kt      |  25 ++---
 .../wallet/withdraw/PromptWithdrawFragment.kt      |  48 +++++-----
 .../wallet/withdraw/ReviewExchangeTosFragment.kt   |  29 +++---
 .../net/taler/wallet/withdraw/WithdrawManager.kt   |  34 +++----
 wallet/src/main/res/layout/activity_main.xml       |   3 +-
 .../{app_bar_main.xml => app_content_main.xml}     |   0
 .../main/res/layout/fragment_prompt_payment.xml    |   8 +-
 wallet/src/main/res/layout/payment_bottom_bar.xml  |   1 +
 wallet/src/main/res/navigation/nav_graph.xml       |  38 +++++++-
 29 files changed, 510 insertions(+), 339 deletions(-)

diff --git a/wallet/build.gradle b/wallet/build.gradle
index 434ebb9..47de2dd 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -19,7 +19,6 @@ import com.android.build.gradle.tasks.MergeResources
 plugins {
     id "com.android.application"
     id "kotlin-android"
-    id "kotlin-android-extensions"
     id "kotlinx-serialization"
     id "de.undercouch.download"
 }
@@ -88,6 +87,10 @@ android {
         jvmTarget = "1.8"
     }
 
+    buildFeatures {
+        viewBinding = true
+    }
+
     packagingOptions {
         exclude("META-INF/*.kotlin_module")
     }
diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt 
b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
index 838ed2d..0605976 100644
--- a/wallet/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
@@ -47,8 +47,6 @@ import 
com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_SHORT
 import com.google.android.material.snackbar.Snackbar
 import com.google.zxing.integration.android.IntentIntegrator
 import 
com.google.zxing.integration.android.IntentIntegrator.parseActivityResult
-import kotlinx.android.synthetic.main.activity_main.*
-import kotlinx.android.synthetic.main.app_bar_main.*
 import net.taler.common.isOnline
 import net.taler.wallet.BuildConfig.VERSION_CODE
 import net.taler.wallet.BuildConfig.VERSION_NAME
@@ -56,6 +54,7 @@ import 
net.taler.wallet.HostCardEmulatorService.Companion.HTTP_TUNNEL_RESPONSE
 import 
net.taler.wallet.HostCardEmulatorService.Companion.MERCHANT_NFC_CONNECTED
 import 
net.taler.wallet.HostCardEmulatorService.Companion.MERCHANT_NFC_DISCONNECTED
 import 
net.taler.wallet.HostCardEmulatorService.Companion.TRIGGER_PAYMENT_ACTION
+import net.taler.wallet.databinding.ActivityMainBinding
 import net.taler.wallet.refund.RefundStatus
 import java.util.Locale.ROOT
 
@@ -64,35 +63,37 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
 
     private val model: MainViewModel by viewModels()
 
+    private lateinit var ui: ActivityMainBinding
     private lateinit var nav: NavController
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        setContentView(R.layout.activity_main)
+        ui = ActivityMainBinding.inflate(layoutInflater)
+        setContentView(ui.root)
 
         val navHostFragment =
             supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as 
NavHostFragment
         nav = navHostFragment.navController
-        nav_view.setupWithNavController(nav)
-        nav_view.setNavigationItemSelectedListener(this)
+        ui.navView.setupWithNavController(nav)
+        ui.navView.setNavigationItemSelectedListener(this)
         if (savedInstanceState == null) {
-            nav_view.menu.getItem(0).isChecked = true
+            ui.navView.menu.getItem(0).isChecked = true
         }
 
-        setSupportActionBar(toolbar)
+        setSupportActionBar(ui.content.toolbar)
         val appBarConfiguration = AppBarConfiguration(
             setOf(R.id.nav_main, R.id.nav_settings, 
R.id.nav_pending_operations),
-            drawer_layout
+            ui.drawerLayout
         )
-        toolbar.setupWithNavController(nav, appBarConfiguration)
+        ui.content.toolbar.setupWithNavController(nav, appBarConfiguration)
 
-        model.showProgressBar.observe(this, Observer { show ->
-            progress_bar.visibility = if (show) VISIBLE else INVISIBLE
+        model.showProgressBar.observe(this, { show ->
+            ui.content.progressBar.visibility = if (show) VISIBLE else 
INVISIBLE
         })
 
-        val versionView: TextView = 
nav_view.getHeaderView(0).findViewById(R.id.versionView)
-        model.devMode.observe(this, Observer { enabled ->
-            nav_view.menu.findItem(R.id.nav_dev).isVisible = enabled
+        val versionView: TextView = 
ui.navView.getHeaderView(0).findViewById(R.id.versionView)
+        model.devMode.observe(this, { enabled ->
+            ui.navView.menu.findItem(R.id.nav_dev).isVisible = enabled
             if (enabled) {
                 @SuppressLint("SetTextI18n")
                 versionView.text = "$VERSION_NAME ($VERSION_CODE)"
@@ -113,7 +114,7 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
     }
 
     override fun onBackPressed() {
-        if (drawer_layout.isDrawerOpen(START)) drawer_layout.closeDrawer(START)
+        if (ui.drawerLayout.isDrawerOpen(START)) 
ui.drawerLayout.closeDrawer(START)
         else super.onBackPressed()
     }
 
@@ -123,7 +124,7 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
             R.id.nav_settings -> nav.navigate(R.id.nav_settings)
             R.id.nav_pending_operations -> 
nav.navigate(R.id.nav_pending_operations)
         }
-        drawer_layout.closeDrawer(START)
+        ui.drawerLayout.closeDrawer(START)
         return true
     }
 
@@ -167,7 +168,7 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
             }
             else -> {
                 Snackbar.make(
-                    nav_view,
+                    ui.navView,
                     "URL from $from doesn't contain a supported Taler Uri.",
                     LENGTH_SHORT
                 ).show()
@@ -179,13 +180,13 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
         model.showProgressBar.value = false
         when (status) {
             is RefundStatus.Error -> {
-                Snackbar.make(nav_view, R.string.refund_error, 
LENGTH_LONG).show()
+                Snackbar.make(ui.navView, R.string.refund_error, 
LENGTH_LONG).show()
             }
             is RefundStatus.Success -> {
                 val amount = status.response.amountRefundGranted
                 model.showTransactions(amount.currency)
                 val str = getString(R.string.refund_success, amount.amountStr)
-                Snackbar.make(nav_view, str, LENGTH_LONG).show()
+                Snackbar.make(ui.navView, str, LENGTH_LONG).show()
             }
         }
     }
diff --git a/wallet/src/main/java/net/taler/wallet/MainFragment.kt 
b/wallet/src/main/java/net/taler/wallet/MainFragment.kt
index d5bd3fc..1479bc0 100644
--- a/wallet/src/main/java/net/taler/wallet/MainFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainFragment.kt
@@ -22,14 +22,13 @@ import android.view.View
 import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import androidx.navigation.fragment.findNavController
-import kotlinx.android.synthetic.main.fragment_main.*
 import net.taler.common.EventObserver
 import net.taler.wallet.CurrencyMode.MULTI
 import net.taler.wallet.CurrencyMode.SINGLE
 import net.taler.wallet.balances.BalanceItem
 import net.taler.wallet.balances.BalancesFragment
+import net.taler.wallet.databinding.FragmentMainBinding
 import net.taler.wallet.transactions.TransactionsFragment
 
 enum class CurrencyMode { SINGLE, MULTI }
@@ -39,16 +38,19 @@ class MainFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
     private var currencyMode: CurrencyMode? = null
 
+    private lateinit var ui: FragmentMainBinding
+
     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_main, container, false)
+        ui = FragmentMainBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        model.balances.observe(viewLifecycleOwner, Observer {
+        model.balances.observe(viewLifecycleOwner, {
             onBalancesChanged(it)
         })
         model.transactionsEvent.observe(viewLifecycleOwner, EventObserver { 
currency ->
@@ -59,10 +61,10 @@ class MainFragment : Fragment() {
             }
         })
 
-        mainFab.setOnClickListener {
+        ui.mainFab.setOnClickListener {
             scanQrCode(requireActivity())
         }
-        mainFab.setOnLongClickListener {
+        ui.mainFab.setOnLongClickListener {
             findNavController().navigate(R.id.action_nav_main_to_nav_uri_input)
             true
         }
diff --git a/wallet/src/main/java/net/taler/wallet/UriInputFragment.kt 
b/wallet/src/main/java/net/taler/wallet/UriInputFragment.kt
index eaa6d16..d17977b 100644
--- a/wallet/src/main/java/net/taler/wallet/UriInputFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/UriInputFragment.kt
@@ -27,40 +27,43 @@ import android.view.ViewGroup
 import android.widget.Toast
 import android.widget.Toast.LENGTH_LONG
 import androidx.fragment.app.Fragment
-import kotlinx.android.synthetic.main.fragment_uri_input.*
+import net.taler.wallet.databinding.FragmentUriInputBinding
 
 class UriInputFragment : Fragment() {
 
+    private lateinit var ui: FragmentUriInputBinding
+
     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_uri_input, container, false)
+        ui = FragmentUriInputBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         val clipboard = 
requireContext().getSystemService(ClipboardManager::class.java)!!
 
-        pasteButton.setOnClickListener {
+        ui.pasteButton.setOnClickListener {
             val item = clipboard.primaryClip?.getItemAt(0)
             if (item?.text != null) {
-                uriView.setText(item.text)
+                ui.uriView.setText(item.text)
             } else {
                 if (item?.uri != null) {
-                    uriView.setText(item.uri.toString())
+                    ui.uriView.setText(item.uri.toString())
                 } else {
                     Toast.makeText(requireContext(), R.string.paste_invalid, 
LENGTH_LONG).show()
                 }
             }
         }
-        okButton.setOnClickListener {
-            if (uriView.text?.startsWith("taler://") == true) {
-                uriLayout.error = null
-                val i = Intent(ACTION_VIEW, Uri.parse(uriView.text.toString()))
+        ui.okButton.setOnClickListener {
+            if (ui.uriView.text?.startsWith("taler://") == true) {
+                ui.uriLayout.error = null
+                val i = Intent(ACTION_VIEW, 
Uri.parse(ui.uriView.text.toString()))
                 startActivity(i)
             } else {
-                uriLayout.error = getString(R.string.uri_invalid)
+                ui.uriLayout.error = getString(R.string.uri_invalid)
             }
         }
     }
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt 
b/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt
index 2b4d032..afd9a23 100644
--- a/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt
@@ -26,13 +26,11 @@ import android.view.View.VISIBLE
 import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
-import kotlinx.android.synthetic.main.fragment_balances.*
 import net.taler.common.fadeIn
 import net.taler.wallet.MainViewModel
-import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentBalancesBinding
 
 interface BalanceClickListener {
     fun onBalanceClick(currency: String)
@@ -43,6 +41,7 @@ class BalancesFragment : Fragment(),
 
     private val model: MainViewModel by activityViewModels()
 
+    private lateinit var ui: FragmentBalancesBinding
     private val balancesAdapter = BalanceAdapter(this)
 
     override fun onCreateView(
@@ -50,16 +49,17 @@ class BalancesFragment : Fragment(),
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_balances, container, false)
+        ui = FragmentBalancesBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        mainList.apply {
+        ui.mainList.apply {
             adapter = balancesAdapter
             addItemDecoration(DividerItemDecoration(context, VERTICAL))
         }
 
-        model.balances.observe(viewLifecycleOwner, Observer {
+        model.balances.observe(viewLifecycleOwner, {
             onBalancesChanged(it)
         })
     }
@@ -67,12 +67,12 @@ class BalancesFragment : Fragment(),
     private fun onBalancesChanged(balances: List<BalanceItem>) {
         beginDelayedTransition(view as ViewGroup)
         if (balances.isEmpty()) {
-            mainEmptyState.visibility = VISIBLE
-            mainList.visibility = GONE
+            ui.mainEmptyState.visibility = VISIBLE
+            ui.mainList.visibility = GONE
         } else {
             balancesAdapter.setItems(balances)
-            mainEmptyState.visibility = INVISIBLE
-            mainList.fadeIn()
+            ui.mainEmptyState.visibility = INVISIBLE
+            ui.mainList.fadeIn()
         }
     }
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt 
b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
index c7da205..86b2519 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
@@ -24,43 +24,45 @@ import android.widget.Toast
 import android.widget.Toast.LENGTH_LONG
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import androidx.navigation.fragment.findNavController
 import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
-import kotlinx.android.synthetic.main.fragment_exchange_list.*
 import net.taler.common.EventObserver
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentExchangeListBinding
 
 class ExchangeListFragment : Fragment(), ExchangeClickListener {
 
     private val model: MainViewModel by activityViewModels()
     private val exchangeManager by lazy { model.exchangeManager }
+
+    private lateinit var ui: FragmentExchangeListBinding
     private val exchangeAdapter by lazy { ExchangeAdapter(this) }
 
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_exchange_list, container, 
false)
+        ui = FragmentExchangeListBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        list.apply {
+        ui.list.apply {
             adapter = exchangeAdapter
             addItemDecoration(DividerItemDecoration(context, VERTICAL))
         }
-        addExchangeFab.setOnClickListener {
+        ui.addExchangeFab.setOnClickListener {
             AddExchangeDialogFragment().show(parentFragmentManager, 
"ADD_EXCHANGE")
         }
 
-        exchangeManager.progress.observe(viewLifecycleOwner, Observer { show ->
-            if (show) progressBar.fadeIn() else progressBar.fadeOut()
+        exchangeManager.progress.observe(viewLifecycleOwner, { show ->
+            if (show) ui.progressBar.fadeIn() else ui.progressBar.fadeOut()
         })
-        exchangeManager.exchanges.observe(viewLifecycleOwner, Observer { 
exchanges ->
+        exchangeManager.exchanges.observe(viewLifecycleOwner, { exchanges ->
             onExchangeUpdate(exchanges)
         })
         exchangeManager.addError.observe(viewLifecycleOwner, EventObserver { 
error ->
@@ -71,11 +73,11 @@ class ExchangeListFragment : Fragment(), 
ExchangeClickListener {
     private fun onExchangeUpdate(exchanges: List<ExchangeItem>) {
         exchangeAdapter.update(exchanges)
         if (exchanges.isEmpty()) {
-            emptyState.fadeIn()
-            list.fadeOut()
+            ui.emptyState.fadeIn()
+            ui.list.fadeOut()
         } else {
-            emptyState.fadeOut()
-            list.fadeIn()
+            ui.emptyState.fadeOut()
+            ui.list.fadeIn()
         }
     }
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt 
b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
index 9f5a916..a95a51c 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
@@ -27,12 +27,12 @@ import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.recyclerview.widget.RecyclerView.Adapter
 import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import kotlinx.android.synthetic.main.fragment_select_exchange.*
-import net.taler.lib.common.Amount
 import net.taler.common.toRelativeTime
 import net.taler.common.toShortDate
+import net.taler.lib.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentSelectExchangeBinding
 import net.taler.wallet.exchanges.CoinFeeAdapter.CoinFeeViewHolder
 import net.taler.wallet.exchanges.WireFeeAdapter.WireFeeViewHolder
 
@@ -41,28 +41,29 @@ class SelectExchangeFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
     private val withdrawManager by lazy { model.withdrawManager }
 
+    private lateinit var ui: FragmentSelectExchangeBinding
+
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_select_exchange, container, 
false)
+        ui = FragmentSelectExchangeBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         val fees = withdrawManager.exchangeFees ?: throw 
IllegalStateException()
         if (fees.withdrawFee.isZero()) {
-            withdrawFeeLabel.visibility = GONE
-            withdrawFeeView.visibility = GONE
-        } else withdrawFeeView.setAmount(fees.withdrawFee)
+            ui.withdrawFeeLabel.visibility = GONE
+            ui.withdrawFeeView.visibility = GONE
+        } else ui.withdrawFeeView.setAmount(fees.withdrawFee)
         if (fees.overhead.isZero()) {
-            overheadLabel.visibility = GONE
-            overheadView.visibility = GONE
-        } else overheadView.setAmount(fees.overhead)
-        expirationView.text = 
fees.earliestDepositExpiration.ms.toRelativeTime(requireContext())
-        coinFeesList.adapter =
-            CoinFeeAdapter(fees.coinFees)
-        wireFeesList.adapter =
-            WireFeeAdapter(fees.wireFees)
+            ui.overheadLabel.visibility = GONE
+            ui.overheadView.visibility = GONE
+        } else ui.overheadView.setAmount(fees.overhead)
+        ui.expirationView.text = 
fees.earliestDepositExpiration.ms.toRelativeTime(requireContext())
+        ui.coinFeesList.adapter = CoinFeeAdapter(fees.coinFees)
+        ui.wireFeesList.adapter = WireFeeAdapter(fees.wireFees)
     }
 
     private fun TextView.setAmount(amount: Amount) {
diff --git 
a/wallet/src/main/java/net/taler/wallet/payment/AlreadyPaidFragment.kt 
b/wallet/src/main/java/net/taler/wallet/payment/AlreadyPaidFragment.kt
index 33e3a1d..df2b2b8 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/AlreadyPaidFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/AlreadyPaidFragment.kt
@@ -22,8 +22,7 @@ import android.view.View
 import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.findNavController
-import kotlinx.android.synthetic.main.fragment_already_paid.*
-import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentAlreadyPaidBinding
 
 /**
  * Display the message that the user already paid for the order
@@ -31,15 +30,18 @@ import net.taler.wallet.R
  */
 class AlreadyPaidFragment : Fragment() {
 
+    private lateinit var ui: FragmentAlreadyPaidBinding
+
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_already_paid, container, 
false)
+        ui = FragmentAlreadyPaidBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        backButton.setOnClickListener {
+        ui.backButton.setOnClickListener {
             findNavController().navigateUp()
         }
     }
diff --git 
a/wallet/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt 
b/wallet/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt
index ff70f75..75de93f 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt
@@ -22,11 +22,12 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.fragment.app.DialogFragment
-import kotlinx.android.synthetic.main.fragment_product_image.*
-import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentProductImageBinding
 
 class ProductImageFragment private constructor() : DialogFragment() {
 
+    private lateinit var ui: FragmentProductImageBinding
+
     companion object {
         private const val IMAGE = "image"
 
@@ -41,12 +42,13 @@ class ProductImageFragment private constructor() : 
DialogFragment() {
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_product_image, container, 
false)
+        ui = FragmentProductImageBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         val bitmap = requireArguments().getParcelable<Bitmap>(IMAGE)
-        productImageView.setImageBitmap(bitmap)
+        ui.productImageView.setImageBitmap(bitmap)
     }
 
 }
diff --git 
a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt 
b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
index 99a6ec8..8815408 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
@@ -32,14 +32,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.transition.TransitionManager.beginDelayedTransition
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
-import kotlinx.android.synthetic.main.payment_bottom_bar.*
-import kotlinx.android.synthetic.main.payment_details.*
 import net.taler.common.ContractTerms
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
 import net.taler.lib.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentPromptPaymentBinding
 
 /**
  * Show a payment and ask the user to accept/decline.
@@ -48,13 +47,16 @@ class PromptPaymentFragment : Fragment(), 
ProductImageClickListener {
 
     private val model: MainViewModel by activityViewModels()
     private val paymentManager by lazy { model.paymentManager }
+
+    private lateinit var ui: FragmentPromptPaymentBinding
     private val adapter = ProductAdapter(this)
 
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_prompt_payment, container, 
false)
+        ui = FragmentPromptPaymentBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -62,14 +64,14 @@ class PromptPaymentFragment : Fragment(), 
ProductImageClickListener {
         paymentManager.detailsShown.observe(viewLifecycleOwner, Observer { 
shown ->
             beginDelayedTransition(view as ViewGroup)
             val res = if (shown) R.string.payment_hide_details else 
R.string.payment_show_details
-            detailsButton.setText(res)
-            productsList.visibility = if (shown) VISIBLE else GONE
+            ui.details.detailsButton.setText(res)
+            ui.details.productsList.visibility = if (shown) VISIBLE else GONE
         })
 
-        detailsButton.setOnClickListener {
+        ui.details.detailsButton.setOnClickListener {
             paymentManager.toggleDetailsShown()
         }
-        productsList.apply {
+        ui.details.productsList.apply {
             adapter = this@PromptPaymentFragment.adapter
             layoutManager = LinearLayoutManager(requireContext())
         }
@@ -85,9 +87,9 @@ class PromptPaymentFragment : Fragment(), 
ProductImageClickListener {
     private fun showLoading(show: Boolean) {
         model.showProgressBar.value = show
         if (show) {
-            progressBar.fadeIn()
+            ui.details.progressBar.fadeIn()
         } else {
-            progressBar.fadeOut()
+            ui.details.progressBar.fadeOut()
         }
     }
 
@@ -97,22 +99,22 @@ class PromptPaymentFragment : Fragment(), 
ProductImageClickListener {
                 showLoading(false)
                 val fees = payStatus.amountEffective - payStatus.amountRaw
                 showOrder(payStatus.contractTerms, payStatus.amountRaw, fees)
-                confirmButton.isEnabled = true
-                confirmButton.setOnClickListener {
+                ui.bottom.confirmButton.isEnabled = true
+                ui.bottom.confirmButton.setOnClickListener {
                     model.showProgressBar.value = true
                     paymentManager.confirmPay(
                         payStatus.proposalId,
                         payStatus.contractTerms.amount.currency
                     )
-                    confirmButton.fadeOut()
-                    confirmProgressBar.fadeIn()
+                    ui.bottom.confirmButton.fadeOut()
+                    ui.bottom.confirmProgressBar.fadeIn()
                 }
             }
             is PayStatus.InsufficientBalance -> {
                 showLoading(false)
                 showOrder(payStatus.contractTerms, payStatus.amountRaw)
-                errorView.setText(R.string.payment_balance_insufficient)
-                errorView.fadeIn()
+                
ui.details.errorView.setText(R.string.payment_balance_insufficient)
+                ui.details.errorView.fadeIn()
             }
             is PayStatus.Success -> {
                 showLoading(false)
@@ -128,8 +130,8 @@ class PromptPaymentFragment : Fragment(), 
ProductImageClickListener {
             }
             is PayStatus.Error -> {
                 showLoading(false)
-                errorView.text = getString(R.string.payment_error, 
payStatus.error)
-                errorView.fadeIn()
+                ui.details.errorView.text = getString(R.string.payment_error, 
payStatus.error)
+                ui.details.errorView.fadeIn()
             }
             is PayStatus.None -> {
                 // No payment active.
@@ -143,21 +145,21 @@ class PromptPaymentFragment : Fragment(), 
ProductImageClickListener {
     }
 
     private fun showOrder(contractTerms: ContractTerms, amount:Amount, 
totalFees: Amount? = null) {
-        orderView.text = contractTerms.summary
+        ui.details.orderView.text = contractTerms.summary
         adapter.setItems(contractTerms.products)
         if (contractTerms.products.size == 1) 
paymentManager.toggleDetailsShown()
-        totalView.text = amount.toString()
+        ui.bottom.totalView.text = amount.toString()
         if (totalFees != null && !totalFees.isZero()) {
-            feeView.text = getString(R.string.payment_fee, totalFees)
-            feeView.fadeIn()
+            ui.bottom.feeView.text = getString(R.string.payment_fee, totalFees)
+            ui.bottom.feeView.fadeIn()
         } else {
-            feeView.visibility = GONE
+            ui.bottom.feeView.visibility = GONE
         }
-        orderLabelView.fadeIn()
-        orderView.fadeIn()
-        if (contractTerms.products.size > 1) detailsButton.fadeIn()
-        totalLabelView.fadeIn()
-        totalView.fadeIn()
+        ui.details.orderLabelView.fadeIn()
+        ui.details.orderView.fadeIn()
+        if (contractTerms.products.size > 1) ui.details.detailsButton.fadeIn()
+        ui.bottom.totalLabelView.fadeIn()
+        ui.bottom.totalView.fadeIn()
     }
 
     override fun onImageClick(image: Bitmap) {
diff --git 
a/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt 
b/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt
index 293dbdb..e2f3ca1 100644
--- a/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt
@@ -30,16 +30,15 @@ import android.widget.LinearLayout
 import android.widget.TextView
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.snackbar.Snackbar.LENGTH_SHORT
-import kotlinx.android.synthetic.main.fragment_pending_operations.*
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 import net.taler.wallet.TAG
+import net.taler.wallet.databinding.FragmentPendingOperationsBinding
 import org.json.JSONObject
 
 interface PendingOperationClickListener {
@@ -52,6 +51,7 @@ class PendingOperationsFragment : Fragment(), 
PendingOperationClickListener {
     private val model: MainViewModel by activityViewModels()
     private val pendingOperationsManager by lazy { 
model.pendingOperationsManager }
 
+    private lateinit var ui: FragmentPendingOperationsBinding
     private val pendingAdapter = PendingOperationsAdapter(emptyList(), this)
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -64,13 +64,14 @@ class PendingOperationsFragment : Fragment(), 
PendingOperationClickListener {
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_pending_operations, 
container, false)
+        ui = FragmentPendingOperationsBinding.inflate(inflater, container, 
false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
-        list_pending.apply {
+        ui.listPending.apply {
             val myLayoutManager = LinearLayoutManager(requireContext())
             val myItemDecoration =
                 DividerItemDecoration(requireContext(), 
myLayoutManager.orientation)
@@ -79,7 +80,7 @@ class PendingOperationsFragment : Fragment(), 
PendingOperationClickListener {
             addItemDecoration(myItemDecoration)
         }
 
-        pendingOperationsManager.pendingOperations.observe(viewLifecycleOwner, 
Observer {
+        pendingOperationsManager.pendingOperations.observe(viewLifecycleOwner, 
{
             updatePending(it)
         })
     }
diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt 
b/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
index a52b9d8..63492f4 100644
--- a/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
@@ -20,7 +20,6 @@ import android.os.Bundle
 import android.view.View
 import androidx.appcompat.app.AlertDialog
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import androidx.preference.Preference
 import androidx.preference.PreferenceFragmentCompat
 import androidx.preference.SwitchPreferenceCompat
@@ -75,12 +74,12 @@ class SettingsFragment : PreferenceFragmentCompat() {
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
-        model.lastBackup.observe(viewLifecycleOwner, Observer {
+        model.lastBackup.observe(viewLifecycleOwner, {
             val time = it.toRelativeTime(requireContext())
             prefBackup.summary = getString(R.string.backup_last, time)
         })
 
-        model.devMode.observe(viewLifecycleOwner, Observer { enabled ->
+        model.devMode.observe(viewLifecycleOwner, { enabled ->
             prefDevMode.isChecked = enabled
             if (enabled) {
                 prefVersionApp.summary = "$VERSION_NAME ($FLAVOR 
$VERSION_CODE)"
@@ -95,7 +94,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
             true
         }
 
-        withdrawManager.testWithdrawalInProgress.observe(viewLifecycleOwner, 
Observer { loading ->
+        withdrawManager.testWithdrawalInProgress.observe(viewLifecycleOwner, { 
loading ->
             prefWithdrawTest.isEnabled = !loading
             model.showProgressBar.value = loading
         })
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
index f15e34f..302e684 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -19,68 +19,34 @@ package net.taler.wallet.transactions
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
-import android.view.LayoutInflater
 import android.view.Menu
 import android.view.MenuInflater
 import android.view.MenuItem
-import android.view.View
-import android.view.View.GONE
-import android.view.ViewGroup
-import android.widget.Toast
-import android.widget.Toast.LENGTH_LONG
-import androidx.core.content.ContextCompat.getColor
+import android.widget.TextView
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import kotlinx.android.synthetic.main.fragment_transaction_payment.*
-import kotlinx.android.synthetic.main.fragment_transaction_withdrawal.*
-import kotlinx.android.synthetic.main.fragment_transaction_withdrawal.feeView
-import kotlinx.android.synthetic.main.fragment_transaction_withdrawal.timeView
 import net.taler.common.isSafe
-import net.taler.common.toAbsoluteTime
 import net.taler.lib.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
-import net.taler.wallet.cleanExchange
-import net.taler.wallet.transactions.WithdrawalDetails.TalerBankIntegrationApi
 
-class TransactionDetailFragment : Fragment() {
+abstract class TransactionDetailFragment : Fragment() {
 
     private val model: MainViewModel by activityViewModels()
     private val transactionManager by lazy { model.transactionManager }
-    private val transaction by lazy { 
requireNotNull(transactionManager.selectedTransaction) }
+    protected val transaction: Transaction? get() = 
transactionManager.selectedTransaction
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setHasOptionsMenu(model.devMode.value == true)
     }
 
-    override fun onCreateView(
-        inflater: LayoutInflater,
-        container: ViewGroup?,
-        savedInstanceState: Bundle?
-    ): View? {
-        return inflater.inflate(transaction.detailPageLayout, container, false)
-    }
-
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         super.onActivityCreated(savedInstanceState)
         requireActivity().apply {
-            title = getString(transaction.generalTitleRes)
-        }
-    }
-
-    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        timeView.text = 
transaction.timestamp.ms.toAbsoluteTime(requireContext())
-        when (val e = transaction) {
-            is TransactionWithdrawal -> bind(e)
-            is TransactionPayment -> bind(e)
-            is TransactionRefund -> bind(e)
-            is TransactionRefresh -> bind(e)
-            else -> Toast.makeText(
-                requireContext(),
-                "Transaction ${e.javaClass.simpleName} not implemented.",
-                LENGTH_LONG
-            ).show()
+            transaction?.generalTitleRes?.let {
+                title = getString(it)
+            }
         }
     }
 
@@ -94,54 +60,15 @@ class TransactionDetailFragment : Fragment() {
         }
     }
 
-    private fun bind(t: TransactionWithdrawal) {
-        effectiveAmountLabel.text = getString(R.string.withdraw_total)
-        effectiveAmountView.text = t.amountEffective.toString()
-        if (t.pending && t.withdrawalDetails is TalerBankIntegrationApi &&
-            !t.confirmed && t.withdrawalDetails.bankConfirmationUrl != null
-        ) {
-            val i = Intent().apply {
-                data = Uri.parse(t.withdrawalDetails.bankConfirmationUrl)
-            }
-            if (i.isSafe(requireContext())) {
-                confirmWithdrawalButton.setOnClickListener { startActivity(i) }
-            }
-        } else confirmWithdrawalButton.visibility = GONE
-        chosenAmountLabel.text = getString(R.string.amount_chosen)
-        chosenAmountView.text =
-            getString(R.string.amount_positive, t.amountRaw.toString())
-        val fee = t.amountRaw - t.amountEffective
-        feeView.text = getString(R.string.amount_negative, fee.toString())
-        exchangeView.text = cleanExchange(t.exchangeBaseUrl)
-    }
-
-    private fun bind(t: TransactionPayment) {
-        amountPaidWithFeesView.text = t.amountEffective.toString()
-        val fee = t.amountEffective - t.amountRaw
-        bindOrderAndFee(t.info, t.amountRaw, fee)
-    }
-
-    private fun bind(t: TransactionRefund) {
-        amountPaidWithFeesLabel.text = getString(R.string.transaction_refund)
-        amountPaidWithFeesView.setTextColor(getColor(requireContext(), 
R.color.green))
-        amountPaidWithFeesView.text =
-            getString(R.string.amount_positive, t.amountEffective.toString())
-        val fee = t.amountRaw - t.amountEffective
-        bindOrderAndFee(t.info, t.amountRaw, fee)
-    }
-
-    private fun bind(t: TransactionRefresh) {
-        effectiveAmountLabel.visibility = GONE
-        effectiveAmountView.visibility = GONE
-        confirmWithdrawalButton.visibility = GONE
-        chosenAmountLabel.visibility = GONE
-        chosenAmountView.visibility = GONE
-        val fee = t.amountEffective
-        feeView.text = getString(R.string.amount_negative, fee.toString())
-        exchangeView.text = cleanExchange(t.exchangeBaseUrl)
-    }
-
-    private fun bindOrderAndFee(info: TransactionInfo, raw: Amount, fee: 
Amount) {
+    protected fun bindOrderAndFee(
+        orderSummaryView: TextView,
+        orderAmountView: TextView,
+        orderIdView: TextView,
+        feeView: TextView,
+        info: TransactionInfo,
+        raw: Amount,
+        fee: Amount
+    ) {
         orderAmountView.text = raw.toString()
         feeView.text = getString(R.string.amount_negative, fee.toString())
         orderSummaryView.text = if (info.fulfillmentMessage == null) {
diff --git 
a/wallet/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
similarity index 53%
copy from wallet/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt
copy to 
wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
index ff70f75..84c5c77 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
@@ -14,39 +14,43 @@
  * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-package net.taler.wallet.payment
+package net.taler.wallet.transactions
 
-import android.graphics.Bitmap
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import androidx.fragment.app.DialogFragment
-import kotlinx.android.synthetic.main.fragment_product_image.*
-import net.taler.wallet.R
+import net.taler.common.toAbsoluteTime
+import net.taler.wallet.databinding.FragmentTransactionPaymentBinding
 
-class ProductImageFragment private constructor() : DialogFragment() {
+class TransactionPaymentFragment : TransactionDetailFragment() {
 
-    companion object {
-        private const val IMAGE = "image"
-
-        fun new(image: Bitmap) = ProductImageFragment().apply {
-            arguments = Bundle().apply {
-                putParcelable(IMAGE, image)
-            }
-        }
-    }
+    private lateinit var ui: FragmentTransactionPaymentBinding
 
     override fun onCreateView(
-        inflater: LayoutInflater, container: ViewGroup?,
+        inflater: LayoutInflater,
+        container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_product_image, container, 
false)
+        ui = FragmentTransactionPaymentBinding.inflate(inflater, container, 
false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        val bitmap = requireArguments().getParcelable<Bitmap>(IMAGE)
-        productImageView.setImageBitmap(bitmap)
+        val t = transaction as TransactionPayment
+        ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
+
+        ui.amountPaidWithFeesView.text = t.amountEffective.toString()
+        val fee = t.amountEffective - t.amountRaw
+        bindOrderAndFee(
+            ui.orderSummaryView,
+            ui.orderAmountView,
+            ui.orderIdView,
+            ui.feeView,
+            t.info,
+            t.amountRaw,
+            fee
+        )
     }
 
 }
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
new file mode 100644
index 0000000..717dd33
--- /dev/null
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
@@ -0,0 +1,56 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.transactions
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.GONE
+import android.view.ViewGroup
+import net.taler.common.toAbsoluteTime
+import net.taler.wallet.R
+import net.taler.wallet.cleanExchange
+import net.taler.wallet.databinding.FragmentTransactionWithdrawalBinding
+
+class TransactionRefreshFragment : TransactionDetailFragment() {
+
+    private lateinit var ui: FragmentTransactionWithdrawalBinding
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        ui = FragmentTransactionWithdrawalBinding.inflate(inflater, container, 
false)
+        return ui.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        val t = transaction as TransactionRefresh
+        ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
+
+        ui.effectiveAmountLabel.visibility = GONE
+        ui.effectiveAmountView.visibility = GONE
+        ui.confirmWithdrawalButton.visibility = GONE
+        ui.chosenAmountLabel.visibility = GONE
+        ui.chosenAmountView.visibility = GONE
+        val fee = t.amountEffective
+        ui.feeView.text = getString(R.string.amount_negative, fee.toString())
+        ui. exchangeView.text = cleanExchange(t.exchangeBaseUrl)
+    }
+
+}
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
new file mode 100644
index 0000000..6628d6c
--- /dev/null
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
@@ -0,0 +1,61 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.transactions
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat.getColor
+import net.taler.common.toAbsoluteTime
+import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentTransactionPaymentBinding
+
+class TransactionRefundFragment : TransactionDetailFragment() {
+
+    private lateinit var ui: FragmentTransactionPaymentBinding
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        ui = FragmentTransactionPaymentBinding.inflate(inflater, container, 
false)
+        return ui.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        val t = transaction as TransactionRefund
+        ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
+
+        ui.amountPaidWithFeesLabel.text = 
getString(R.string.transaction_refund)
+        ui.amountPaidWithFeesView.setTextColor(getColor(requireContext(), 
R.color.green))
+        ui.amountPaidWithFeesView.text =
+            getString(R.string.amount_positive, t.amountEffective.toString())
+        val fee = t.amountRaw - t.amountEffective
+        bindOrderAndFee(
+            ui.orderSummaryView,
+            ui.orderAmountView,
+            ui.orderIdView,
+            ui.feeView,
+            t.info,
+            t.amountRaw,
+            fee
+        )
+    }
+
+}
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
new file mode 100644
index 0000000..26965ef
--- /dev/null
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
@@ -0,0 +1,68 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.transactions
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import net.taler.common.isSafe
+import net.taler.common.toAbsoluteTime
+import net.taler.wallet.R
+import net.taler.wallet.cleanExchange
+import net.taler.wallet.databinding.FragmentTransactionWithdrawalBinding
+
+class TransactionWithdrawalFragment : TransactionDetailFragment() {
+
+    private lateinit var ui: FragmentTransactionWithdrawalBinding
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        ui = FragmentTransactionWithdrawalBinding.inflate(inflater, container, 
false)
+        return ui.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        val t = transaction as TransactionWithdrawal
+        ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
+
+        ui.effectiveAmountLabel.text = getString(R.string.withdraw_total)
+        ui.effectiveAmountView.text = t.amountEffective.toString()
+        if (t.pending && t.withdrawalDetails is 
WithdrawalDetails.TalerBankIntegrationApi &&
+            !t.confirmed && t.withdrawalDetails.bankConfirmationUrl != null
+        ) {
+            val i = Intent().apply {
+                data = Uri.parse(t.withdrawalDetails.bankConfirmationUrl)
+            }
+            if (i.isSafe(requireContext())) {
+                ui.confirmWithdrawalButton.setOnClickListener { 
startActivity(i) }
+            }
+        } else ui.confirmWithdrawalButton.visibility = View.GONE
+        ui.chosenAmountLabel.text = getString(R.string.amount_chosen)
+        ui.chosenAmountView.text =
+            getString(R.string.amount_positive, t.amountRaw.toString())
+        val fee = t.amountRaw - t.amountEffective
+        ui.feeView.text = getString(R.string.amount_negative, fee.toString())
+        ui.exchangeView.text = cleanExchange(t.exchangeBaseUrl)
+    }
+
+}
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
index 0817c36..50181c5 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -18,7 +18,7 @@ package net.taler.wallet.transactions
 
 import android.content.Context
 import androidx.annotation.DrawableRes
-import androidx.annotation.LayoutRes
+import androidx.annotation.IdRes
 import androidx.annotation.StringRes
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
@@ -48,8 +48,8 @@ sealed class Transaction {
     @get:DrawableRes
     abstract val icon: Int
 
-    @get:LayoutRes
-    abstract val detailPageLayout: Int
+    @get:IdRes
+    abstract val detailPageNav: Int
 
     abstract val amountType: AmountType
 
@@ -78,7 +78,8 @@ class TransactionWithdrawal(
     override val amountEffective: Amount
 ) : Transaction() {
     override val icon = R.drawable.transaction_withdrawal
-    override val detailPageLayout = R.layout.fragment_transaction_withdrawal
+
+    override val detailPageNav = R.id.action_nav_transactions_detail_withdrawal
 
     @Transient
     override val amountType = AmountType.Positive
@@ -135,7 +136,7 @@ class TransactionPayment(
     override val amountEffective: Amount
 ) : Transaction() {
     override val icon = R.drawable.ic_cash_usd_outline
-    override val detailPageLayout = R.layout.fragment_transaction_payment
+    override val detailPageNav = R.id.action_nav_transactions_detail_payment
 
     @Transient
     override val amountType = AmountType.Negative
@@ -194,7 +195,7 @@ class TransactionRefund(
     override val amountEffective: Amount
 ) : Transaction() {
     override val icon = R.drawable.transaction_refund
-    override val detailPageLayout = R.layout.fragment_transaction_payment
+    override val detailPageNav = R.id.action_nav_transactions_detail_refund
 
     @Transient
     override val amountType = AmountType.Positive
@@ -219,7 +220,7 @@ class TransactionTip(
     override val amountEffective: Amount
 ) : Transaction() {
     override val icon = R.drawable.transaction_tip_accepted // TODO different 
when declined
-    override val detailPageLayout = R.layout.fragment_transaction_payment
+    override val detailPageNav = 0
 
     @Transient
     override val amountType = AmountType.Positive
@@ -242,7 +243,7 @@ class TransactionRefresh(
     override val amountEffective: Amount
 ) : Transaction() {
     override val icon = R.drawable.transaction_refresh
-    override val detailPageLayout = R.layout.fragment_transaction_withdrawal
+    override val detailPageNav = R.id.action_nav_transactions_detail_refresh
 
     @Transient
     override val amountType = AmountType.Negative
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
index 8d47a3f..90510e6 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -30,18 +30,17 @@ import androidx.appcompat.widget.SearchView
 import androidx.appcompat.widget.SearchView.OnQueryTextListener
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import androidx.navigation.fragment.findNavController
 import androidx.recyclerview.selection.SelectionPredicates
 import androidx.recyclerview.selection.SelectionTracker
 import androidx.recyclerview.selection.StorageStrategy
 import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
-import kotlinx.android.synthetic.main.fragment_transactions.*
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentTransactionsBinding
 
 interface OnTransactionClickListener {
     fun onTransactionClicked(transaction: Transaction)
@@ -52,6 +51,7 @@ class TransactionsFragment : Fragment(), 
OnTransactionClickListener, ActionMode.
     private val model: MainViewModel by activityViewModels()
     private val transactionManager by lazy { model.transactionManager }
 
+    private lateinit var ui: FragmentTransactionsBinding
     private val transactionAdapter by lazy { TransactionAdapter(this) }
     private val currency by lazy { transactionManager.selectedCurrency!! }
     private var tracker: SelectionTracker<String>? = null
@@ -66,19 +66,20 @@ class TransactionsFragment : Fragment(), 
OnTransactionClickListener, ActionMode.
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_transactions, container, 
false)
+        ui = FragmentTransactionsBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        list.apply {
+        ui.list.apply {
             adapter = transactionAdapter
             addItemDecoration(DividerItemDecoration(context, VERTICAL))
         }
         val tracker = SelectionTracker.Builder(
             "transaction-selection-id",
-            list,
+            ui.list,
             transactionAdapter.keyProvider,
-            TransactionLookup(list, transactionAdapter),
+            TransactionLookup(ui.list, transactionAdapter),
             StorageStrategy.createStringStorage()
         ).withSelectionPredicate(
             SelectionPredicates.createSelectAnything()
@@ -101,17 +102,17 @@ class TransactionsFragment : Fragment(), 
OnTransactionClickListener, ActionMode.
             }
         })
 
-        transactionManager.progress.observe(viewLifecycleOwner, Observer { 
show ->
-            if (show) progressBar.fadeIn() else progressBar.fadeOut()
+        transactionManager.progress.observe(viewLifecycleOwner, { show ->
+            if (show) ui.progressBar.fadeIn() else ui.progressBar.fadeOut()
         })
-        transactionManager.transactions.observe(viewLifecycleOwner, Observer { 
result ->
+        transactionManager.transactions.observe(viewLifecycleOwner, { result ->
             onTransactionsResult(result)
         })
     }
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         super.onActivityCreated(savedInstanceState)
-        model.balances.observe(viewLifecycleOwner, Observer { balances ->
+        model.balances.observe(viewLifecycleOwner, { balances ->
             balances.find { it.currency == currency }?.available?.let { amount 
->
                 requireActivity().title =
                     getString(R.string.transactions_detail_title_balance, 
amount)
@@ -153,35 +154,35 @@ class TransactionsFragment : Fragment(), 
OnTransactionClickListener, ActionMode.
 
     override fun onTransactionClicked(transaction: Transaction) {
         if (actionMode != null) return // don't react on clicks while in 
action mode
-        if (transaction.detailPageLayout != 0) {
+        if (transaction.detailPageNav != 0) {
             transactionManager.selectedTransaction = transaction
-            findNavController().navigate(R.id.action_nav_transaction_detail)
+            findNavController().navigate(transaction.detailPageNav)
         }
     }
 
     private fun onTransactionsResult(result: TransactionsResult) = when 
(result) {
         is TransactionsResult.Error -> {
-            list.fadeOut()
-            emptyState.text = getString(R.string.transactions_error, 
result.msg)
-            emptyState.fadeIn()
+            ui.list.fadeOut()
+            ui.emptyState.text = getString(R.string.transactions_error, 
result.msg)
+            ui.emptyState.fadeIn()
         }
         is TransactionsResult.Success -> {
             if (result.transactions.isEmpty()) {
                 val isSearch = transactionManager.searchQuery.value != null
-                emptyState.setText(if (isSearch) 
R.string.transactions_empty_search else R.string.transactions_empty)
-                emptyState.fadeIn()
-                list.fadeOut()
+                ui.emptyState.setText(if (isSearch) 
R.string.transactions_empty_search else R.string.transactions_empty)
+                ui.emptyState.fadeIn()
+                ui.list.fadeOut()
             } else {
-                emptyState.fadeOut()
+                ui.emptyState.fadeOut()
                 transactionAdapter.update(result.transactions)
-                list.fadeIn()
+                ui.list.fadeIn()
             }
         }
     }
 
     private fun onSearch(query: String) {
-        list.fadeOut()
-        progressBar.fadeIn()
+        ui.list.fadeOut()
+        ui.progressBar.fadeIn()
         transactionManager.searchQuery.value = query
     }
 
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/ErrorFragment.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/ErrorFragment.kt
index fa5ab2f..8b4ca9d 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/ErrorFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/ErrorFragment.kt
@@ -25,38 +25,41 @@ import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.navigation.fragment.findNavController
-import kotlinx.android.synthetic.main.fragment_error.*
-import net.taler.wallet.R
 import net.taler.wallet.MainViewModel
+import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentErrorBinding
 
 class ErrorFragment : Fragment() {
 
     private val model: MainViewModel by activityViewModels()
     private val withdrawManager by lazy { model.withdrawManager }
 
+    private lateinit var ui: FragmentErrorBinding
+
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_error, container, false)
+        ui = FragmentErrorBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
-        errorTitle.setText(R.string.withdraw_error_title)
-        errorMessage.setText(R.string.withdraw_error_message)
+        ui.errorTitle.setText(R.string.withdraw_error_title)
+        ui.errorMessage.setText(R.string.withdraw_error_message)
 
         // show dev error message if dev mode is on
         val status = withdrawManager.withdrawStatus.value
         if (model.devMode.value == true && status is WithdrawStatus.Error) {
-            errorDevMessage.visibility = VISIBLE
-            errorDevMessage.text = status.message
+            ui.errorDevMessage.visibility = VISIBLE
+            ui.errorDevMessage.text = status.message
         } else {
-            errorDevMessage.visibility = GONE
+            ui.errorDevMessage.visibility = GONE
         }
 
-        backButton.setOnClickListener {
+        ui.backButton.setOnClickListener {
             findNavController().navigateUp()
         }
     }
diff --git 
a/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt
index af76e9b..4b56dd0 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt
@@ -25,11 +25,11 @@ import android.widget.Toast
 import android.widget.Toast.LENGTH_SHORT
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import kotlinx.android.synthetic.main.fragment_manual_withdraw.*
 import net.taler.common.hideKeyboard
 import net.taler.lib.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentManualWithdrawBinding
 import net.taler.wallet.scanQrCode
 import java.util.Locale
 
@@ -40,33 +40,36 @@ class ManualWithdrawFragment : Fragment() {
     private val exchangeItem by lazy { 
requireNotNull(exchangeManager.withdrawalExchange) }
     private val withdrawManager by lazy { model.withdrawManager }
 
+    private lateinit var ui: FragmentManualWithdrawBinding
+
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_manual_withdraw, container, 
false)
+        ui = FragmentManualWithdrawBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        qrCodeButton.setOnClickListener { scanQrCode(requireActivity()) }
-        currencyView.text = exchangeItem.currency
+        ui.qrCodeButton.setOnClickListener { scanQrCode(requireActivity()) }
+        ui.currencyView.text = exchangeItem.currency
         val paymentOptions = exchangeItem.paytoUris.mapNotNull {paytoUri ->
             Uri.parse(paytoUri).authority?.toUpperCase(Locale.getDefault())
         }.joinToString(separator = "\n", prefix = "• ")
-        paymentOptionsLabel.text =
+        ui.paymentOptionsLabel.text =
             getString(R.string.withdraw_manual_payment_options, 
exchangeItem.name, paymentOptions)
-        checkFeesButton.setOnClickListener { onCheckFees() }
+        ui.checkFeesButton.setOnClickListener { onCheckFees() }
     }
 
     private fun onCheckFees() {
-        if (amountView.text?.isEmpty() ?: true) {
-            amountLayout.setError(getString(R.string.withdraw_amount_error))
+        if (ui.amountView.text?.isEmpty() != false) {
+            ui.amountLayout.error = getString(R.string.withdraw_amount_error)
             return
         }
-        amountLayout.setError(null)
-        val value = amountView.text.toString().toLong()
+        ui.amountLayout.error = null
+        val value = ui.amountView.text.toString().toLong()
         val amount = Amount(exchangeItem.currency, value, 0)
-        amountView.hideKeyboard()
+        ui.amountView.hideKeyboard()
         Toast.makeText(requireContext(), "Not implemented: $amount", 
LENGTH_SHORT).show()
         withdrawManager.getWithdrawalDetails(exchangeItem.exchangeBaseUrl, 
amount)
     }
diff --git 
a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
index ffc64d4..0c7687c 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
@@ -24,17 +24,16 @@ import android.widget.Toast
 import android.widget.Toast.LENGTH_SHORT
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import androidx.navigation.fragment.findNavController
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
-import kotlinx.android.synthetic.main.fragment_prompt_withdraw.*
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
 import net.taler.lib.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 import net.taler.wallet.cleanExchange
+import net.taler.wallet.databinding.FragmentPromptWithdrawBinding
 import net.taler.wallet.withdraw.WithdrawStatus.Loading
 import net.taler.wallet.withdraw.WithdrawStatus.TosReviewRequired
 import net.taler.wallet.withdraw.WithdrawStatus.Withdrawing
@@ -44,17 +43,20 @@ class PromptWithdrawFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
     private val withdrawManager by lazy { model.withdrawManager }
 
+    private lateinit var ui: FragmentPromptWithdrawBinding
+
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_prompt_withdraw, container, 
false)
+        ui = FragmentPromptWithdrawBinding.inflate(inflater, container, false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
-        withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer {
+        withdrawManager.withdrawStatus.observe(viewLifecycleOwner, {
             showWithdrawStatus(it)
         })
     }
@@ -62,11 +64,11 @@ class PromptWithdrawFragment : Fragment() {
     private fun showWithdrawStatus(status: WithdrawStatus?): Any = when 
(status) {
         is WithdrawStatus.ReceivedDetails -> {
             showContent(status.amountRaw, status.amountEffective, 
status.exchangeBaseUrl)
-            confirmWithdrawButton.apply {
+            ui.confirmWithdrawButton.apply {
                 text = getString(R.string.withdraw_button_confirm)
                 setOnClickListener {
                     it.fadeOut()
-                    confirmProgressBar.fadeIn()
+                    ui.confirmProgressBar.fadeIn()
                     withdrawManager.acceptWithdrawal()
                 }
                 isEnabled = true
@@ -87,7 +89,7 @@ class PromptWithdrawFragment : Fragment() {
         }
         is TosReviewRequired -> {
             showContent(status.amountRaw, status.amountEffective, 
status.exchangeBaseUrl)
-            confirmWithdrawButton.apply {
+            ui.confirmWithdrawButton.apply {
                 text = getString(R.string.withdraw_button_tos)
                 setOnClickListener {
                     
findNavController().navigate(R.id.action_promptWithdraw_to_reviewExchangeTOS)
@@ -104,29 +106,29 @@ class PromptWithdrawFragment : Fragment() {
 
     private fun showContent(amountRaw: Amount, amountEffective: Amount, 
exchange: String) {
         model.showProgressBar.value = false
-        progressBar.fadeOut()
+        ui.progressBar.fadeOut()
 
-        introView.fadeIn()
-        effectiveAmountView.text = amountEffective.toString()
-        effectiveAmountView.fadeIn()
+        ui.introView.fadeIn()
+        ui.effectiveAmountView.text = amountEffective.toString()
+        ui.effectiveAmountView.fadeIn()
 
-        chosenAmountLabel.fadeIn()
-        chosenAmountView.text = amountRaw.toString()
-        chosenAmountView.fadeIn()
+        ui.chosenAmountLabel.fadeIn()
+        ui.chosenAmountView.text = amountRaw.toString()
+        ui.chosenAmountView.fadeIn()
 
-        feeLabel.fadeIn()
-        feeView.text = getString(R.string.amount_negative, (amountRaw - 
amountEffective).toString())
-        feeView.fadeIn()
+        ui.feeLabel.fadeIn()
+        ui.feeView.text = getString(R.string.amount_negative, (amountRaw - 
amountEffective).toString())
+        ui.feeView.fadeIn()
 
-        exchangeIntroView.fadeIn()
-        withdrawExchangeUrl.text = cleanExchange(exchange)
-        withdrawExchangeUrl.fadeIn()
-        selectExchangeButton.fadeIn()
-        selectExchangeButton.setOnClickListener {
+        ui.exchangeIntroView.fadeIn()
+        ui.withdrawExchangeUrl.text = cleanExchange(exchange)
+        ui.withdrawExchangeUrl.fadeIn()
+        ui.selectExchangeButton.fadeIn()
+        ui.selectExchangeButton.setOnClickListener {
             Toast.makeText(context, "Not yet implemented", LENGTH_SHORT).show()
         }
 
-        withdrawCard.fadeIn()
+        ui.withdrawCard.fadeIn()
     }
 
 }
diff --git 
a/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
index db1f326..73fe760 100644
--- 
a/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
@@ -25,17 +25,19 @@ import androidx.fragment.app.activityViewModels
 import androidx.lifecycle.Observer
 import androidx.navigation.fragment.findNavController
 import io.noties.markwon.Markwon
-import kotlinx.android.synthetic.main.fragment_review_exchange_tos.*
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
+import net.taler.wallet.databinding.FragmentReviewExchangeTosBinding
 import java.text.ParseException
 
 class ReviewExchangeTosFragment : Fragment() {
 
     private val model: MainViewModel by activityViewModels()
     private val withdrawManager by lazy { model.withdrawManager }
+
+    private lateinit var ui: FragmentReviewExchangeTosBinding
     private val markwon by lazy { Markwon.builder(requireContext()).build() }
     private val adapter by lazy { TosAdapter(markwon) }
 
@@ -44,13 +46,14 @@ class ReviewExchangeTosFragment : Fragment() {
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_review_exchange_tos, 
container, false)
+        ui = FragmentReviewExchangeTosBinding.inflate(inflater, container, 
false)
+        return ui.root
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
-        acceptTosCheckBox.isChecked = false
-        acceptTosCheckBox.setOnCheckedChangeListener { _, _ ->
+        ui.acceptTosCheckBox.isChecked = false
+        ui.acceptTosCheckBox.setOnCheckedChangeListener { _, _ ->
             withdrawManager.acceptCurrentTermsOfService()
         }
         withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer {
@@ -65,11 +68,11 @@ class ReviewExchangeTosFragment : Fragment() {
                         return@Observer
                     }
                     adapter.setSections(sections)
-                    tosList.adapter = adapter
-                    tosList.fadeIn()
+                    ui.tosList.adapter = adapter
+                    ui.tosList.fadeIn()
 
-                    acceptTosCheckBox.fadeIn()
-                    progressBar.fadeOut()
+                    ui.acceptTosCheckBox.fadeIn()
+                    ui.progressBar.fadeOut()
                 }
                 is WithdrawStatus.Loading -> {
                     
findNavController().navigate(R.id.action_reviewExchangeTOS_to_promptWithdraw)
@@ -82,11 +85,11 @@ class ReviewExchangeTosFragment : Fragment() {
     }
 
     private fun onTosError(msg: String) {
-        tosList.fadeIn()
-        progressBar.fadeOut()
-        buttonCard.fadeOut()
-        errorView.text = getString(R.string.exchange_tos_error, "\n\n$msg")
-        errorView.fadeIn()
+        ui.tosList.fadeIn()
+        ui.progressBar.fadeOut()
+        ui.buttonCard.fadeOut()
+        ui.errorView.text = getString(R.string.exchange_tos_error, "\n\n$msg")
+        ui.errorView.fadeIn()
     }
 
 }
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
index b6b4285..25c5b72 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -24,8 +24,8 @@ import kotlinx.coroutines.launch
 import kotlinx.serialization.Serializable
 import net.taler.lib.common.Amount
 import net.taler.wallet.TAG
-import net.taler.wallet.backend.WalletBackendApi
 import net.taler.wallet.backend.TalerErrorInfo
+import net.taler.wallet.backend.WalletBackendApi
 import net.taler.wallet.exchanges.ExchangeFees
 import net.taler.wallet.exchanges.ExchangeItem
 import net.taler.wallet.withdraw.WithdrawStatus.ReceivedDetails
@@ -89,14 +89,11 @@ class WithdrawManager(
 
     fun getWithdrawalDetails(uri: String) = scope.launch {
         withdrawStatus.value = WithdrawStatus.Loading(uri)
-        val response =
-            api.request("getWithdrawalDetailsForUri", 
WithdrawalDetailsForUri.serializer()) {
-                put("talerWithdrawUri", uri)
-            }
-        response.onError { error ->
+        api.request("getWithdrawalDetailsForUri", 
WithdrawalDetailsForUri.serializer()) {
+            put("talerWithdrawUri", uri)
+        }.onError { error ->
             handleError("getWithdrawalDetailsForUri", error)
-        }
-        response.onSuccess { details ->
+        }.onSuccess { details ->
             if (details.defaultExchangeBaseUrl == null) {
                 // TODO go to exchange selection screen instead
                 val chosenExchange = 
details.possibleExchanges[0].exchangeBaseUrl
@@ -113,15 +110,12 @@ class WithdrawManager(
         uri: String? = null
     ) = scope.launch {
         withdrawStatus.value = WithdrawStatus.Loading(uri)
-        val response =
-            api.request("getWithdrawalDetailsForAmount", 
WithdrawalDetails.serializer()) {
-                put("exchangeBaseUrl", exchangeBaseUrl)
-                put("amount", amount.toJSONString())
-            }
-        response.onError { error ->
+        api.request("getWithdrawalDetailsForAmount", 
WithdrawalDetails.serializer()) {
+            put("exchangeBaseUrl", exchangeBaseUrl)
+            put("amount", amount.toJSONString())
+        }.onError { error ->
             handleError("getWithdrawalDetailsForAmount", error)
-        }
-        response.onSuccess { details ->
+        }.onSuccess { details ->
             if (details.tosAccepted) {
                 withdrawStatus.value = ReceivedDetails(
                     talerWithdrawUri = uri,
@@ -138,13 +132,11 @@ class WithdrawManager(
         details: WithdrawalDetails,
         uri: String?
     ) = scope.launch {
-        val response = api.request("getExchangeTos", TosResponse.serializer()) 
{
+        api.request("getExchangeTos", TosResponse.serializer()) {
             put("exchangeBaseUrl", exchangeBaseUrl)
-        }
-        response.onError {
+        }.onError {
             handleError("getExchangeTos", it)
-        }
-        response.onSuccess {
+        }.onSuccess {
             withdrawStatus.value = WithdrawStatus.TosReviewRequired(
                 talerWithdrawUri = uri,
                 exchangeBaseUrl = exchangeBaseUrl,
diff --git a/wallet/src/main/res/layout/activity_main.xml 
b/wallet/src/main/res/layout/activity_main.xml
index 3879490..15e11fe 100644
--- a/wallet/src/main/res/layout/activity_main.xml
+++ b/wallet/src/main/res/layout/activity_main.xml
@@ -24,7 +24,8 @@
     tools:openDrawer="start">
 
     <include
-        layout="@layout/app_bar_main"
+        android:id="@+id/content"
+        layout="@layout/app_content_main"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
 
diff --git a/wallet/src/main/res/layout/app_bar_main.xml 
b/wallet/src/main/res/layout/app_content_main.xml
similarity index 100%
rename from wallet/src/main/res/layout/app_bar_main.xml
rename to wallet/src/main/res/layout/app_content_main.xml
diff --git a/wallet/src/main/res/layout/fragment_prompt_payment.xml 
b/wallet/src/main/res/layout/fragment_prompt_payment.xml
index 8d8954d..8cfa3dd 100644
--- a/wallet/src/main/res/layout/fragment_prompt_payment.xml
+++ b/wallet/src/main/res/layout/fragment_prompt_payment.xml
@@ -22,23 +22,23 @@
     tools:context=".payment.PromptPaymentFragment">
 
     <include
-        android:id="@+id/scrollView"
+        android:id="@+id/details"
         layout="@layout/payment_details"
         android:layout_width="0dp"
         android:layout_height="0dp"
-        app:layout_constraintBottom_toTopOf="@+id/bottomView"
+        app:layout_constraintBottom_toTopOf="@+id/bottom"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
     <include
-        android:id="@+id/bottomView"
+        android:id="@+id/bottom"
         layout="@layout/payment_bottom_bar"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/scrollView" />
+        app:layout_constraintTop_toBottomOf="@+id/details" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/wallet/src/main/res/layout/payment_bottom_bar.xml 
b/wallet/src/main/res/layout/payment_bottom_bar.xml
index dbc60ae..496f2f3 100644
--- a/wallet/src/main/res/layout/payment_bottom_bar.xml
+++ b/wallet/src/main/res/layout/payment_bottom_bar.xml
@@ -17,6 +17,7 @@
 <com.google.android.material.card.MaterialCardView 
xmlns:android="http://schemas.android.com/apk/res/android";
     xmlns:app="http://schemas.android.com/apk/res-auto";
     xmlns:tools="http://schemas.android.com/tools";
+    android:id="@+id/bottomView"
     style="@style/BottomCard"
     android:layout_width="0dp"
     android:layout_height="wrap_content"
diff --git a/wallet/src/main/res/navigation/nav_graph.xml 
b/wallet/src/main/res/navigation/nav_graph.xml
index 285fac9..d8ce5b2 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -89,8 +89,26 @@
         tools:layout="@layout/fragment_transactions" />
 
     <fragment
-        android:id="@+id/nav_transactions_detail"
-        android:name="net.taler.wallet.transactions.TransactionDetailFragment"
+        android:id="@+id/nav_transactions_detail_withdrawal"
+        
android:name="net.taler.wallet.transactions.TransactionWithdrawalFragment"
+        android:label="@string/transactions_detail_title"
+        tools:layout="@layout/fragment_transaction_withdrawal" />
+
+    <fragment
+        android:id="@+id/nav_transactions_detail_payment"
+        android:name="net.taler.wallet.transactions.TransactionPaymentFragment"
+        android:label="@string/transactions_detail_title"
+        tools:layout="@layout/fragment_transaction_payment" />
+
+    <fragment
+        android:id="@+id/nav_transactions_detail_refund"
+        android:name="net.taler.wallet.transactions.TransactionRefundFragment"
+        android:label="@string/transactions_detail_title"
+        tools:layout="@layout/fragment_transaction_payment" />
+
+    <fragment
+        android:id="@+id/nav_transactions_detail_refresh"
+        android:name="net.taler.wallet.transactions.TransactionRefreshFragment"
         android:label="@string/transactions_detail_title"
         tools:layout="@layout/fragment_transaction_withdrawal" />
 
@@ -168,7 +186,19 @@
         app:destination="@id/nav_pending_operations" />
 
     <action
-        android:id="@+id/action_nav_transaction_detail"
-        app:destination="@id/nav_transactions_detail" />
+        android:id="@+id/action_nav_transactions_detail_withdrawal"
+        app:destination="@id/nav_transactions_detail_withdrawal" />
+
+    <action
+        android:id="@+id/action_nav_transactions_detail_payment"
+        app:destination="@id/nav_transactions_detail_payment" />
+
+    <action
+        android:id="@+id/action_nav_transactions_detail_refund"
+        app:destination="@id/nav_transactions_detail_refund" />
+
+    <action
+        android:id="@+id/action_nav_transactions_detail_refresh"
+        app:destination="@id/nav_transactions_detail_refresh" />
 
 </navigation>

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]