taler-android

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

commit a9b2ec4f35851c26bbe4f62a2e7fa17d9ee79576
parent 059f240efaa6330c7222ba30b01cb32362bad4a3
Author: Torsten Grote <t@grobox.de>
Date:   Thu, 11 Jun 2020 15:40:29 -0300

[wallet] UI mockup for backup and anastasis

Diffstat:
M.idea/dictionaries/user.xml | 1+
Mbuild.gradle | 1+
Mwallet/src/main/java/net/taler/wallet/MainActivity.kt | 17++++++++++++++++-
Mwallet/src/main/java/net/taler/wallet/MainViewModel.kt | 10++++++++++
Dwallet/src/main/java/net/taler/wallet/SettingsFragment.kt | 114-------------------------------------------------------------------------------
Awallet/src/main/java/net/taler/wallet/settings/AnastasisAuthenticationFragment.kt | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awallet/src/main/java/net/taler/wallet/settings/AnastasisIdentityFragment.kt | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awallet/src/main/java/net/taler/wallet/settings/AnastasisIntroFragment.kt | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Awallet/src/main/java/net/taler/wallet/settings/BackupSettingsFragment.kt | 41+++++++++++++++++++++++++++++++++++++++++
Awallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awallet/src/main/res/anim/slide_in_right.xml | 23+++++++++++++++++++++++
Awallet/src/main/res/anim/slide_out_left.xml | 23+++++++++++++++++++++++
Awallet/src/main/res/drawable/ic_baseline_account_tree.xml | 10++++++++++
Awallet/src/main/res/drawable/ic_baseline_backup.xml | 10++++++++++
Awallet/src/main/res/drawable/ic_baseline_check.xml | 10++++++++++
Awallet/src/main/res/drawable/ic_baseline_cloud_circle.xml | 10++++++++++
Awallet/src/main/res/drawable/ic_baseline_cloud_download.xml | 10++++++++++
Awallet/src/main/res/drawable/ic_baseline_lock.xml | 10++++++++++
Awallet/src/main/res/drawable/ic_baseline_person.xml | 10++++++++++
Awallet/src/main/res/drawable/ic_baseline_vpn_key.xml | 10++++++++++
Awallet/src/main/res/layout/fragment_anastasis_authentication.xml | 272+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awallet/src/main/res/layout/fragment_anastasis_identity.xml | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awallet/src/main/res/layout/fragment_anastasis_intro.xml | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwallet/src/main/res/navigation/nav_graph.xml | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++--
Awallet/src/main/res/values/defaults.xml | 22++++++++++++++++++++++
Mwallet/src/main/res/values/strings.xml | 3+++
Awallet/src/main/res/xml/settings_backup.xml | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwallet/src/main/res/xml/settings_main.xml | 8++++++++
28 files changed, 1189 insertions(+), 117 deletions(-)

