taler-android

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

commit dc86881ab67c826c326b9a1c9384320427e79702
parent e5178c02dc267cc7d3fec62cbf7adbeab0bbc754
Author: Bohdan Potuzhnyi <bohdan.potuzhnyi@gmail.com>
Date:   Fri,  2 May 2025 13:28:33 +0200

fixing the bugs, checking strings, adding check for token being expired

Diffstat:
Mmerchant-terminal/src/main/java/net/taler/merchantpos/MainActivity.kt | 23+++++++++++++++++------
Mmerchant-terminal/src/main/java/net/taler/merchantpos/MainViewModel.kt | 12++++++++++++
Mmerchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigFragment.kt | 6+++---
Mmerchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigManager.kt | 8++++++++
Mmerchant-terminal/src/main/res/values/strings.xml | 9++-------
5 files changed, 42 insertions(+), 16 deletions(-)

diff --git a/merchant-terminal/src/main/java/net/taler/merchantpos/MainActivity.kt b/merchant-terminal/src/main/java/net/taler/merchantpos/MainActivity.kt @@ -36,9 +36,9 @@ import androidx.navigation.ui.setupWithNavController import com.google.android.material.navigation.NavigationView.OnNavigationItemSelectedListener import net.taler.lib.android.TalerNfcService import net.taler.merchantpos.config.Config +import net.taler.merchantpos.config.ConfigUpdateResult import net.taler.merchantpos.databinding.ActivityMainBinding import android.util.Log -import net.taler.merchantpos.config.ConfigUpdateResult class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener { @@ -66,6 +66,14 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener { } } + // new: if we ever see a 401, fire this and kick back to settings + model.configManager.sessionExpired.observe(this) { + Toast + .makeText(this, R.string.session_expired_toast, Toast.LENGTH_LONG) + .show() + nav.navigate(R.id.action_global_merchantSettings) + } + val navHostFragment = supportFragmentManager.findFragmentById(R.id.navHostFragment) as NavHostFragment nav = navHostFragment.navController @@ -83,8 +91,10 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener { override fun onStart() { super.onStart() if (!model.configManager.config.isValid()) { - if (nav.currentDestination?.id != R.id.nav_settings) nav.navigate(R.id.action_global_merchantSettings) - } else if (model.configManager.merchantConfig == null && nav.currentDestination?.id != R.id.configFetcher) { + if (nav.currentDestination?.id != R.id.nav_settings) + nav.navigate(R.id.action_global_merchantSettings) + } else if (model.configManager.merchantConfig == null + && nav.currentDestination?.id != R.id.configFetcher) { nav.navigate(R.id.action_global_configFetcher) } } @@ -101,9 +111,9 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener { override fun onNavigationItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.nav_order -> nav.navigate(R.id.action_global_order) + R.id.nav_order -> nav.navigate(R.id.action_global_order) R.id.nav_history -> nav.navigate(R.id.action_global_merchantHistory) - R.id.nav_settings -> nav.navigate(R.id.action_global_merchantSettings) + R.id.nav_settings-> nav.navigate(R.id.action_global_merchantSettings) } ui.drawerLayout.closeDrawer(START) return true @@ -119,7 +129,8 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener { val currentDestination = nav.currentDestination?.id if (ui.drawerLayout.isDrawerOpen(START)) { ui.drawerLayout.closeDrawer(START) - } else if (currentDestination == R.id.nav_settings && !model.configManager.config.isValid()) { + } else if (currentDestination == R.id.nav_settings + && !model.configManager.config.isValid()) { // we are in the configuration screen and need a config to continue val intent = Intent(ACTION_MAIN).apply { addCategory(CATEGORY_HOME) diff --git a/merchant-terminal/src/main/java/net/taler/merchantpos/MainViewModel.kt b/merchant-terminal/src/main/java/net/taler/merchantpos/MainViewModel.kt @@ -19,6 +19,8 @@ package net.taler.merchantpos import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope +import io.ktor.client.statement.* +import io.ktor.http.HttpStatusCode import net.taler.common.getDefaultHttpClient import net.taler.merchantlib.MerchantApi import net.taler.merchantpos.config.ConfigManager @@ -40,6 +42,16 @@ class MainViewModel(app: Application) : AndroidViewModel(app) { val historyManager = HistoryManager(configManager, viewModelScope, api) val refundManager = RefundManager(configManager, viewModelScope, api) + init { + httpClient.responsePipeline.intercept(HttpResponsePipeline.Transform) { (info, body) -> + if (context.response.status == HttpStatusCode.Unauthorized) { + configManager.forgetPassword() + configManager.notifySessionExpired() + } + proceedWith(subject) + } + } + override fun onCleared() { httpClient.close() } 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 @@ -151,8 +151,8 @@ class ConfigFragment : Fragment() { val duration: TokenDuration = if (neverOption.isChecked) { TokenDuration.Forever } else { - val micros = deadlineCal.timeInMillis * 1_000L - TokenDuration.Micros(micros) + val microsToDeadline = (deadlineCal.timeInMillis - System.currentTimeMillis()) * 1_000L + TokenDuration.Micros(microsToDeadline) } // fetch limited write token @@ -328,7 +328,7 @@ class ConfigFragment : Fragment() { Log.d("ConfigFragment", "CAMERA permission granted? $granted") if (granted) startCamera() else Toast.makeText(requireContext(), - "Camera permission is required for QR scanning", Toast.LENGTH_SHORT).show() + R.string.config_fragment_camera_needed_text, Toast.LENGTH_SHORT).show() } // 2) request if needed diff --git a/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigManager.kt b/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigManager.kt @@ -226,6 +226,9 @@ class ConfigManager( private val api: MerchantApi, ) { + private val _sessionExpired = MutableLiveData<Unit>() + val sessionExpired: LiveData<Unit> = _sessionExpired + private val prefs = context.getSharedPreferences(SETTINGS_NAME, MODE_PRIVATE) private val configurationReceivers = ArrayList<ConfigurationReceiver>() @@ -422,6 +425,11 @@ class ConfigManager( private fun onNetworkError(msg: String) = scope.launch(Dispatchers.Main) { mConfigUpdateResult.value = ConfigUpdateResult.Error(msg) } + + internal fun notifySessionExpired() { + // do it on the Main thread + _sessionExpired.postValue(Unit) + } } sealed class ConfigUpdateResult { diff --git a/merchant-terminal/src/main/res/values/strings.xml b/merchant-terminal/src/main/res/values/strings.xml @@ -99,11 +99,6 @@ <string name="no_deadline_set">No deadline set</string> <string name="pick_date">Pick date</string> <string name="pick_time">Pick time</string> - <string-array name="time_units_array"> - <item>Seconds</item> - <item>Minutes</item> - <item>Hours</item> - <item>Days</item> - </string-array> - + <string name="session_expired_toast">Session expired – please re-enter your credentials</string> + <string name="config_fragment_camera_needed_text">Camera permission is required for QR scanning</string> </resources>