gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] branch master updated (663d264 -> d351f89)


From: gnunet
Subject: [taler-taler-android] branch master updated (663d264 -> d351f89)
Date: Tue, 08 Sep 2020 22:02:41 +0200

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

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

    from 663d264  [wallet] add logcat viewer to dev settings
     new a6332a0  [wallet] prepare play store upload
     new b0b2b7f  [pos] prepare for play store upload
     new c09cc9c  [cashier] prepare play store upload
     new 7260531  [wallet] change how we check if launching intents is safe
     new 0030ad1  [pos] use bottom sheet for showing errors instead of snackbar
     new 310775d  [wallet] Use bottom sheet to show errors instead of snackbar
     new d351f89  Fix minor lint warnings

The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 anastasis-ui/build.gradle                          |   8 +-
 .../java/org/gnu/anastasis/ui/IntroFragment.kt     |   2 -
 .../java/org/gnu/anastasis/ui/MainViewModel.kt     |   2 +-
 .../ui/authentication/AuthenticationFragment.kt    |   6 +-
 .../gnu/anastasis/ui/authentication/SmsFragment.kt |   4 +-
 .../gnu/anastasis/ui/identity/IdentityFragment.kt  |   2 +-
 .../{ic_baseline_check.xml => ic_add_circle.xml}   |   2 +-
 .../src/main/res/layout/fragment_identity.xml      |   6 +-
 cashier/.gitignore                                 |   1 +
 {wallet => cashier}/fastlane/Appfile               |   2 +-
 cashier/fastlane/Fastfile                          |  43 +++++++++++
 .../metadata/android/en-US/full_description.txt    |   1 +
 .../android/en-US/images/featureGraphic.png        | Bin
 .../metadata/android/en-US/images/icon.png}        | Bin
 .../en-US/images/phoneScreenshots/1_en-US.png      | Bin 0 -> 74406 bytes
 .../en-US/images/phoneScreenshots/2_en-US.png      | Bin 0 -> 87698 bytes
 .../en-US/images/phoneScreenshots/3_en-US.png      | Bin 0 -> 122058 bytes
 .../metadata/android/en-US/short_description.txt   |   1 +
 cashier/fastlane/metadata/android/en-US/title.txt  |   1 +
 .../fastlane/metadata/android/en-US/video.txt      |   0
 .../main/java/net/taler/cashier/BalanceFragment.kt |   6 +-
 .../main/java/net/taler/cashier/MainViewModel.kt   |   2 +-
 .../main/res/layout-w550dp/fragment_balance.xml    |   4 +-
 cashier/src/main/res/layout/fragment_balance.xml   |   4 +-
 merchant-terminal/.gitignore                       |   1 +
 merchant-terminal/build.gradle                     |   6 +-
 {wallet => merchant-terminal}/fastlane/Appfile     |   2 +-
 merchant-terminal/fastlane/Fastfile                |  42 +++++++++++
 .../metadata/android/en-US/full_description.txt    |   5 ++
 .../android/en-US/images/featureGraphic.png        | Bin
 .../metadata/android/en-US/images/icon.png}        | Bin
 .../en-US/images/phoneScreenshots/1_en-US.png      | Bin 0 -> 159178 bytes
 .../en-US/images/phoneScreenshots/2_en-US.png      | Bin 0 -> 146824 bytes
 .../en-US/images/phoneScreenshots/3_en-US.png      | Bin 0 -> 146896 bytes
 .../en-US/images/phoneScreenshots/4_en-US.png      | Bin 0 -> 135798 bytes
 .../en-US/images/phoneScreenshots/5_en-US.png      | Bin 0 -> 80474 bytes
 .../metadata/android/en-US/short_description.txt   |   1 +
 .../fastlane/metadata/android/en-US/title.txt      |   1 +
 .../fastlane/metadata/android/en-US/video.txt      |   0
 .../src/main/java/net/taler/merchantpos/Utils.kt   |  32 --------
 .../net/taler/merchantpos/config/ConfigFragment.kt |   6 +-
 .../taler/merchantpos/history/HistoryFragment.kt   |   9 +--
 .../merchantpos/payment/ProcessPaymentFragment.kt  |   7 +-
 .../net/taler/merchantpos/refund/RefundFragment.kt |  12 +--
 .../src/main/res/values-de/strings.xml             |   1 -
 .../src/main/res/values-fr/strings.xml             |   1 -
 merchant-terminal/src/main/res/values/strings.xml  |   4 +-
 taler-kotlin-android/build.gradle                  |   5 ++
 .../src/main/java/net/taler/common/AndroidUtils.kt |  23 +++++-
 .../java/net/taler/lib/android/ErrorBottomSheet.kt |  64 ++++++++++++++++
 .../src/main/res/drawable/ic_close.xml             |   2 +-
 .../src/main/res/drawable/ic_share.xml             |  10 +++
 .../src/main/res/layout/bottomsheet_error.xml      |  84 +++++++++++----------
 .../src/main/res/values/dimens.xml                 |   3 +-
 .../src/main/res/values/strings.xml                |   3 +
 .../src/main/res/values/styles.xml                 |   8 +-
 wallet/.gitignore                                  |   1 +
 wallet/build.gradle                                |   4 +-
 wallet/fastlane/Fastfile                           |  21 +++++-
 .../src/main/java/net/taler/wallet/MainActivity.kt |  10 +--
 .../net/taler/wallet/backend/WalletResponse.kt     |  13 ++--
 .../wallet/pending/PendingOperationsFragment.kt    |   5 +-
 .../java/net/taler/wallet/refund/RefundManager.kt  |   9 +--
 .../transactions/TransactionDetailFragment.kt      |   6 +-
 .../transactions/TransactionWithdrawalFragment.kt  |   6 +-
 wallet/src/main/res/drawable/ic_add_circle.xml     |  26 -------
 wallet/src/main/res/values-fr/strings.xml          |   2 -
 wallet/src/main/res/values/strings.xml             |   3 +-
 68 files changed, 338 insertions(+), 197 deletions(-)
 copy anastasis-ui/src/main/res/drawable/{ic_baseline_check.xml => 
ic_add_circle.xml} (67%)
 copy {wallet => cashier}/fastlane/Appfile (67%)
 create mode 100644 cashier/fastlane/Fastfile
 create mode 100644 cashier/fastlane/metadata/android/en-US/full_description.txt
 copy {wallet => 
cashier}/fastlane/metadata/android/en-US/images/featureGraphic.png (100%)
 copy cashier/{src/main/ic_launcher-web.png => 
fastlane/metadata/android/en-US/images/icon.png} (100%)
 create mode 100644 
cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
 create mode 100644 
cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
 create mode 100644 
cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
 create mode 100644 
cashier/fastlane/metadata/android/en-US/short_description.txt
 create mode 100644 cashier/fastlane/metadata/android/en-US/title.txt
 copy {wallet => cashier}/fastlane/metadata/android/en-US/video.txt (100%)
 copy {wallet => merchant-terminal}/fastlane/Appfile (65%)
 create mode 100644 merchant-terminal/fastlane/Fastfile
 create mode 100644 
merchant-terminal/fastlane/metadata/android/en-US/full_description.txt
 copy {wallet => 
merchant-terminal}/fastlane/metadata/android/en-US/images/featureGraphic.png 
(100%)
 copy merchant-terminal/{src/main/ic_taler_logo-web.png => 
fastlane/metadata/android/en-US/images/icon.png} (100%)
 create mode 100644 
merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
 create mode 100644 
merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
 create mode 100644 
merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
 create mode 100644 
merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png
 create mode 100644 
merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png
 create mode 100644 
merchant-terminal/fastlane/metadata/android/en-US/short_description.txt
 create mode 100644 merchant-terminal/fastlane/metadata/android/en-US/title.txt
 copy {wallet => merchant-terminal}/fastlane/metadata/android/en-US/video.txt 
(100%)
 delete mode 100644 
merchant-terminal/src/main/java/net/taler/merchantpos/Utils.kt
 create mode 100644 
taler-kotlin-android/src/main/java/net/taler/lib/android/ErrorBottomSheet.kt
 copy anastasis-ui/src/main/res/drawable/ic_baseline_check.xml => 
