[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-cashier-terminal-android] 03/04: Allow the user to lock the app
From: |
gnunet |
Subject: |
[taler-cashier-terminal-android] 03/04: Allow the user to lock the app |
Date: |
Wed, 05 Feb 2020 18:30:19 +0100 |
This is an automated email from the git hooks/post-receive script.
torsten-grote pushed a commit to branch master
in repository cashier-terminal-android.
commit 53877fbbba62794160735cd5bbbc7438afdc9201
Author: Torsten Grote <address@hidden>
AuthorDate: Wed Feb 5 13:52:44 2020 -0300
Allow the user to lock the app
This is implemented by "forgetting" the configuration password.
It needs to be re-entered for the app to be used again.
---
.idea/codeStyles/Project.xml | 2 ++
.../main/java/net/taler/cashier/BalanceFragment.kt | 31 ++++++++++++++++++++++
.../main/java/net/taler/cashier/ConfigFragment.kt | 18 ++++++++++++-
.../main/java/net/taler/cashier/MainViewModel.kt | 28 +++++++++++++------
app/src/main/res/menu/balance.xml | 14 ++++++++++
app/src/main/res/values/strings.xml | 2 ++
6 files changed, 86 insertions(+), 9 deletions(-)
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 45b5654..0c9ea66 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -4,6 +4,8 @@
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
</AndroidXmlCodeStyleSettings>
<JetCodeStyleSettings>
+ <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
+ <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS"
value="2147483647" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
diff --git a/app/src/main/java/net/taler/cashier/BalanceFragment.kt
b/app/src/main/java/net/taler/cashier/BalanceFragment.kt
index 6c5b454..987553f 100644
--- a/app/src/main/java/net/taler/cashier/BalanceFragment.kt
+++ b/app/src/main/java/net/taler/cashier/BalanceFragment.kt
@@ -2,12 +2,16 @@ package net.taler.cashier
import android.os.Bundle
import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
import android.view.View
import android.view.View.INVISIBLE
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
import kotlinx.android.synthetic.main.fragment_balance.*
@@ -20,6 +24,7 @@ class BalanceFragment : Fragment() {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
+ setHasOptionsMenu(true)
return inflater.inflate(R.layout.fragment_balance, container, false)
}
@@ -33,4 +38,30 @@ class BalanceFragment : Fragment() {
}
}
+ override fun onStart() {
+ super.onStart()
+ // update balance if there's a config
+ if (viewModel.hasConfig()) {
+ viewModel.getBalance()
+ }
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ inflater.inflate(R.menu.balance, menu)
+ super.onCreateOptionsMenu(menu, inflater)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
+ R.id.action_reconfigure -> {
+ findNavController().navigate(viewModel.configDestination)
+ true
+ }
+ R.id.action_lock -> {
+ viewModel.lock()
+ findNavController().navigate(viewModel.configDestination)
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+
}
diff --git a/app/src/main/java/net/taler/cashier/ConfigFragment.kt
b/app/src/main/java/net/taler/cashier/ConfigFragment.kt
index 3bcae3e..fc53124 100644
--- a/app/src/main/java/net/taler/cashier/ConfigFragment.kt
+++ b/app/src/main/java/net/taler/cashier/ConfigFragment.kt
@@ -29,6 +29,11 @@ class ConfigFragment : Fragment() {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ if (savedInstanceState == null) {
+ urlView.editText!!.setText(viewModel.config.bankUrl)
+ usernameView.editText!!.setText(viewModel.config.username)
+ passwordView.editText!!.setText(viewModel.config.password)
+ }
saveButton.setOnClickListener {
val config = Config(
bankUrl = urlView.editText!!.text.toString(),
@@ -50,6 +55,16 @@ class ConfigFragment : Fragment() {
}
}
+ override fun onStart() {
+ super.onStart()
+ // focus on password if it is the only missing value (like after
locking)
+ if (urlView.editText!!.text.isNotBlank()
+ && usernameView.editText!!.text.isNotBlank()
+ && passwordView.editText!!.text.isBlank()) {
+ passwordView.editText!!.requestFocus()
+ }
+ }
+
private fun checkConfig(config: Config): Boolean {
if (!config.bankUrl.startsWith("https://")) {
urlView.error = getString(R.string.config_bank_url_error)
@@ -68,7 +83,8 @@ class ConfigFragment : Fragment() {
private val onConfigResult = Observer<ConfigResult> { result ->
if (result == null) return@Observer
if (result.success) {
-
findNavController().navigate(R.id.action_configFragment_to_balanceFragment)
+ val action =
ConfigFragmentDirections.actionConfigFragmentToBalanceFragment()
+ findNavController().navigate(action)
} else {
Snackbar.make(view!!, R.string.config_error, LENGTH_LONG).show()
}
diff --git a/app/src/main/java/net/taler/cashier/MainViewModel.kt
b/app/src/main/java/net/taler/cashier/MainViewModel.kt
index da4a164..5645b23 100644
--- a/app/src/main/java/net/taler/cashier/MainViewModel.kt
+++ b/app/src/main/java/net/taler/cashier/MainViewModel.kt
@@ -6,7 +6,10 @@ import android.content.Context.MODE_PRIVATE
import android.util.Log
import androidx.annotation.UiThread
import androidx.annotation.WorkerThread
-import androidx.lifecycle.*
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.taler.cashier.HttpHelper.makeJsonGetRequest
@@ -19,12 +22,12 @@ private const val PREF_KEY_BANK_URL = "bankUrl"
private const val PREF_KEY_USERNAME = "username"
private const val PREF_KEY_PASSWORD = "password"
-class MainViewModel(app: Application) : AndroidViewModel(app) {
+class MainViewModel(private val app: Application) : AndroidViewModel(app) {
val configDestination =
ConfigFragmentDirections.actionGlobalConfigFragment()
private val prefs = app.getSharedPreferences(PREF_NAME, MODE_PRIVATE)
- private val config = Config(
+ internal var config = Config(
bankUrl = prefs.getString(PREF_KEY_BANK_URL, "")!!,
username = prefs.getString(PREF_KEY_USERNAME, "")!!,
password = prefs.getString(PREF_KEY_PASSWORD, "")!!
@@ -33,6 +36,9 @@ class MainViewModel(app: Application) : AndroidViewModel(app)
{
private val mConfigResult = MutableLiveData<ConfigResult>()
val configResult: LiveData<ConfigResult> = mConfigResult
+ private val mBalance = MutableLiveData<String>()
+ val balance: LiveData<String> = mBalance
+
fun hasConfig() = config.bankUrl.isNotEmpty()
&& config.username.isNotEmpty()
&& config.password.isNotEmpty()
@@ -71,6 +77,7 @@ class MainViewModel(app: Application) : AndroidViewModel(app)
{
@WorkerThread
@SuppressLint("ApplySharedPref")
private fun saveConfig(config: Config) {
+ this.config = config
prefs.edit()
.putString(PREF_KEY_BANK_URL, config.bankUrl)
.putString(PREF_KEY_USERNAME, config.username)
@@ -78,14 +85,15 @@ class MainViewModel(app: Application) :
AndroidViewModel(app) {
.commit()
}
- val balance = liveData(Dispatchers.IO) {
+ fun getBalance() = viewModelScope.launch(Dispatchers.IO) {
+ check(hasConfig()) { "No config to get balance" }
val url = "${config.bankUrl}/history?delta=50&direction=both"
val response = try {
makeJsonGetRequest(url, config)
} catch (e: Exception) {
Log.e(TAG, "Error fetching $url", e)
- emit(app.getString(R.string.balance_error))
- return@liveData
+ mBalance.postValue(app.getString(R.string.balance_error))
+ return@launch
}
val result = if (response.code() == 200 && response.body() != null) {
// TODO get real amount here once API is available
@@ -97,12 +105,16 @@ class MainViewModel(app: Application) :
AndroidViewModel(app) {
Log.e(TAG, "Error fetching $url - Response: ${response.code()}")
app.getString(R.string.balance_error)
}
- emit(result)
+ mBalance.postValue(result)
+ }
+
+ fun lock() {
+ saveConfig(config.copy(password=""))
}
}
-class Config(
+data class Config(
val bankUrl: String,
val username: String,
val password: String
diff --git a/app/src/main/res/menu/balance.xml
b/app/src/main/res/menu/balance.xml
new file mode 100644
index 0000000..2f1b6fb
--- /dev/null
+++ b/app/src/main/res/menu/balance.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/action_reconfigure"
+ android:title="@string/action_reconfigure"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/action_lock"
+ android:title="@string/action_lock"
+ app:showAsAction="never" />
+
+</menu>
diff --git a/app/src/main/res/values/strings.xml
b/app/src/main/res/values/strings.xml
index ebfc0ff..2f114de 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -11,5 +11,7 @@
<string name="balance_current_label">Current Balance:</string>
<string name="balance_error">ERROR</string>
+ <string name="action_reconfigure">Reconfigure</string>
+ <string name="action_lock">Lock</string>
</resources>
--
To stop receiving notification emails like this one, please contact
address@hidden.