diff --git a/.idea/dictionaries/user.xml b/.idea/dictionaries/user.xml @@ -4,6 +4,7 @@ <w>abcdef</w> <w>aiddescription</w> <w>akono</w> + <w>anastasis</w> <w>apdu</w> <w>markwon</w> <w>servicedesc</w> diff --git a/build.gradle b/build.gradle @@ -1,6 +1,7 @@ buildscript { ext.kotlin_version = '1.3.72' ext.nav_version = "2.2.2" + // check https://android-rebuilds.beuc.net/ for availability of free build tools ext.build_tools_version = "29.0.2" repositories { google() diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/MainActivity.kt @@ -37,6 +37,9 @@ import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.setupWithNavController +import androidx.preference.Preference +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 @@ -54,7 +57,8 @@ import net.taler.wallet.HostCardEmulatorService.Companion.TRIGGER_PAYMENT_ACTION import net.taler.wallet.refund.RefundStatus import java.util.Locale.ROOT -class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener { +class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, + OnPreferenceStartFragmentCallback { private val model: MainViewModel by viewModels() @@ -206,4 +210,15 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener { } } + override fun onPreferenceStartFragment( + caller: PreferenceFragmentCompat, + pref: Preference + ): Boolean { + when (pref.key) { + "pref_backup" -> nav.navigate(R.id.action_nav_settings_to_nav_settings_backup) + "pref_backup_recovery" -> nav.navigate(R.id.action_nav_settings_backup_to_nav_anastasis_intro) + } + return true + } + } diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt @@ -40,6 +40,9 @@ import net.taler.wallet.refund.RefundManager import net.taler.wallet.transactions.TransactionManager import net.taler.wallet.withdraw.WithdrawManager import org.json.JSONObject +import java.util.concurrent.TimeUnit.DAYS +import java.util.concurrent.TimeUnit.MINUTES +import kotlin.random.Random const val TAG = "taler-wallet" @@ -103,6 +106,13 @@ class MainViewModel(val app: Application) : AndroidViewModel(app) { private val mTransactionsEvent = MutableLiveData<Event<String>>() val transactionsEvent: LiveData<Event<String>> = mTransactionsEvent + private val mLastBackup = MutableLiveData( + // fake backup time until we actually do backup + System.currentTimeMillis() - + Random.nextLong(MINUTES.toMillis(5), DAYS.toMillis(2)) + ) + val lastBackup: LiveData<Long> = mLastBackup + override fun onCleared() { walletBackendApi.destroy() super.onCleared() diff --git a/wallet/src/main/java/net/taler/wallet/SettingsFragment.kt b/wallet/src/main/java/net/taler/wallet/SettingsFragment.kt @@ -1,114 +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.wallet - -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 -import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_SHORT -import com.google.android.material.snackbar.Snackbar -import net.taler.wallet.BuildConfig.VERSION_CODE -import net.taler.wallet.BuildConfig.VERSION_NAME -import net.taler.wallet.BuildConfig.WALLET_CORE_VERSION - - -class SettingsFragment : PreferenceFragmentCompat() { - - private val model: MainViewModel by activityViewModels() - private val withdrawManager by lazy { model.withdrawManager } - - private lateinit var prefDevMode: SwitchPreferenceCompat - private lateinit var prefWithdrawTest: Preference - private lateinit var prefVersionApp: Preference - private lateinit var prefVersionCore: Preference - private lateinit var prefVersionExchange: Preference - private lateinit var prefVersionMerchant: Preference - private lateinit var prefReset: Preference - private val devPrefs by lazy { - listOf( - prefWithdrawTest, - prefVersionApp, - prefVersionCore, - prefVersionExchange, - prefVersionMerchant, - prefReset - ) - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.settings_main, rootKey) - prefDevMode = findPreference("pref_dev_mode")!! - prefWithdrawTest = findPreference("pref_testkudos")!! - prefVersionApp = findPreference("pref_version_app")!! - prefVersionCore = findPreference("pref_version_core")!! - prefVersionExchange = findPreference("pref_version_protocol_exchange")!! - prefVersionMerchant = findPreference("pref_version_protocol_merchant")!! - prefReset = findPreference("pref_reset")!! - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - model.devMode.observe(viewLifecycleOwner, Observer { enabled -> - prefDevMode.isChecked = enabled - if (enabled) { - prefVersionApp.summary = "$VERSION_NAME ($VERSION_CODE)" - prefVersionCore.summary = WALLET_CORE_VERSION - model.exchangeVersion?.let { prefVersionExchange.summary = it } - model.merchantVersion?.let { prefVersionMerchant.summary = it } - } - devPrefs.forEach { it.isVisible = enabled } - }) - prefDevMode.setOnPreferenceChangeListener { _, newValue -> - model.devMode.value = newValue as Boolean - true - } - - withdrawManager.testWithdrawalInProgress.observe(viewLifecycleOwner, Observer { loading -> - prefWithdrawTest.isEnabled = !loading - model.showProgressBar.value = loading - }) - prefWithdrawTest.setOnPreferenceClickListener { - withdrawManager.withdrawTestkudos() - true - } - - prefReset.setOnPreferenceClickListener { - showResetDialog() - true - } - } - - private fun showResetDialog() { - AlertDialog.Builder(requireContext()) - .setMessage("Do you really want to reset the wallet and lose all coins and purchases?") - .setPositiveButton("Reset") { _, _ -> - model.dangerouslyReset() - Snackbar.make(requireView(), "Wallet has been reset", LENGTH_SHORT).show() - } - .setNegativeButton("Cancel") { _, _ -> - Snackbar.make(requireView(), "Reset cancelled", LENGTH_SHORT).show() - } - .show() - } - -} diff --git a/wallet/src/main/java/net/taler/wallet/settings/AnastasisAuthenticationFragment.kt b/wallet/src/main/java/net/taler/wallet/settings/AnastasisAuthenticationFragment.kt @@ -0,0 +1,91 @@ +/* + * 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.settings + +import android.os.Bundle +import android.view.Gravity.CENTER +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import android.widget.Toast.LENGTH_SHORT +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import com.google.android.material.card.MaterialCardView +import kotlinx.android.synthetic.main.fragment_anastasis_authentication.* +import net.taler.common.Amount +import net.taler.wallet.MainViewModel +import net.taler.wallet.R + + +class AnastasisAuthenticationFragment : Fragment() { + + private val model: MainViewModel by activityViewModels() + + private var price: Amount = Amount.zero("KUDOS") + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_anastasis_authentication, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + passwordCard.setOnClickListener { + toggleCard( + passwordCard, + Amount.fromJSONString("KUDOS:0.5") + ) + } + postidentCard.setOnClickListener { + toggleCard( + postidentCard, + Amount.fromJSONString("KUDOS:3.5") + ) + } + smsCard.setOnClickListener { toggleCard(smsCard, Amount.fromJSONString("KUDOS:1.0")) } + videoCard.setOnClickListener { toggleCard(videoCard, Amount.fromJSONString("KUDOS:2.25")) } + } + + private fun toggleCard(card: MaterialCardView, price: Amount) { + card.isChecked = !card.isChecked + val text = "Imagine you entered information here" + if (card.isChecked) Toast.makeText(requireContext(), text, LENGTH_SHORT).apply { + setGravity(CENTER, 0, 0) + }.show() + updatePrice(card.isChecked, price) + updateNextButtonState() + } + + private fun updatePrice(add: Boolean, amount: Amount) { + if (add) price += amount + else price -= amount + recoveryCostView.text = "Recovery cost: $price" + } + + private fun updateNextButtonState() { + var numChecked = 0 + numChecked += if (passwordCard.isChecked) 1 else 0 + numChecked += if (postidentCard.isChecked) 1 else 0 + numChecked += if (smsCard.isChecked) 1 else 0 + numChecked += if (videoCard.isChecked) 1 else 0 + nextAuthButton.isEnabled = numChecked >= 2 + } + +} diff --git a/wallet/src/main/java/net/taler/wallet/settings/AnastasisIdentityFragment.kt b/wallet/src/main/java/net/taler/wallet/settings/AnastasisIdentityFragment.kt @@ -0,0 +1,86 @@ +/* + * 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.settings + +import android.annotation.SuppressLint +import android.app.DatePickerDialog +import android.os.Bundle +import android.telephony.TelephonyManager +import android.text.format.DateFormat.getDateFormat +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController +import com.google.android.material.snackbar.Snackbar +import kotlinx.android.synthetic.main.fragment_anastasis_identity.* +import net.taler.wallet.MainViewModel +import net.taler.wallet.R +import java.util.* + +class AnastasisIdentityFragment : Fragment() { + + private val model: MainViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_anastasis_identity, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + countryView.text = getCountryName() + changeCountryView.setOnClickListener { + Snackbar.make(view, "Not implemented", Snackbar.LENGTH_SHORT).show() + } + birthDateInput.editText?.setOnClickListener { + val picker = DatePickerDialog(requireContext()) + picker.setOnDateSetListener { _, year, month, dayOfMonth -> + val calender = Calendar.getInstance().apply { + set(year, month, dayOfMonth) + } + val date = Date(calender.timeInMillis) + val dateStr = getDateFormat(requireContext()).format(date) + birthDateInput.editText?.setText(dateStr) + } + picker.show() + } + createIdentifierButton.setOnClickListener { + findNavController().navigate(R.id.action_nav_anastasis_intro_to_nav_anastasis_authentication) + } + } + + private fun getCountryName(): String { + val tm = requireContext().getSystemService(TelephonyManager::class.java)!! + val countryIso = if (tm.networkCountryIso.isNullOrEmpty()) + tm.simCountryIso else tm.networkCountryIso + var countryName = "Unknown" + for (locale in Locale.getAvailableLocales()) { + @SuppressLint("DefaultLocale") + if (locale.country.toLowerCase() == countryIso) { + countryName = locale.displayCountry + break + } + } + return countryName + } + +} diff --git a/wallet/src/main/java/net/taler/wallet/settings/AnastasisIntroFragment.kt b/wallet/src/main/java/net/taler/wallet/settings/AnastasisIntroFragment.kt @@ -0,0 +1,51 @@ +/* + * 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.settings + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +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_anastasis_intro.* +import net.taler.wallet.MainViewModel +import net.taler.wallet.R + + +class AnastasisIntroFragment : Fragment() { + + private val model: MainViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_anastasis_intro, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + button.setOnClickListener { + findNavController().navigate(R.id.action_nav_anastasis_intro_to_nav_anastasis_identity) + } + } + + +} diff --git a/wallet/src/main/java/net/taler/wallet/settings/BackupSettingsFragment.kt b/wallet/src/main/java/net/taler/wallet/settings/BackupSettingsFragment.kt @@ -0,0 +1,41 @@ +/* + * 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.settings + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.activityViewModels +import androidx.preference.PreferenceFragmentCompat +import net.taler.wallet.MainViewModel +import net.taler.wallet.R + + +class BackupSettingsFragment : PreferenceFragmentCompat() { + + private val model: MainViewModel by activityViewModels() + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.settings_backup, rootKey) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + } + + +} diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt b/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt @@ -0,0 +1,125 @@ +/* + * 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.settings + +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 +import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_SHORT +import com.google.android.material.snackbar.Snackbar +import net.taler.common.toRelativeTime +import net.taler.wallet.BuildConfig.VERSION_CODE +import net.taler.wallet.BuildConfig.VERSION_NAME +import net.taler.wallet.BuildConfig.WALLET_CORE_VERSION +import net.taler.wallet.MainViewModel +import net.taler.wallet.R + + +class SettingsFragment : PreferenceFragmentCompat() { + + private val model: MainViewModel by activityViewModels() + private val withdrawManager by lazy { model.withdrawManager } + + private lateinit var prefBackup: Preference + private lateinit var prefDevMode: SwitchPreferenceCompat + private lateinit var prefWithdrawTest: Preference + private lateinit var prefVersionApp: Preference + private lateinit var prefVersionCore: Preference + private lateinit var prefVersionExchange: Preference + private lateinit var prefVersionMerchant: Preference + private lateinit var prefReset: Preference + private val devPrefs by lazy { + listOf( + prefBackup, + prefWithdrawTest, + prefVersionApp, + prefVersionCore, + prefVersionExchange, + prefVersionMerchant, + prefReset + ) + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.settings_main, rootKey) + prefBackup = findPreference("pref_backup")!! + prefDevMode = findPreference("pref_dev_mode")!! + prefWithdrawTest = findPreference("pref_testkudos")!! + prefVersionApp = findPreference("pref_version_app")!! + prefVersionCore = findPreference("pref_version_core")!! + prefVersionExchange = findPreference("pref_version_protocol_exchange")!! + prefVersionMerchant = findPreference("pref_version_protocol_merchant")!! + prefReset = findPreference("pref_reset")!! + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + model.lastBackup.observe(viewLifecycleOwner, Observer { + val time = it.toRelativeTime(requireContext()) + prefBackup.summary = getString(R.string.backup_last, time) + }) + + model.devMode.observe(viewLifecycleOwner, Observer { enabled -> + prefDevMode.isChecked = enabled + if (enabled) { + prefVersionApp.summary = "$VERSION_NAME ($VERSION_CODE)" + prefVersionCore.summary = WALLET_CORE_VERSION + model.exchangeVersion?.let { prefVersionExchange.summary = it } + model.merchantVersion?.let { prefVersionMerchant.summary = it } + } + devPrefs.forEach { it.isVisible = enabled } + }) + prefDevMode.setOnPreferenceChangeListener { _, newValue -> + model.devMode.value = newValue as Boolean + true + } + + withdrawManager.testWithdrawalInProgress.observe(viewLifecycleOwner, Observer { loading -> + prefWithdrawTest.isEnabled = !loading + model.showProgressBar.value = loading + }) + prefWithdrawTest.setOnPreferenceClickListener { + withdrawManager.withdrawTestkudos() + true + } + + prefReset.setOnPreferenceClickListener { + showResetDialog() + true + } + } + + private fun showResetDialog() { + AlertDialog.Builder(requireContext()) + .setMessage("Do you really want to reset the wallet and lose all coins and purchases?") + .setPositiveButton("Reset") { _, _ -> + model.dangerouslyReset() + Snackbar.make(requireView(), "Wallet has been reset", LENGTH_SHORT).show() + } + .setNegativeButton("Cancel") { _, _ -> + Snackbar.make(requireView(), "Reset cancelled", LENGTH_SHORT).show() + } + .show() + } + +} diff --git a/wallet/src/main/res/anim/slide_in_right.xml b/wallet/src/main/res/anim/slide_in_right.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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/> + --> + +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <translate android:fromXDelta="75%p" android:toXDelta="0" + android:duration="@android:integer/config_mediumAnimTime"/> + <alpha android:fromAlpha="0.0" android:toAlpha="1.0" + android:duration="@android:integer/config_mediumAnimTime" /> +</set> diff --git a/wallet/src/main/res/anim/slide_out_left.xml b/wallet/src/main/res/anim/slide_out_left.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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/> + --> + +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <translate android:fromXDelta="0" android:toXDelta="-75%p" + android:duration="@android:integer/config_mediumAnimTime"/> + <alpha android:fromAlpha="1.0" android:toAlpha="0.0" + android:duration="@android:integer/config_mediumAnimTime" /> +</set> diff --git a/wallet/src/main/res/drawable/ic_baseline_account_tree.xml b/wallet/src/main/res/drawable/ic_baseline_account_tree.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="M22,11V3h-7v3H9V3H2v8h7V8h2v10h4v3h7v-8h-7v3h-2V8h2v3z" /> +</vector> diff --git a/wallet/src/main/res/drawable/ic_baseline_backup.xml b/wallet/src/main/res/drawable/ic_baseline_backup.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="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z" /> +</vector> diff --git a/wallet/src/main/res/drawable/ic_baseline_check.xml b/wallet/src/main/res/drawable/ic_baseline_check.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="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" /> +</vector> diff --git a/wallet/src/main/res/drawable/ic_baseline_cloud_circle.xml b/wallet/src/main/res/drawable/ic_baseline_cloud_circle.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="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM16.5,16L8,16c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3l0.14,0.01C8.58,8.28 10.13,7 12,7c2.21,0 4,1.79 4,4h0.5c1.38,0 2.5,1.12 2.5,2.5S17.88,16 16.5,16z" /> +</vector> diff --git a/wallet/src/main/res/drawable/ic_baseline_cloud_download.xml b/wallet/src/main/res/drawable/ic_baseline_cloud_download.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="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-5,5 -5,-5h3V9h4v4h3z" /> +</vector> diff --git a/wallet/src/main/res/drawable/ic_baseline_lock.xml b/wallet/src/main/res/drawable/ic_baseline_lock.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,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" /> +</vector> diff --git a/wallet/src/main/res/drawable/ic_baseline_person.xml b/wallet/src/main/res/drawable/ic_baseline_person.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="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" /> +</vector> diff --git a/wallet/src/main/res/drawable/ic_baseline_vpn_key.xml b/wallet/src/main/res/drawable/ic_baseline_vpn_key.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="M12.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z" /> +</vector> diff --git a/wallet/src/main/res/layout/fragment_anastasis_authentication.xml b/wallet/src/main/res/layout/fragment_anastasis_authentication.xml @@ -0,0 +1,272 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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/> + --> + +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@+id/bottomCard" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <com.google.android.material.card.MaterialCardView + android:id="@+id/passwordCard" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="16dp" + android:checkable="true" + android:clickable="true" + android:focusable="true" + app:cardElevation="4dp" + app:cardUseCompatPadding="true" + app:checkedIcon="@drawable/ic_baseline_check" + app:checkedIconTint="@color/green" + app:contentPadding="8dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/passwordHeadline" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:text="Password" + android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/passwordText" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="Provide your own password that you will need to enter to authenticate when recovering your backup." + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/passwordHeadline" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + </com.google.android.material.card.MaterialCardView> + + <com.google.android.material.circularreveal.cardview.CircularRevealCardView + android:id="@+id/postidentCard" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="16dp" + android:checkable="true" + app:cardElevation="4dp" + app:cardUseCompatPadding="true" + app:checkedIcon="@drawable/ic_baseline_check" + app:checkedIconTint="@color/green" + app:contentPadding="8dp"> + + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/postidentHeadline" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:text="Postident Verfahren" + android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/postidentText" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="Die Postident-Verfahren sind Methoden der persönlichen Identifikation von Personen, die durch die Mitarbeiter der Deutschen Post AG vorgenommen werden. Man spricht beim Postident-Verfahren auch von einer unpersönlichen Legitimationsprüfung. " + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/postidentHeadline" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </com.google.android.material.circularreveal.cardview.CircularRevealCardView> + + + <com.google.android.material.card.MaterialCardView + android:id="@+id/smsCard" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="16dp" + android:checkable="true" + android:clickable="true" + android:focusable="true" + app:cardElevation="4dp" + app:cardUseCompatPadding="true" + app:checkedIcon="@drawable/ic_baseline_check" + app:checkedIconTint="@color/green" + app:contentPadding="8dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/smsHeadline" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:text="SMS" + android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/smsText" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="Sends an SMS with a code to the users phone. The must send this code back with his request. If the transmitted code is correct, the server responses with the requested encrypted key share." + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/smsHeadline" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + </com.google.android.material.card.MaterialCardView> + + <com.google.android.material.card.MaterialCardView + android:id="@+id/videoCard" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:checkable="true" + android:clickable="true" + android:focusable="true" + app:cardElevation="4dp" + app:cardUseCompatPadding="true" + app:checkedIcon="@drawable/ic_baseline_check" + app:checkedIconTint="@color/green" + app:contentPadding="8dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/videoHeadline" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:text="Video identification" + android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/videoText" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="Requires the user to identify via video-call. The user is expected to delete all metadata revealing information about him/her from the images before uploading them. Since the respective images must be passed on to the video identification service in the event of password recovery, it must be ensured that no further information about the user can be derived from them." + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/videoHeadline" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + </com.google.android.material.card.MaterialCardView> + + </LinearLayout> + + </ScrollView> + + <com.google.android.material.card.MaterialCardView + android:id="@+id/bottomCard" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:cardCornerRadius="0dp" + app:cardElevation="6dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Button + android:id="@+id/nextAuthButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:backgroundTint="@color/green" + android:enabled="false" + android:text="Next" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/annualCostView" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="8dp" + android:layout_marginBottom="8dp" + android:text="Annual cost: 5 KUDOS" + app:layout_constraintBottom_toTopOf="@+id/recoveryCostView" + app:layout_constraintEnd_toStartOf="@+id/nextAuthButton" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="spread" /> + + <TextView + android:id="@+id/recoveryCostView" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginEnd="8dp" + android:layout_marginBottom="8dp" + android:text="Recovery cost: 0 KUDOS" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@+id/nextAuthButton" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/annualCostView" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + </com.google.android.material.card.MaterialCardView> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/wallet/src/main/res/layout/fragment_anastasis_identity.xml b/wallet/src/main/res/layout/fragment_anastasis_identity.xml @@ -0,0 +1,165 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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/> + --> + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/imageView2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_baseline_person" /> + + <TextView + android:id="@+id/identityIntro" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:layout_marginTop="24dp" + android:text="To find your secret later, we create an anonymous identifier from unforgettable information about you.\n\nFeel free to lie as long as you will be able to provide exactly the same information when needing to restore." + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/imageView2" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/textView3" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:text="Detected Country:" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/identityIntro" /> + + <TextView + android:id="@+id/countryView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:text="Unknown" + app:layout_constraintBaseline_toBaselineOf="@+id/textView3" + app:layout_constraintStart_toEndOf="@+id/textView3" /> + + <TextView + android:id="@+id/changeCountryView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:text="Change" + android:textColor="@color/colorAccent" + app:layout_constraintBaseline_toBaselineOf="@+id/countryView" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toEndOf="@+id/countryView" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/nameInput" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="16dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textView3"> + + <com.google.android.material.textfield.TextInputEditText + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="Name" /> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/placeOfBirthInput" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="16dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/nameInput"> + + <com.google.android.material.textfield.TextInputEditText + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="Place of birth" /> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/birthDateInput" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="16dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/placeOfBirthInput"> + + <com.google.android.material.textfield.TextInputEditText + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:focusable="false" + android:hint="Birthday" + android:inputType="date" /> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/idNumberInput" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="16dp" + app:layout_constraintBottom_toTopOf="@+id/createIdentifierButton" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/birthDateInput" + app:layout_constraintVertical_bias="0.0"> + + <com.google.android.material.textfield.TextInputEditText + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="AHV number" + android:inputType="number" + android:maxLength="13" /> + + </com.google.android.material.textfield.TextInputLayout> + + <Button + android:id="@+id/createIdentifierButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:backgroundTint="@color/green" + android:drawableLeft="@drawable/ic_baseline_lock" + android:drawableTint="?attr/colorOnPrimarySurface" + android:text="Encrypt Identity" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</ScrollView> diff --git a/wallet/src/main/res/layout/fragment_anastasis_intro.xml b/wallet/src/main/res/layout/fragment_anastasis_intro.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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/> + --> + +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:id="@+id/imageView" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_margin="16dp" + android:tint="@color/green" + app:layout_constraintBottom_toTopOf="@+id/textView" + app:layout_constraintDimensionRatio="1:1" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHeight_max="200dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="1.0" + app:layout_constraintVertical_chainStyle="spread" + app:srcCompat="@drawable/ic_baseline_cloud_circle" /> + + <TextView + android:id="@+id/textView" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:text="Secure cloud recovery keeps your backup secret safe with service providers of your choice.\n\nTo access your backup, you need to identify yourself to some or all of those providers, so they unlock your backup." + android:textSize="22sp" + app:layout_constraintBottom_toTopOf="@+id/button" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/imageView" /> + + <Button + android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:backgroundTint="@color/green" + android:text="Setup cloud recovery" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/wallet/src/main/res/navigation/nav_graph.xml b/wallet/src/main/res/navigation/nav_graph.xml @@ -56,8 +56,59 @@ <fragment android:id="@+id/nav_settings" - android:name="net.taler.wallet.SettingsFragment" - android:label="@string/menu_settings" /> + android:name="net.taler.wallet.settings.SettingsFragment" + android:label="@string/menu_settings"> + <action + android:id="@+id/action_nav_settings_to_nav_settings_backup" + app:destination="@id/nav_settings_backup" /> + </fragment> + + <fragment + android:id="@+id/nav_settings_backup" + android:name="net.taler.wallet.settings.BackupSettingsFragment" + android:label="@string/nav_settings_backup"> + <action + android:id="@+id/action_nav_settings_backup_to_nav_anastasis_intro" + app:destination="@id/nav_anastasis_intro" + app:enterAnim="@anim/slide_in_right" + app:exitAnim="@anim/slide_out_left" + app:popEnterAnim="@android:anim/slide_in_left" + app:popExitAnim="@android:anim/slide_out_right" /> + </fragment> + + <fragment + android:id="@+id/nav_anastasis_intro" + android:name="net.taler.wallet.settings.AnastasisIntroFragment" + android:label="Secure Cloud Recovery" + tools:layout="@layout/fragment_anastasis_intro"> + <action + android:id="@+id/action_nav_anastasis_intro_to_nav_anastasis_identity" + app:destination="@id/nav_anastasis_identity" + app:enterAnim="@anim/slide_in_right" + app:exitAnim="@anim/slide_out_left" + app:popEnterAnim="@android:anim/slide_in_left" + app:popExitAnim="@android:anim/slide_out_right" /> + </fragment> + + <fragment + android:id="@+id/nav_anastasis_identity" + android:name="net.taler.wallet.settings.AnastasisIdentityFragment" + android:label="Define your identity" + tools:layout="@layout/fragment_anastasis_identity"> + <action + android:id="@+id/action_nav_anastasis_intro_to_nav_anastasis_authentication" + app:destination="@id/nav_anastasis_authentication" + app:enterAnim="@anim/slide_in_right" + app:exitAnim="@anim/slide_out_left" + app:popEnterAnim="@android:anim/slide_in_left" + app:popExitAnim="@android:anim/slide_out_right" /> + </fragment> + + <fragment + android:id="@+id/nav_anastasis_authentication" + android:name="net.taler.wallet.settings.AnastasisAuthenticationFragment" + android:label="Choose authentication methods" + tools:layout="@layout/fragment_anastasis_authentication"/> <fragment android:id="@+id/nav_transactions" diff --git a/wallet/src/main/res/values/defaults.xml b/wallet/src/main/res/values/defaults.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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/> + --> + +<resources> + + <bool name="settings_backup_default">true</bool> + +</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 @@ -147,6 +147,9 @@ GNU Taler is immune against many types of fraud, such as phishing of credit card <string name="settings_reset">Reset Wallet (dangerous!)</string> <string name="settings_reset_summary">Throws away your money</string> + <string name="nav_settings_backup">Backup</string> + <string name="backup_last">Last Backup: %s</string> + <string name="refund_title">Refund</string> <string name="refund_error">Error processing refund</string> <string name="refund_success">Refund received</string> diff --git a/wallet/src/main/res/xml/settings_backup.xml b/wallet/src/main/res/xml/settings_backup.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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/> + --> + +<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"> + + <SwitchPreferenceCompat + app:defaultValue="@bool/settings_backup_default" + app:fragment="net.taler.wallet.settings.BackupSettingsFragment" + app:icon="@drawable/ic_baseline_backup" + app:key="pref_backup_switch" + app:summaryOff="Backup is disabled" + app:summaryOn="Backup is enabled" + app:title="Backup my wallet" /> + + <Preference + app:dependency="pref_backup_switch" + app:icon="@drawable/ic_baseline_account_tree" + app:key="pref_backup_services" + app:selectable="false" + app:summary="1 backup service set up" + app:title="Backup services" /> + + <PreferenceCategory + app:iconSpaceReserved="false" + app:summary="At least one of these is required to restore from backup" + app:title="Recovery Options"> + + <Preference + app:dependency="pref_backup_switch" + app:icon="@drawable/ic_baseline_vpn_key" + app:key="pref_backup_secret" + app:selectable="false" + app:title="Show backup secret" /> + + <Preference + app:dependency="pref_backup_switch" + app:icon="@drawable/ic_baseline_cloud_circle" + app:fragment="net.taler.wallet.settings.SettingsFragment" + app:key="pref_backup_recovery" + app:summary="Not used" + app:title="Secure cloud recovery" /> + + </PreferenceCategory> + +</PreferenceScreen> diff --git a/wallet/src/main/res/xml/settings_main.xml b/wallet/src/main/res/xml/settings_main.xml @@ -17,6 +17,14 @@ <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> + <Preference + app:fragment="net.taler.wallet.settings.BackupSettingsFragment" + app:icon="@drawable/ic_baseline_backup" + app:isPreferenceVisible="false" + app:key="pref_backup" + app:title="Backup" + tools:isPreferenceVisible="true" /> + <SwitchPreferenceCompat app:icon="@drawable/ic_developer_mode" app:key="pref_dev_mode"