taler-kotlin-android/src/main/res/drawable/ic_close.xml (69%)
 create mode 100644 taler-kotlin-android/src/main/res/drawable/ic_share.xml
 copy wallet/src/main/res/layout/fragment_review_exchange_tos.xml => 
taler-kotlin-android/src/main/res/layout/bottomsheet_error.xml (51%)
 copy wallet/src/nightly/res/values/strings.xml => 
taler-kotlin-android/src/main/res/values/dimens.xml (87%)
 copy wallet/src/main/res/values/defaults.xml => 
taler-kotlin-android/src/main/res/values/styles.xml (67%)
 delete mode 100644 wallet/src/main/res/drawable/ic_add_circle.xml

diff --git a/anastasis-ui/build.gradle b/anastasis-ui/build.gradle
index 0f86815..cbb0077 100644
--- a/anastasis-ui/build.gradle
+++ b/anastasis-ui/build.gradle
@@ -57,8 +57,8 @@ android {
 dependencies {
     implementation project(":taler-kotlin-android")
 
-    implementation 'com.google.android.material:material:1.2.0-beta01'
-    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+    implementation "com.google.android.material:material:$material_version"
+    implementation 
"androidx.constraintlayout:constraintlayout:$constraintlayout_version"
 
     // Navigation Library
     implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
@@ -69,6 +69,6 @@ dependencies {
 
     testImplementation 'junit:junit:4.13'
 
-    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
-    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
 }
diff --git a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/IntroFragment.kt 
b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/IntroFragment.kt
index c4b8e73..1e5a8d1 100644
--- a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/IntroFragment.kt
+++ b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/IntroFragment.kt
@@ -27,8 +27,6 @@ import kotlinx.android.synthetic.main.fragment_intro.*
 
 class IntroFragment : Fragment() {
 
-    private val model: MainViewModel by activityViewModels()
-
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
diff --git a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/MainViewModel.kt 
b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/MainViewModel.kt
index 3b97578..e2bf0c8 100644
--- a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/MainViewModel.kt
+++ b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/MainViewModel.kt
@@ -21,7 +21,7 @@ import androidx.lifecycle.AndroidViewModel
 import androidx.lifecycle.MutableLiveData
 import org.gnu.anastasis.ui.identity.LOCATIONS
 
-class MainViewModel(private val app: Application) : AndroidViewModel(app) {
+class MainViewModel(app: Application) : AndroidViewModel(app) {
 
     val currentCountry = MutableLiveData(LOCATIONS[0])
 
diff --git 
a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/authentication/AuthenticationFragment.kt
 
b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/authentication/AuthenticationFragment.kt
index fd770cb..5f7ab2e 100644
--- 
a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/authentication/AuthenticationFragment.kt
+++ 
b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/authentication/AuthenticationFragment.kt
@@ -79,17 +79,17 @@ class AuthenticationFragment : Fragment() {
             )
         }
 
-        viewModel.securityQuestionChecked.observe(viewLifecycleOwner, Observer 
{ checked ->
+        viewModel.securityQuestionChecked.observe(viewLifecycleOwner, { 
checked ->
             passwordCard.isChecked = checked
             updatePrice(checked, Amount.fromJSONString("KUDOS:0.5"))
             updateNextButtonState()
         })
-        viewModel.smsChecked.observe(viewLifecycleOwner, Observer { checked ->
+        viewModel.smsChecked.observe(viewLifecycleOwner, { checked ->
             smsCard.isChecked = checked
             updatePrice(checked, Amount.fromJSONString("KUDOS:1.0"))
             updateNextButtonState()
         })
-        viewModel.videoChecked.observe(viewLifecycleOwner, Observer { checked 
->
+        viewModel.videoChecked.observe(viewLifecycleOwner, { checked ->
             videoCard.isChecked = checked
             updatePrice(checked, Amount.fromJSONString("KUDOS:2.25"))
             updateNextButtonState()
diff --git 
a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/authentication/SmsFragment.kt 
b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/authentication/SmsFragment.kt
index f20fba5..2daf14a 100644
--- 
a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/authentication/SmsFragment.kt
+++ 
b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/authentication/SmsFragment.kt
@@ -97,8 +97,8 @@ class SmsFragment : Fragment() {
     private fun fillPhoneNumber() {
         val telephonyService = 
requireContext().getSystemService(TelephonyManager::class.java)
         telephonyService?.line1Number?.let { phoneNumber ->
-            smsView?.editText?.setText(phoneNumber)
-            smsView?.editText?.setSelection(phoneNumber.length)
+            smsView.editText?.setText(phoneNumber)
+            smsView.editText?.setSelection(phoneNumber.length)
         }
     }
 
diff --git 
a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/identity/IdentityFragment.kt 
b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/identity/IdentityFragment.kt
index 40fa477..bcfbf24 100644
--- 
a/anastasis-ui/src/main/java/org/gnu/anastasis/ui/identity/IdentityFragment.kt
+++ 
b/anastasis-ui/src/main/java/org/gnu/anastasis/ui/identity/IdentityFragment.kt
@@ -52,7 +52,7 @@ class AnastasisIdentityFragment : Fragment() {
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
-        model.currentCountry.observe(viewLifecycleOwner, Observer { country ->
+        model.currentCountry.observe(viewLifecycleOwner, { country ->
             countryView.text = country.name
             if (stub != null) {
                 stub.layoutResource = country.layoutRes
diff --git a/anastasis-ui/src/main/res/drawable/ic_baseline_check.xml 
b/anastasis-ui/src/main/res/drawable/ic_add_circle.xml
similarity index 67%
copy from anastasis-ui/src/main/res/drawable/ic_baseline_check.xml
copy to anastasis-ui/src/main/res/drawable/ic_add_circle.xml
index 219e80e..76e1fcb 100644
--- a/anastasis-ui/src/main/res/drawable/ic_baseline_check.xml
+++ b/anastasis-ui/src/main/res/drawable/ic_add_circle.xml
@@ -6,5 +6,5 @@
     android:viewportHeight="24">
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" 
/>
+        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 
10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,13v-2h4L11,7h2v4h4v2z" />
 </vector>
diff --git a/anastasis-ui/src/main/res/layout/fragment_identity.xml 
b/anastasis-ui/src/main/res/layout/fragment_identity.xml
index 072414d..bcf6e4d 100644
--- a/anastasis-ui/src/main/res/layout/fragment_identity.xml
+++ b/anastasis-ui/src/main/res/layout/fragment_identity.xml
@@ -68,7 +68,7 @@
             android:layout_height="wrap_content"
             android:layout_marginStart="8dp"
             android:text="Change"
-            android:textColor="@color/colorAccent"
+            android:textColor="?attr/colorAccent"
             app:layout_constraintBaseline_toBaselineOf="@+id/countryView"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintHorizontal_bias="0.0"
@@ -144,9 +144,9 @@
             android:layout_height="wrap_content"
             android:layout_margin="16dp"
             android:backgroundTint="@color/green"
-            android:drawableLeft="@drawable/ic_baseline_lock"
-            android:drawableTint="?attr/colorOnPrimarySurface"
+            android:drawableStart="@drawable/ic_baseline_lock"
             android:text="Encrypt Identity"
+            app:drawableTint="?attr/colorOnPrimarySurface"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent" />
 
diff --git a/cashier/.gitignore b/cashier/.gitignore
index 796b96d..f4562cb 100644
--- a/cashier/.gitignore
+++ b/cashier/.gitignore
@@ -1 +1,2 @@
 /build
+/.bundle
diff --git a/wallet/fastlane/Appfile b/cashier/fastlane/Appfile
similarity index 67%
copy from wallet/fastlane/Appfile
copy to cashier/fastlane/Appfile
index 3166568..ca67ba4 100644
--- a/wallet/fastlane/Appfile
+++ b/cashier/fastlane/Appfile
@@ -1,2 +1,2 @@
 json_key_file("../../api-5955905454448196576-583043-ea133c8ceb16.json")
-package_name("net.taler.wallet")
+package_name("net.taler.cashier")
diff --git a/cashier/fastlane/Fastfile b/cashier/fastlane/Fastfile
new file mode 100644
index 0000000..08cf386
--- /dev/null
+++ b/cashier/fastlane/Fastfile
@@ -0,0 +1,43 @@
+# This file contains the fastlane.tools configuration
+# You can find the documentation at https://docs.fastlane.tools
+#
+# For a list of all available actions, check out
+#
+#     https://docs.fastlane.tools/actions
+#
+# For a list of all available plugins, check out
+#
+#     https://docs.fastlane.tools/plugins/available-plugins
+#
+
+# Uncomment the line if you want fastlane to automatically update itself
+# update_fastlane
+
+opt_out_usage
+
+default_platform(:android)
+
+platform :android do
+
+  desc "Deploy a new version to the Google Play beta track"
+  lane :deploy do
+    gradle(
+        task: "bundle",
+        build_type: "Release",
+        gradle_path: '../gradlew',
+        properties: {
+            "android.injected.signing.store.file" => 
ENV["TALER_KEYSTORE_PATH"],
+            "android.injected.signing.store.password" => 
ENV["TALER_KEYSTORE_PASS"],
+            "android.injected.signing.key.alias" => 
ENV["TALER_KEYSTORE_CASHIER_ALIAS"],
+            "android.injected.signing.key.password" => 
ENV["TALER_KEYSTORE_CASHIER_PASS"],
+        }
+    )
+    upload_to_play_store(
+        track: 'beta',
+        skip_upload_images: 'true',
+        skip_upload_screenshots: 'true',
+        skip_upload_apk: 'true', # This is an app bundle, so APK is not 
possible
+        validate_only: 'true'
+    )
+  end
+end
diff --git a/cashier/fastlane/metadata/android/en-US/full_description.txt 
b/cashier/fastlane/metadata/android/en-US/full_description.txt
new file mode 100644
index 0000000..c4d2adb
--- /dev/null
+++ b/cashier/fastlane/metadata/android/en-US/full_description.txt
@@ -0,0 +1 @@
+The GNU Taler Cashier app allows you to take in physical cash and hand 
electronic Taler cash in exchange. This is useful for regional or 
organizational currencies.
\ No newline at end of file
diff --git a/wallet/fastlane/metadata/android/en-US/images/featureGraphic.png 
b/cashier/fastlane/metadata/android/en-US/images/featureGraphic.png
similarity index 100%
copy from wallet/fastlane/metadata/android/en-US/images/featureGraphic.png
copy to cashier/fastlane/metadata/android/en-US/images/featureGraphic.png
diff --git a/cashier/src/main/ic_launcher-web.png 
b/cashier/fastlane/metadata/android/en-US/images/icon.png
similarity index 100%
copy from cashier/src/main/ic_launcher-web.png
copy to cashier/fastlane/metadata/android/en-US/images/icon.png
diff --git 
a/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png 
b/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
new file mode 100644
index 0000000..2d7d8c1
Binary files /dev/null and 
b/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png 
differ
diff --git 
a/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png 
b/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
new file mode 100644
index 0000000..a015257
Binary files /dev/null and 
b/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png 
differ
diff --git 
a/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png 
b/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
new file mode 100644
index 0000000..683bb95
Binary files /dev/null and 
b/cashier/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png 
differ
diff --git a/cashier/fastlane/metadata/android/en-US/short_description.txt 
b/cashier/fastlane/metadata/android/en-US/short_description.txt
new file mode 100644
index 0000000..5c80416
--- /dev/null
+++ b/cashier/fastlane/metadata/android/en-US/short_description.txt
@@ -0,0 +1 @@
+Take cash and give out electronic cash
\ No newline at end of file
diff --git a/cashier/fastlane/metadata/android/en-US/title.txt 
b/cashier/fastlane/metadata/android/en-US/title.txt
new file mode 100644
index 0000000..b66b4e4
--- /dev/null
+++ b/cashier/fastlane/metadata/android/en-US/title.txt
@@ -0,0 +1 @@
+Taler Cashier
\ No newline at end of file
diff --git a/wallet/fastlane/metadata/android/en-US/video.txt 
b/cashier/fastlane/metadata/android/en-US/video.txt
similarity index 100%
copy from wallet/fastlane/metadata/android/en-US/video.txt
copy to cashier/fastlane/metadata/android/en-US/video.txt
diff --git a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt 
b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
index 1114080..541bca2 100644
--- a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
@@ -62,10 +62,10 @@ class BalanceFragment : Fragment() {
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        withdrawManager.lastTransaction.observe(viewLifecycleOwner, Observer { 
lastTransaction ->
+        withdrawManager.lastTransaction.observe(viewLifecycleOwner, { 
lastTransaction ->
             onLastTransaction(lastTransaction)
         })
-        viewModel.balance.observe(viewLifecycleOwner, Observer { result ->
+        viewModel.balance.observe(viewLifecycleOwner, { result ->
             onBalanceUpdated(result)
         })
         ui.button5.setOnClickListener { onAmountButtonPressed(5) }
@@ -82,7 +82,7 @@ class BalanceFragment : Fragment() {
                 true
             } else false
         }
-        configManager.currency.observe(viewLifecycleOwner, Observer { currency 
->
+        configManager.currency.observe(viewLifecycleOwner, { currency ->
             ui.currencyView.text = currency
         })
         ui.confirmWithdrawalButton.setOnClickListener { 
onAmountConfirmed(getAmountFromView()) }
diff --git a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt 
b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
index 2cce8cd..253c7d5 100644
--- a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
+++ b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
@@ -69,7 +69,7 @@ class MainViewModel(private val app: Application) : 
AndroidViewModel(app) {
         val result = when (val response = makeJsonGetRequest(url, config)) {
             is HttpJsonResult.Success -> {
                 try {
-                    val balanceObj = response.json.getJSONObject("balance");
+                    val balanceObj = response.json.getJSONObject("balance")
                     val balanceAmount = balanceObj.getString("amount")
                     val positive = when (val creditDebitIndicator =
                         balanceObj.getString("credit_debit_indicator")) {
diff --git a/cashier/src/main/res/layout-w550dp/fragment_balance.xml 
b/cashier/src/main/res/layout-w550dp/fragment_balance.xml
index 40fa6af..bcfffc7 100644
--- a/cashier/src/main/res/layout-w550dp/fragment_balance.xml
+++ b/cashier/src/main/res/layout-w550dp/fragment_balance.xml
@@ -27,13 +27,13 @@
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:background="?attr/colorPrimaryDark"
-        android:drawableStart="@drawable/ic_check_circle"
         android:drawablePadding="8dp"
-        android:drawableTint="?attr/colorOnPrimarySurface"
         android:gravity="center_vertical"
         android:padding="8dp"
         android:textColor="?attr/colorOnPrimarySurface"
         android:visibility="gone"
+        app:drawableStartCompat="@drawable/ic_check_circle"
+        app:drawableTint="?attr/colorOnPrimarySurface"
         app:layout_constraintEnd_toStartOf="@+id/guideline"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
diff --git a/cashier/src/main/res/layout/fragment_balance.xml 
b/cashier/src/main/res/layout/fragment_balance.xml
index fcd0e0a..5a11b2a 100644
--- a/cashier/src/main/res/layout/fragment_balance.xml
+++ b/cashier/src/main/res/layout/fragment_balance.xml
@@ -27,13 +27,13 @@
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:background="?attr/colorPrimaryDark"
-        android:drawableStart="@drawable/ic_check_circle"
         android:drawablePadding="8dp"
-        android:drawableTint="?attr/colorOnPrimarySurface"
         android:gravity="center_vertical"
         android:padding="8dp"
         android:textColor="?attr/colorOnPrimarySurface"
         android:visibility="gone"
+        app:drawableStartCompat="@drawable/ic_check_circle"
+        app:drawableTint="?attr/colorOnPrimarySurface"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
diff --git a/merchant-terminal/.gitignore b/merchant-terminal/.gitignore
index 796b96d..f4562cb 100644
--- a/merchant-terminal/.gitignore
+++ b/merchant-terminal/.gitignore
@@ -1 +1,2 @@
 /build
+/.bundle
diff --git a/merchant-terminal/build.gradle b/merchant-terminal/build.gradle
index df8cee5..d56dd5c 100644
--- a/merchant-terminal/build.gradle
+++ b/merchant-terminal/build.gradle
@@ -14,8 +14,8 @@ android {
         applicationId "net.taler.merchantpos"
         minSdkVersion 24
         targetSdkVersion 29
-        versionCode 1
-        versionName "1.0"
+        versionCode 2
+        versionName "0.1"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
 
@@ -69,7 +69,7 @@ dependencies {
     implementation "com.google.android.material:material:$material_version"
     implementation 
"androidx.constraintlayout:constraintlayout:$constraintlayout_version"
     implementation "androidx.recyclerview:recyclerview:1.1.0"
-    implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc01"
+    implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc02"
 
     // Navigation
     implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
diff --git a/wallet/fastlane/Appfile b/merchant-terminal/fastlane/Appfile
similarity index 65%
copy from wallet/fastlane/Appfile
copy to merchant-terminal/fastlane/Appfile
index 3166568..df5a7c3 100644
--- a/wallet/fastlane/Appfile
+++ b/merchant-terminal/fastlane/Appfile
@@ -1,2 +1,2 @@
 json_key_file("../../api-5955905454448196576-583043-ea133c8ceb16.json")
-package_name("net.taler.wallet")
+package_name("net.taler.merchantpos")
diff --git a/merchant-terminal/fastlane/Fastfile 
b/merchant-terminal/fastlane/Fastfile
new file mode 100644
index 0000000..2398c81
--- /dev/null
+++ b/merchant-terminal/fastlane/Fastfile
@@ -0,0 +1,42 @@
+# This file contains the fastlane.tools configuration
+# You can find the documentation at https://docs.fastlane.tools
+#
+# For a list of all available actions, check out
+#
+#     https://docs.fastlane.tools/actions
+#
+# For a list of all available plugins, check out
+#
+#     https://docs.fastlane.tools/plugins/available-plugins
+#
+
+# Uncomment the line if you want fastlane to automatically update itself
+# update_fastlane
+
+opt_out_usage
+
+default_platform(:android)
+
+platform :android do
+  desc "Deploy a new version to the Google Play beta track"
+  lane :deploy do
+    gradle(
+        task: "bundle",
+        build_type: "Release",
+        gradle_path: '../gradlew',
+        properties: {
+            "android.injected.signing.store.file" => 
ENV["TALER_KEYSTORE_PATH"],
+            "android.injected.signing.store.password" => 
ENV["TALER_KEYSTORE_PASS"],
+            "android.injected.signing.key.alias" => 
ENV["TALER_KEYSTORE_POS_ALIAS"],
+            "android.injected.signing.key.password" => 
ENV["TALER_KEYSTORE_POS_PASS"],
+        }
+    )
+    upload_to_play_store(
+        track: 'beta',
+        skip_upload_images: 'true',
+        skip_upload_screenshots: 'true',
+        skip_upload_apk: 'true', # This is an app bundle, so APK is not 
possible
+        validate_only: 'true'
+    )
+  end
+end
diff --git 
a/merchant-terminal/fastlane/metadata/android/en-US/full_description.txt 
b/merchant-terminal/fastlane/metadata/android/en-US/full_description.txt
new file mode 100644
index 0000000..b6e7f88
--- /dev/null
+++ b/merchant-terminal/fastlane/metadata/android/en-US/full_description.txt
@@ -0,0 +1,5 @@
+The GNU Taler merchant POS (point of sale) terminal allows sellers to
+
+* process customers’ orders by adding or removing products
+* calculate the amount owed by the customer
+* let the customer make a Taler payment via QR code or NFC
\ No newline at end of file
diff --git a/wallet/fastlane/metadata/android/en-US/images/featureGraphic.png 
b/merchant-terminal/fastlane/metadata/android/en-US/images/featureGraphic.png
similarity index 100%
copy from wallet/fastlane/metadata/android/en-US/images/featureGraphic.png
copy to 
merchant-terminal/fastlane/metadata/android/en-US/images/featureGraphic.png
diff --git a/merchant-terminal/src/main/ic_taler_logo-web.png 
b/merchant-terminal/fastlane/metadata/android/en-US/images/icon.png
similarity index 100%
copy from merchant-terminal/src/main/ic_taler_logo-web.png
copy to merchant-terminal/fastlane/metadata/android/en-US/images/icon.png
diff --git 
a/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
new file mode 100644
index 0000000..4eecd67
Binary files /dev/null and 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
 differ
diff --git 
a/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
new file mode 100644
index 0000000..2c2b3df
Binary files /dev/null and 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
 differ
diff --git 
a/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
new file mode 100644
index 0000000..429f508
Binary files /dev/null and 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
 differ
diff --git 
a/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png
 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png
new file mode 100644
index 0000000..ac86e21
Binary files /dev/null and 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png
 differ
diff --git 
a/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png
 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png
new file mode 100644
index 0000000..f6750e9
Binary files /dev/null and 
b/merchant-terminal/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png
 differ
diff --git 
a/merchant-terminal/fastlane/metadata/android/en-US/short_description.txt 
b/merchant-terminal/fastlane/metadata/android/en-US/short_description.txt
new file mode 100644
index 0000000..6e51af5
--- /dev/null
+++ b/merchant-terminal/fastlane/metadata/android/en-US/short_description.txt
@@ -0,0 +1 @@
+Process orders and take in Taler payments
\ No newline at end of file
diff --git a/merchant-terminal/fastlane/metadata/android/en-US/title.txt 
b/merchant-terminal/fastlane/metadata/android/en-US/title.txt
new file mode 100644
index 0000000..235199c
--- /dev/null
+++ b/merchant-terminal/fastlane/metadata/android/en-US/title.txt
@@ -0,0 +1 @@
+Taler Point-of-Sale Merchant Terminal
\ No newline at end of file
diff --git a/wallet/fastlane/metadata/android/en-US/video.txt 
b/merchant-terminal/fastlane/metadata/android/en-US/video.txt
similarity index 100%
copy from wallet/fastlane/metadata/android/en-US/video.txt
copy to merchant-terminal/fastlane/metadata/android/en-US/video.txt
diff --git a/merchant-terminal/src/main/java/net/taler/merchantpos/Utils.kt 
b/merchant-terminal/src/main/java/net/taler/merchantpos/Utils.kt
deleted file mode 100644
index 137dd37..0000000
--- a/merchant-terminal/src/main/java/net/taler/merchantpos/Utils.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.merchantpos
-
-import android.view.View
-import androidx.annotation.StringRes
-import com.google.android.material.bottomsheet.BottomSheetDialog
-import 
com.google.android.material.snackbar.BaseTransientBottomBar.ANIMATION_MODE_FADE
-import com.google.android.material.snackbar.BaseTransientBottomBar.Duration
-import com.google.android.material.snackbar.Snackbar.make
-
-fun topSnackbar(view: View, text: CharSequence, @Duration duration: Int) {
-    make(view, text, duration).show()
-}
-
-fun topSnackbar(view: View, @StringRes resId: Int, @Duration duration: Int) {
-    topSnackbar(view, view.resources.getText(resId), duration)
-}
diff --git 
a/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigFragment.kt
 
b/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigFragment.kt
index c31eb61..3ee5148 100644
--- 
a/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigFragment.kt
+++ 
b/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigFragment.kt
@@ -27,7 +27,6 @@ import android.view.View.VISIBLE
 import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG
 import com.google.android.material.snackbar.Snackbar
 import net.taler.common.navigate
@@ -35,7 +34,6 @@ import net.taler.merchantpos.MainViewModel
 import net.taler.merchantpos.R
 import 
net.taler.merchantpos.config.ConfigFragmentDirections.Companion.actionSettingsToOrder
 import net.taler.merchantpos.databinding.FragmentMerchantConfigBinding
-import net.taler.merchantpos.topSnackbar
 
 /**
  * Fragment that displays merchant settings.
@@ -76,7 +74,7 @@ class ConfigFragment : Fragment() {
                 password = ui.passwordView.editText!!.text.toString()
             )
             configManager.fetchConfig(config, true, 
ui.savePasswordCheckBox.isChecked)
-            configManager.configUpdateResult.observe(viewLifecycleOwner, 
Observer { result ->
+            configManager.configUpdateResult.observe(viewLifecycleOwner, { 
result ->
                 if (onConfigUpdate(result)) {
                     
configManager.configUpdateResult.removeObservers(viewLifecycleOwner)
                 }
@@ -150,7 +148,7 @@ class ConfigFragment : Fragment() {
     private fun onConfigReceived(currency: String) {
         onResultReceived()
         updateView()
-        topSnackbar(requireView(), getString(R.string.config_changed, 
currency), LENGTH_LONG)
+        Snackbar.make(requireView(), getString(R.string.config_changed, 
currency), LENGTH_LONG).show()
         navigate(actionSettingsToOrder())
     }
 
diff --git 
a/merchant-terminal/src/main/java/net/taler/merchantpos/history/HistoryFragment.kt
 
b/merchant-terminal/src/main/java/net/taler/merchantpos/history/HistoryFragment.kt
index 3ef48e1..c7cd8ba 100644
--- 
a/merchant-terminal/src/main/java/net/taler/merchantpos/history/HistoryFragment.kt
+++ 
b/merchant-terminal/src/main/java/net/taler/merchantpos/history/HistoryFragment.kt
@@ -26,10 +26,9 @@ import androidx.fragment.app.activityViewModels
 import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
 import androidx.recyclerview.widget.LinearLayoutManager
-import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG
-import com.google.android.material.snackbar.Snackbar
 import net.taler.common.exhaustive
 import net.taler.common.navigate
+import net.taler.common.showError
 import net.taler.merchantlib.OrderHistoryEntry
 import net.taler.merchantpos.MainViewModel
 import net.taler.merchantpos.databinding.FragmentMerchantHistoryBinding
@@ -81,7 +80,7 @@ class HistoryFragment : Fragment(), RefundClickListener {
         })
         historyManager.items.observe(viewLifecycleOwner, { result ->
             when (result) {
-                is HistoryResult.Error -> onError(result.msg)
+                is HistoryResult.Error -> 
requireActivity().showError(result.msg)
                 is HistoryResult.Success -> 
historyListAdapter.setData(result.items)
             }.exhaustive
         })
@@ -96,10 +95,6 @@ class HistoryFragment : Fragment(), RefundClickListener {
         }
     }
 
-    private fun onError(msg: String) {
-        Snackbar.make(requireView(), msg, LENGTH_LONG).show()
-    }
-
     override fun onRefundClicked(item: OrderHistoryEntry) {
         refundManager.startRefund(item)
         navigate(actionNavHistoryToRefundFragment())
diff --git 
a/merchant-terminal/src/main/java/net/taler/merchantpos/payment/ProcessPaymentFragment.kt
 
b/merchant-terminal/src/main/java/net/taler/merchantpos/payment/ProcessPaymentFragment.kt
index 5c0a894..dc5d554 100644
--- 
a/merchant-terminal/src/main/java/net/taler/merchantpos/payment/ProcessPaymentFragment.kt
+++ 
b/merchant-terminal/src/main/java/net/taler/merchantpos/payment/ProcessPaymentFragment.kt
@@ -24,16 +24,17 @@ import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.navigation.fragment.findNavController
 import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG
+import com.google.android.material.snackbar.Snackbar
 import net.taler.common.NfcManager.Companion.hasNfc
 import net.taler.common.QrCodeManager.makeQrCode
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
 import net.taler.common.navigate
+import net.taler.common.showError
 import net.taler.merchantpos.MainViewModel
 import net.taler.merchantpos.R
 import net.taler.merchantpos.databinding.FragmentProcessPaymentBinding
 import 
net.taler.merchantpos.payment.ProcessPaymentFragmentDirections.Companion.actionProcessPaymentToPaymentSuccess
-import net.taler.merchantpos.topSnackbar
 
 class ProcessPaymentFragment : Fragment() {
 
@@ -69,7 +70,7 @@ class ProcessPaymentFragment : Fragment() {
 
     private fun onPaymentStateChanged(payment: Payment) {
         if (payment.error != null) {
-            topSnackbar(requireView(), payment.error, LENGTH_LONG)
+            requireActivity().showError(R.string.error_payment, payment.error)
             findNavController().navigateUp()
             return
         }
@@ -95,7 +96,7 @@ class ProcessPaymentFragment : Fragment() {
     private fun onPaymentCancel() {
         paymentManager.cancelPayment(getString(R.string.error_cancelled))
         findNavController().navigateUp()
-        topSnackbar(requireView(), R.string.payment_canceled, LENGTH_LONG)
+        Snackbar.make(requireView(), R.string.payment_canceled, 
LENGTH_LONG).show()
     }
 
 }
diff --git 
a/merchant-terminal/src/main/java/net/taler/merchantpos/refund/RefundFragment.kt
 
b/merchant-terminal/src/main/java/net/taler/merchantpos/refund/RefundFragment.kt
index 91e68e6..5306b2f 100644
--- 
a/merchant-terminal/src/main/java/net/taler/merchantpos/refund/RefundFragment.kt
+++ 
b/merchant-terminal/src/main/java/net/taler/merchantpos/refund/RefundFragment.kt
@@ -20,6 +20,7 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.annotation.StringRes
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.navigation.fragment.findNavController
@@ -28,6 +29,7 @@ import com.google.android.material.snackbar.Snackbar
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
 import net.taler.common.navigate
+import net.taler.common.showError
 import net.taler.lib.common.Amount
 import net.taler.lib.common.AmountParserException
 import net.taler.merchantlib.OrderHistoryEntry
@@ -89,9 +91,9 @@ class RefundFragment : Fragment() {
     }
 
     private fun onRefundResultChanged(result: RefundResult?): Any = when 
(result) {
-        is Error -> onError(result.msg)
-        PastDeadline -> onError(getString(R.string.refund_error_deadline))
-        AlreadyRefunded -> 
onError(getString(R.string.refund_error_already_refunded))
+        is Error -> onError(R.string.refund_error_backend, result.msg)
+        PastDeadline -> onError(R.string.refund_error_deadline)
+        AlreadyRefunded -> onError(R.string.refund_error_already_refunded)
         is Success -> {
             ui.progressBar.fadeOut()
             ui.refundButton.fadeIn()
@@ -101,8 +103,8 @@ class RefundFragment : Fragment() {
         }
     }
 
-    private fun onError(msg: String) {
-        Snackbar.make(requireView(), msg, LENGTH_LONG).show()
+    private fun onError(@StringRes main: Int, details: String = "") {
+        requireActivity().showError(main, details)
         ui.progressBar.fadeOut()
         ui.refundButton.fadeIn()
     }
diff --git a/merchant-terminal/src/main/res/values-de/strings.xml 
b/merchant-terminal/src/main/res/values-de/strings.xml
index 03877cb..22f9450 100644
--- a/merchant-terminal/src/main/res/values-de/strings.xml
+++ b/merchant-terminal/src/main/res/values-de/strings.xml
@@ -40,7 +40,6 @@
     <string name="refund_error_deadline">Die Rückerstattungsfrist ist 
abgelaufen</string>
     <string name="refund_intro">Bitte scannen Sie den QR-Code, um eine 
Rückerstattung zu erhalten</string>
     <string name="refund_order_ref">Bestellreferenz: %1$s\n\n%2$s</string>
-    <string name="error_network">Netzwerkfehler</string>
     <string name="toast_back_to_exit">Klicken Sie zum Beenden erneut auf 
«zurück»</string>
     <string name="app_name">Taler Merchant Kassenterminal</string>
     <string name="config_label">Händlereinstellungen</string>
diff --git a/merchant-terminal/src/main/res/values-fr/strings.xml 
b/merchant-terminal/src/main/res/values-fr/strings.xml
index bcc2a16..10c7af5 100644
--- a/merchant-terminal/src/main/res/values-fr/strings.xml
+++ b/merchant-terminal/src/main/res/values-fr/strings.xml
@@ -58,6 +58,5 @@
     <string name="refund_order_ref">Référence d\'achat : %1$s
 \n
 \n%2$s</string>
-    <string name="error_network">Erreur réseau</string>
     <string name="toast_back_to_exit">Cliquez à nouveau sur «retour» pour 
quitter</string>
 </resources>
\ No newline at end of file
diff --git a/merchant-terminal/src/main/res/values/strings.xml 
b/merchant-terminal/src/main/res/values/strings.xml
index f7a62da..bedc486 100644
--- a/merchant-terminal/src/main/res/values/strings.xml
+++ b/merchant-terminal/src/main/res/values/strings.xml
@@ -64,8 +64,8 @@
     <string name="refund_intro">Please let customer scan QR Code to offer 
refund</string>
     <string name="refund_order_ref">Purchase reference: %1$s\n\n%2$s</string>
 
-    <string name="error_network">Network error</string>
-    <string name="error_timeout">No payment found, please try again!</string>
+    <string name="error_payment">Error: No payment received</string>
+    <string name="error_timeout">No payment made within payment period, please 
try again!</string>
     <string name="error_cancelled">Payment cancelled</string>
 
     <string name="toast_back_to_exit">Click «back» again to exit</string>
diff --git a/taler-kotlin-android/build.gradle 
b/taler-kotlin-android/build.gradle
index 872b1cd..acd2dc7 100644
--- a/taler-kotlin-android/build.gradle
+++ b/taler-kotlin-android/build.gradle
@@ -47,6 +47,10 @@ android {
         }
     }
 
+    buildFeatures {
+        viewBinding = true
+    }
+
     packagingOptions {
         exclude("META-INF/*.kotlin_module")
     }
@@ -58,6 +62,7 @@ dependencies {
 
     implementation 'androidx.appcompat:appcompat:1.2.0'
     implementation 'androidx.core:core-ktx:1.3.1'
+    implementation 
"androidx.constraintlayout:constraintlayout:$constraintlayout_version"
 
     // Navigation
     implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
diff --git 
a/taler-kotlin-android/src/main/java/net/taler/common/AndroidUtils.kt 
b/taler-kotlin-android/src/main/java/net/taler/common/AndroidUtils.kt
index 72740df..093194f 100644
--- a/taler-kotlin-android/src/main/java/net/taler/common/AndroidUtils.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/common/AndroidUtils.kt
@@ -16,10 +16,10 @@
 
 package net.taler.common
 
+import android.content.ActivityNotFoundException
 import android.content.Context
 import android.content.Context.CONNECTIVITY_SERVICE
 import android.content.Intent
-import android.content.pm.PackageManager.MATCH_DEFAULT_ONLY
 import android.net.ConnectivityManager
 import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
 import android.os.Build.VERSION.SDK_INT
@@ -35,17 +35,20 @@ import android.text.format.DateUtils.FORMAT_SHOW_YEAR
 import android.text.format.DateUtils.MINUTE_IN_MILLIS
 import android.text.format.DateUtils.formatDateTime
 import android.text.format.DateUtils.getRelativeTimeSpanString
+import android.util.Log
 import android.view.View
 import android.view.View.INVISIBLE
 import android.view.View.VISIBLE
 import android.view.inputmethod.InputMethodManager
+import androidx.annotation.StringRes
 import androidx.core.content.ContextCompat.getSystemService
 import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
 import androidx.navigation.NavDirections
 import androidx.navigation.fragment.findNavController
 import com.github.pedrovgs.lynx.LynxActivity
 import com.github.pedrovgs.lynx.LynxConfig
-import com.github.pedrovgs.lynx.model.TraceLevel
+import net.taler.lib.android.ErrorBottomSheet
 import net.taler.lib.common.Version
 
 fun View.fadeIn(endAction: () -> Unit = {}) {
@@ -100,8 +103,20 @@ fun Context.showLogViewer() {
     startActivity(lynxActivityIntent)
 }
 
-fun Intent.isSafe(context: Context): Boolean {
-    return context.packageManager.queryIntentActivities(this, 
MATCH_DEFAULT_ONLY).isNotEmpty()
+fun FragmentActivity.showError(mainText: String, detailText: String = "") = 
ErrorBottomSheet
+        .newInstance(mainText, detailText)
+        .show(supportFragmentManager, "ERROR_BOTTOM_SHEET")
+
+fun FragmentActivity.showError(@StringRes mainId: Int, detailText: String = 
"") {
+    showError(getString(mainId), detailText)
+}
+
+fun Fragment.startActivitySafe(intent: Intent) {
+    try {
+        startActivity(intent)
+    } catch (e: ActivityNotFoundException) {
+        Log.e("taler-kotlin-android", "Error starting $intent", e)
+    }
 }
 
 fun Fragment.navigate(directions: NavDirections) = 
findNavController().navigate(directions)
diff --git 
a/taler-kotlin-android/src/main/java/net/taler/lib/android/ErrorBottomSheet.kt 
b/taler-kotlin-android/src/main/java/net/taler/lib/android/ErrorBottomSheet.kt
new file mode 100644
index 0000000..2815b64
--- /dev/null
+++ 
b/taler-kotlin-android/src/main/java/net/taler/lib/android/ErrorBottomSheet.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.lib.android
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import net.taler.common.R
+import net.taler.common.databinding.BottomsheetErrorBinding
+
+class ErrorBottomSheet : BottomSheetDialogFragment() {
+
+    companion object {
+        fun newInstance(mainText: String, detailText: String) = 
ErrorBottomSheet().apply {
+            arguments = Bundle().apply {
+                putString("TEXT_MAIN", mainText)
+                putString("TEXT_DETAIL", detailText)
+            }
+            setStyle(STYLE_NORMAL, R.style.ErrorBottomSheetTheme)
+        }
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        val ui = BottomsheetErrorBinding.inflate(inflater, container, false)
+        val args = requireArguments()
+        val mainText = args.getString("TEXT_MAIN")
+        val detailText = args.getString("TEXT_DETAIL")
+        ui.mainText.text = mainText
+        ui.closeButton.setOnClickListener { dismiss() }
+        ui.detailText.text = detailText
+        ui.shareButton.setOnClickListener {
+            val sendIntent: Intent = Intent().apply {
+                action = Intent.ACTION_SEND
+                putExtra(Intent.EXTRA_TEXT, "$mainText\n\n$detailText")
+                type = "text/plain"
+            }
+            val shareIntent = Intent.createChooser(sendIntent, null)
+            startActivity(shareIntent)
+        }
+        return ui.root
+    }
+
+}
diff --git a/anastasis-ui/src/main/res/drawable/ic_baseline_check.xml 
b/taler-kotlin-android/src/main/res/drawable/ic_close.xml
similarity index 69%
copy from anastasis-ui/src/main/res/drawable/ic_baseline_check.xml
copy to taler-kotlin-android/src/main/res/drawable/ic_close.xml
index 219e80e..d5d2297 100644
--- a/anastasis-ui/src/main/res/drawable/ic_baseline_check.xml
+++ b/taler-kotlin-android/src/main/res/drawable/ic_close.xml
@@ -6,5 +6,5 @@
     android:viewportHeight="24">
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" 
/>
+        android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 
5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
 </vector>
diff --git a/taler-kotlin-android/src/main/res/drawable/ic_share.xml 
b/taler-kotlin-android/src/main/res/drawable/ic_share.xml
new file mode 100644
index 0000000..59b0e84
--- /dev/null
+++ b/taler-kotlin-android/src/main/res/drawable/ic_share.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android";
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?attr/colorControlNormal"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18,16.08c-0.76,0 -1.44,0.3 
-1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 
-0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 
-3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 
6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 
2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 
2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
+</vector>
diff --git a/wallet/src/main/res/layout/fragment_review_exchange_tos.xml 
b/taler-kotlin-android/src/main/res/layout/bottomsheet_error.xml
similarity index 51%
copy from wallet/src/main/res/layout/fragment_review_exchange_tos.xml
copy to taler-kotlin-android/src/main/res/layout/bottomsheet_error.xml
index ec8d996..8d8e540 100644
--- a/wallet/src/main/res/layout/fragment_review_exchange_tos.xml
+++ b/taler-kotlin-android/src/main/res/layout/bottomsheet_error.xml
@@ -19,64 +19,66 @@
     xmlns:tools="http://schemas.android.com/tools";
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".withdraw.ReviewExchangeTosFragment">
+    tools:layout_height="500dp">
 
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/tosList"
+    <TextView
+        android:id="@+id/mainText"
         android:layout_width="0dp"
-        android:layout_height="0dp"
-        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
-        app:layout_constraintBottom_toTopOf="@+id/buttonCard"
-        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="16dp"
+        android:textColor="?android:attr/textColorPrimary"
+        app:layout_constrainedHeight="true"
+        app:layout_constraintBottom_toTopOf="@+id/guideline"
+        app:layout_constraintEnd_toStartOf="@+id/closeButton"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        tools:listitem="@layout/list_item_tos" />
+        tools:text="@tools:sample/lorem" />
 
-    <ProgressBar
-        android:id="@+id/progressBar"
-        style="?android:attr/progressBarStyleLarge"
+    <ImageButton
+        android:id="@+id/closeButton"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:background="?attr/selectableItemBackgroundBorderless"
+        android:contentDescription="@string/close"
+        android:src="@drawable/ic_close"
+        app:layout_constraintBottom_toTopOf="@+id/guideline"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.0" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/guideline"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        app:layout_constraintBottom_toBottomOf="@+id/tosList"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
+        android:orientation="horizontal"
+        app:layout_constraintGuide_begin="@dimen/bottom_sheet_peek_height" />
 
     <TextView
-        android:id="@+id/errorView"
+        android:id="@+id/detailText"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_margin="16dp"
-        android:gravity="center"
+        android:fontFamily="monospace"
+        android:minHeight="48dp"
         android:textColor="@color/red"
-        android:textSize="16sp"
-        android:visibility="invisible"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/shareButton"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        tools:text="@string/exchange_tos_error"
-        tools:visibility="visible" />
+        app:layout_constraintTop_toTopOf="@+id/guideline"
+        app:layout_constraintVertical_bias="0.0"
+        tools:text="@tools:sample/lorem/random" />
 
-    <com.google.android.material.card.MaterialCardView
-        android:id="@+id/buttonCard"
-        style="@style/BottomCard"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
+    <ImageButton
+        android:id="@+id/shareButton"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_margin="16dp"
+        android:background="?attr/selectableItemBackgroundBorderless"
+        android:contentDescription="@string/share"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent">
-
-        <CheckBox
-            android:id="@+id/acceptTosCheckBox"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
-            android:text="@string/exchange_tos_accept"
-            android:visibility="invisible"
-            tools:visibility="visible" />
-
-    </com.google.android.material.card.MaterialCardView>
+        app:layout_constraintTop_toTopOf="@+id/guideline"
+        app:layout_constraintVertical_bias="1.0"
+        app:srcCompat="@drawable/ic_share" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/wallet/src/nightly/res/values/strings.xml 
b/taler-kotlin-android/src/main/res/values/dimens.xml
similarity index 87%
copy from wallet/src/nightly/res/values/strings.xml
copy to taler-kotlin-android/src/main/res/values/dimens.xml
index 7276d52..03c413d 100644
--- a/wallet/src/nightly/res/values/strings.xml
+++ b/taler-kotlin-android/src/main/res/values/dimens.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ This file is part of GNU Taler
   ~ (C) 2020 Taler Systems S.A.
@@ -15,5 +16,5 @@
   -->
 
 <resources>
-    <string name="app_name">Taler Wallet Nightly</string>
+    <item name="bottom_sheet_peek_height" type="dimen">80dp</item>
 </resources>
diff --git a/taler-kotlin-android/src/main/res/values/strings.xml 
b/taler-kotlin-android/src/main/res/values/strings.xml
index a5b1df1..9903ada 100644
--- a/taler-kotlin-android/src/main/res/values/strings.xml
+++ b/taler-kotlin-android/src/main/res/values/strings.xml
@@ -18,4 +18,7 @@
     <string name="version_invalid">Invalid version. Please try again 
later!</string>
     <string name="version_too_old">App too old. Please upgrade!</string>
     <string name="version_too_new">Service outdated. Please wait until it gets 
upgraded.</string>
+
+    <string name="close">Close</string>
+    <string name="share">Share</string>
 </resources>
diff --git a/wallet/src/main/res/values/defaults.xml 
b/taler-kotlin-android/src/main/res/values/styles.xml
similarity index 67%
copy from wallet/src/main/res/values/defaults.xml
copy to taler-kotlin-android/src/main/res/values/styles.xml
index 0e2a6a1..af11cbd 100644
--- a/wallet/src/main/res/values/defaults.xml
+++ b/taler-kotlin-android/src/main/res/values/styles.xml
@@ -16,6 +16,12 @@
 
 <resources>
 
-    <bool name="settings_backup_default">true</bool>
+    <style name="ErrorBottomSheet" 
parent="Widget.MaterialComponents.BottomSheet.Modal">
+        <item name="behavior_peekHeight">@dimen/bottom_sheet_peek_height</item>
+    </style>
+
+    <style name="ErrorBottomSheetTheme" 
parent="Theme.MaterialComponents.BottomSheetDialog">
+        <item name="bottomSheetStyle">@style/ErrorBottomSheet</item>
+    </style>
 
 </resources>
\ No newline at end of file
diff --git a/wallet/.gitignore b/wallet/.gitignore
index 094515c..fa4dd35 100644
--- a/wallet/.gitignore
+++ b/wallet/.gitignore
@@ -1,2 +1,3 @@
 /build
+/.bundle
 /src/main/assets/taler-wallet-android-*.js
diff --git a/wallet/build.gradle b/wallet/build.gradle
index 0e04d17..cc0e411 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -46,7 +46,7 @@ android {
         applicationId "net.taler.wallet"
         minSdkVersion 24
         targetSdkVersion 29
-        versionCode 6
+        versionCode 8
         versionName "0.7.1.dev.28"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         buildConfigField "String", "WALLET_CORE_VERSION", 
"\"$walletCoreVersion\""
@@ -117,7 +117,7 @@ dependencies {
 
     // Lists and Selection
     implementation "androidx.recyclerview:recyclerview:1.1.0"
-    implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc01"
+    implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc02"
 
     // Navigation Library
     implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
diff --git a/wallet/fastlane/Fastfile b/wallet/fastlane/Fastfile
index 559acac..3c2f8cd 100644
--- a/wallet/fastlane/Fastfile
+++ b/wallet/fastlane/Fastfile
@@ -25,8 +25,25 @@ platform :android do
 
   desc "Deploy a new version to the Google Play beta track"
   lane :deploy do
-    gradle(task: "clean assembleRelease", gradle_path: '../gradlew')
-    upload_to_play_store(track: 'beta', skip_upload_images: 'true', 
skip_upload_screenshots: 'true', validate_only: 'true')
+    gradle(
+        task: "bundle",
+        build_type: "Release",
+        flavor: "google",
+        gradle_path: '../gradlew',
+        properties: {
+            "android.injected.signing.store.file" => 
ENV["TALER_KEYSTORE_PATH"],
+            "android.injected.signing.store.password" => 
ENV["TALER_KEYSTORE_PASS"],
+            "android.injected.signing.key.alias" => 
ENV["TALER_KEYSTORE_WALLET_ALIAS"],
+            "android.injected.signing.key.password" => 
ENV["TALER_KEYSTORE_WALLET_PASS"],
+        }
+    )
+    upload_to_play_store(
+        track: 'beta',
+        skip_upload_images: 'true',
+        skip_upload_screenshots: 'true',
+        skip_upload_apk: 'true', # This is an app bundle, so APK is not 
possible
+        validate_only: 'true'
+    )
   end
 end
 
diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt 
b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
index 0605976..1dafce0 100644
--- a/wallet/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
@@ -43,11 +43,11 @@ import androidx.preference.PreferenceFragmentCompat
 import 
androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
 import 
com.google.android.material.navigation.NavigationView.OnNavigationItemSelectedListener
 import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG
-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 net.taler.common.isOnline
+import net.taler.common.showError
 import net.taler.wallet.BuildConfig.VERSION_CODE
 import net.taler.wallet.BuildConfig.VERSION_NAME
 import net.taler.wallet.HostCardEmulatorService.Companion.HTTP_TUNNEL_RESPONSE
@@ -167,11 +167,7 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
                 model.refundManager.refund(url).observe(this, 
Observer(::onRefundResponse))
             }
             else -> {
-                Snackbar.make(
-                    ui.navView,
-                    "URL from $from doesn't contain a supported Taler Uri.",
-                    LENGTH_SHORT
-                ).show()
+                showError(R.string.error_unsupported_uri, "From: $from\nURI: 
$url")
             }
         }
     }
@@ -180,7 +176,7 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
         model.showProgressBar.value = false
         when (status) {
             is RefundStatus.Error -> {
-                Snackbar.make(ui.navView, R.string.refund_error, 
LENGTH_LONG).show()
+                showError(R.string.refund_error, status.msg)
             }
             is RefundStatus.Success -> {
                 val amount = status.response.amountRefundGranted
diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt 
b/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt
index 2476607..ab1ac80 100644
--- a/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt
+++ b/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt
@@ -73,13 +73,16 @@ data class TalerErrorInfo(
         get() {
             return StringBuilder().apply {
                 append(code)
+                hint?.let { append(" (").append(it).append(")") }
                 message?.let { append(" ").append(it) }
                 details?.let { details ->
-                    append("\n\n")
-                    details.optJSONObject("errorResponse")?.let { 
errorResponse ->
-                        append(errorResponse.optString("code")).append(" ")
-                        append(errorResponse.optString("hint"))
-                    } ?: append(details.toString(2))
+                    if (details.length() > 0) {
+                        append("\n\n")
+                        details.optJSONObject("errorResponse")?.let { 
errorResponse ->
+                            append(errorResponse.optString("code")).append(" ")
+                            append(errorResponse.optString("hint"))
+                        } ?: append(details.toString(2))
+                    }
                 }
             }.toString()
         }
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 e2f3ca1..e3b5dc2 100644
--- a/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt
@@ -33,8 +33,7 @@ import androidx.fragment.app.activityViewModels
 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 net.taler.common.showError
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 import net.taler.wallet.TAG
@@ -110,7 +109,7 @@ class PendingOperationsFragment : Fragment(), 
PendingOperationClickListener {
     }
 
     override fun onPendingOperationClick(type: String, detail: JSONObject) {
-        Snackbar.make(requireView(), "No detail view for $type implemented 
yet.", LENGTH_SHORT).show()
+        requireActivity().showError("No detail view for $type implemented 
yet.")
     }
 
     override fun onPendingOperationActionClick(type: String, detail: 
JSONObject) {
diff --git a/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt 
b/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
index 559b91d..9c292aa 100644
--- a/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
@@ -16,18 +16,16 @@
 
 package net.taler.wallet.refund
 
-import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import kotlinx.coroutines.CoroutineScope
 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
 
 sealed class RefundStatus {
-    object Error : RefundStatus()
+    data class Error(val msg: String) : RefundStatus()
     data class Success(val response: RefundResponse) : RefundStatus()
 }
 
@@ -50,11 +48,8 @@ class RefundManager(
             api.request("applyRefund", RefundResponse.serializer()) {
                 put("talerRefundUri", refundUri)
             }.onError {
-                Log.e(TAG, "Refund Error: $it")
-                // TODO show error string
-                liveData.postValue(RefundStatus.Error)
+                liveData.postValue(RefundStatus.Error(it.userFacingMsg))
             }.onSuccess {
-                Log.e(TAG, "Refund Success: $it")
                 liveData.postValue(RefundStatus.Success(it))
             }
         }
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 302e684..866b363 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -25,7 +25,7 @@ import android.view.MenuItem
 import android.widget.TextView
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import net.taler.common.isSafe
+import net.taler.common.startActivitySafe
 import net.taler.lib.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
@@ -80,9 +80,7 @@ abstract class TransactionDetailFragment : Fragment() {
             val i = Intent().apply {
                 data = Uri.parse(info.fulfillmentUrl)
             }
-            if (i.isSafe(requireContext())) {
-                orderSummaryView.setOnClickListener { startActivity(i) }
-            }
+            orderSummaryView.setOnClickListener { startActivitySafe(i) }
         }
         orderIdView.text = getString(R.string.transaction_order_id, 
info.orderId)
     }
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
index 26965ef..96782fd 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
@@ -22,7 +22,7 @@ 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.startActivitySafe
 import net.taler.common.toAbsoluteTime
 import net.taler.wallet.R
 import net.taler.wallet.cleanExchange
@@ -53,9 +53,7 @@ class TransactionWithdrawalFragment : 
TransactionDetailFragment() {
             val i = Intent().apply {
                 data = Uri.parse(t.withdrawalDetails.bankConfirmationUrl)
             }
-            if (i.isSafe(requireContext())) {
-                ui.confirmWithdrawalButton.setOnClickListener { 
startActivity(i) }
-            }
+            ui.confirmWithdrawalButton.setOnClickListener { 
startActivitySafe(i) }
         } else ui.confirmWithdrawalButton.visibility = View.GONE
         ui.chosenAmountLabel.text = getString(R.string.amount_chosen)
         ui.chosenAmountView.text =
diff --git a/wallet/src/main/res/drawable/ic_add_circle.xml 
b/wallet/src/main/res/drawable/ic_add_circle.xml
deleted file mode 100644
index 4144735..0000000
--- a/wallet/src/main/res/drawable/ic_add_circle.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-  ~ 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/>
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android";
-    android:width="24dp"
-    android:height="24dp"
-    android:tint="?attr/colorControlNormal"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 
10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,13v-2h4L11,7h2v4h4v2z" />
-</vector>
diff --git a/wallet/src/main/res/values-fr/strings.xml 
b/wallet/src/main/res/values-fr/strings.xml
index 3a54659..e13a912 100644
--- a/wallet/src/main/res/values-fr/strings.xml
+++ b/wallet/src/main/res/values-fr/strings.xml
@@ -50,7 +50,6 @@
     <string name="button_back">Retour</string>
     <string name="payment_label_order_summary">Achat</string>
     <string name="payment_balance_insufficient">Solde insuffisant !</string>
-    <string name="payment_hide_details">Masquer les détails</string>
     <string name="payment_already_paid_title">Déjà payé</string>
     <string name="payment_already_paid">Vous avez déjà payé cet achat.</string>
     <string name="withdraw_total">Retrait</string>
@@ -84,6 +83,5 @@
     <string name="payment_error">Erreur : %s</string>
     <string name="google_play_full_desc" 
tools:keep="@string/google_play_full_desc">Cette application est un 
portefeuille pour GNU Taler. Elle est très expérimentale et n\'est pas encore 
prête à être utilisée en production. GNU Taler est un système de paiement 
préservant la vie privée. Les clients peuvent rester anonymes, mais les 
commerçants ne peuvent pas cacher leurs revenus par des paiements avec GNU 
Taler. Cela permet d\'éviter l\'évasion fiscale et le blanchiment d\'argent. Le 
prin [...]
     <string name="payment_label_amount_total">Montant total :</string>
-    <string name="payment_show_details">Afficher les détails</string>
     <string name="exchange_fee_coin_expiration_label">Expiration de la pièce 
au plus tôt :</string>
 </resources>
\ No newline at end of file
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index b419766..24db2b0 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -55,6 +55,7 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <string name="or">or</string>
 
     <string name="offline">Operation requires internet access. Please ensure 
your internet connection works and try again.</string>
+    <string name="error_unsupported_uri">Error: This Taler URI is not 
supported.</string>
 
     <string name="menu_settings">Settings</string>
     <string name="menu_retry_pending_operations">Retry Pending 
Operations</string>
@@ -96,8 +97,6 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <string name="payment_label_order_summary">Purchase</string>
     <string name="payment_error">Error: %s</string>
     <string name="payment_balance_insufficient">Balance insufficient!</string>
-    <string name="payment_show_details">Show Details</string>
-    <string name="payment_hide_details">Hide Details</string>
     <string name="payment_aborted">Aborted</string>
     <string name="payment_failed">Failed</string>
     <string name="payment_initiated">Payment initiated</string>

-- 
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]