From 2678fd3c428c854825aaa841259d5ef8e3c6000b Mon Sep 17 00:00:00 2001 From: Henrik Lepson Date: Sat, 16 Oct 2021 11:02:48 +0300 Subject: [PATCH] MOB-38 MOB-40 PIN1 save functionality added, pin/can nav order changed --- .../mobileauthapp/CanFragment.kt | 6 +- .../mobileauthapp/HomeFragment.kt | 3 +- .../mobileauthapp/PinFragment.kt | 58 +++++++++--- .../mobileauthapp/menu/SettingsFragment.kt | 94 ++++++++++++++++--- .../mobileauthapp/model/SmartCardViewModel.kt | 19 ++++ .../app/src/main/res/layout/activity_main.xml | 2 +- .../src/main/res/layout/fragment_settings.xml | 21 ++++- .../app/src/main/res/navigation/nav_graph.xml | 61 +++++++----- .../app/src/main/res/values-en/strings.xml | 8 +- .../app/src/main/res/values-et/strings.xml | 8 +- .../app/src/main/res/values/strings.xml | 11 ++- 11 files changed, 227 insertions(+), 64 deletions(-) diff --git a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/CanFragment.kt b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/CanFragment.kt index 19179f1..8c028af 100644 --- a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/CanFragment.kt +++ b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/CanFragment.kt @@ -49,7 +49,7 @@ class CanFragment : Fragment() { // If CAN is already set private fun skip() { - findNavController().navigate(R.id.action_canFragment_to_authFragment) + findNavController().navigate(R.id.action_canFragment_to_pinFragment) } // Might need some rework, must break it up and make logic better. @@ -73,10 +73,10 @@ class CanFragment : Fragment() { viewModel.storeCan( requireContext() ) - findNavController().navigate(R.id.action_canFragment_to_authFragment) + findNavController().navigate(R.id.action_canFragment_to_pinFragment) } setNegativeButton(R.string.deny_text) { _, _ -> - findNavController().navigate(R.id.action_canFragment_to_authFragment) + findNavController().navigate(R.id.action_canFragment_to_pinFragment) } } builder.setMessage(R.string.can_save_request) diff --git a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/HomeFragment.kt b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/HomeFragment.kt index 600fdd8..75a9ebf 100644 --- a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/HomeFragment.kt +++ b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/HomeFragment.kt @@ -29,11 +29,12 @@ class HomeFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.checkCan(requireContext()) + viewModel.checkPin(requireContext()) binding!!.beginButton.setOnClickListener { goToNextFragment() } } private fun goToNextFragment() { - findNavController().navigate(R.id.action_homeFragment_to_pinFragment) + findNavController().navigate(R.id.action_homeFragment_to_canFragment) } override fun onDestroyView() { diff --git a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/PinFragment.kt b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/PinFragment.kt index 23ed504..cc9dd30 100644 --- a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/PinFragment.kt +++ b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/PinFragment.kt @@ -1,5 +1,6 @@ package com.tarkvaraprojekt.mobileauthapp +import android.app.AlertDialog import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -8,6 +9,7 @@ import android.widget.Toast import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentPinBinding import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel @@ -20,6 +22,9 @@ class PinFragment : Fragment() { private var binding: FragmentPinBinding? = null + // Navigation arguments. saving = true means that we are navigating here from the settings menu and must return to the settings + private val args: CanFragmentArgs by navArgs() + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -31,12 +36,18 @@ class PinFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - + if (viewModel.userPin.length in 4..12) { + skip() + } + if (args.saving) { + binding!!.nextButton.text = getString(R.string.save_text) + } binding!!.nextButton.setOnClickListener { goToNextFragment() } binding!!.cancelButton.setOnClickListener { goToTheStart() } - // Currently PIN 1 is not required and thus this step is immediately skipped. - // In the future the UI flow will be changed in the nav_graph. - goToNextFragment() + } + + private fun skip() { + findNavController().navigate(R.id.action_pinFragment_to_authFragment) } private fun goToNextFragment() { @@ -45,19 +56,42 @@ class PinFragment : Fragment() { viewModel.setUserPin( binding!!.pinEditText.editText?.text.toString() ) - findNavController().navigate(R.id.action_pinFragment_to_canFragment) + if (args.saving) { + viewModel.storePin(requireContext()) + findNavController().navigate(R.id.action_pinFragment_to_settingsFragment) + } else { + val canStoreQuestion: AlertDialog? = activity?.let { frag -> + val builder = AlertDialog.Builder(frag) + builder.apply { + setPositiveButton(R.string.save_text) { _, _ -> + viewModel.storePin( + requireContext() + ) + findNavController().navigate(R.id.action_pinFragment_to_authFragment) + } + setNegativeButton(R.string.deny_text) { _, _ -> + findNavController().navigate(R.id.action_pinFragment_to_authFragment) + } + } + builder.setMessage(R.string.pin_save_request) + builder.setTitle(R.string.save_pin_title) + builder.create() + } + canStoreQuestion?.show() + } } else { - // Currently it is not important to enter PIN1 so we will allow the user to leave this field empty - //Toast.makeText(requireContext(), getString(R.string.length_pin), Toast.LENGTH_SHORT) - // .show() - viewModel.setUserPin("1234") - findNavController().navigate(R.id.action_pinFragment_to_canFragment) + Toast.makeText(requireContext(), getString(R.string.length_pin), Toast.LENGTH_SHORT) + .show() } } private fun goToTheStart() { - viewModel.clearUserInfo() - findNavController().navigate(R.id.action_pinFragment_to_homeFragment) + if (args.saving) { + findNavController().navigate(R.id.action_pinFragment_to_settingsFragment) + } else { + viewModel.clearUserInfo() + findNavController().navigate(R.id.action_pinFragment_to_homeFragment) + } } override fun onDestroy() { diff --git a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/menu/SettingsFragment.kt b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/menu/SettingsFragment.kt index 533d5f4..7410c3f 100644 --- a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/menu/SettingsFragment.kt +++ b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/menu/SettingsFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Button import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController @@ -11,14 +12,19 @@ import com.tarkvaraprojekt.mobileauthapp.R import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentSettingsBinding import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel - -// Currently CAN is not actually saved, only UI part is implemented +/** + * This fragment allows the user to save the CAN and the PIN 1 and also to delete them if necessary. + * Should only be accessible for the user from the HomeFragment and not during the + * authentication process itself. + */ class SettingsFragment : Fragment() { private val viewModel: SmartCardViewModel by activityViewModels() private var binding: FragmentSettingsBinding? = null + private var showPin: Boolean = false + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -30,6 +36,18 @@ class SettingsFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + showCanField() + showPinField() + togglePinButton() + binding!!.canMenuAction.setOnClickListener { canAction() } + binding!!.pinMenuAction.setOnClickListener { pinAction() } + binding!!.pinMenuShow.setOnClickListener { togglePin() } + } + + /** + * Method for showing the CAN field to the user and can be used to refresh the field as well. + */ + private fun showCanField() { if (viewModel.userCan.length == 6) { binding!!.canSaved.text = getString(R.string.saved_can, viewModel.userCan) binding!!.canMenuAction.text = getString(R.string.can_delete) @@ -37,23 +55,73 @@ class SettingsFragment : Fragment() { binding!!.canSaved.text = getString(R.string.saved_can, getString(R.string.missing)) binding!!.canMenuAction.text = getString(R.string.can_add) } + } + + /** + * Method that allows the user to delete saved CAN from the device and also to save new a CAN if + * currently there is no CAN saved. + */ + private fun canAction() { + if (viewModel.userCan.length == 6) { + viewModel.deleteCan(requireContext()) + showCanField() + } else { + val action = SettingsFragmentDirections.actionSettingsFragmentToCanFragment(true) + findNavController().navigate(action) + } + } + + /** + * Method for showing the PIN 1 field to the user and can be used to refresh the field as well. + * The PIN 1 is hidden by default and when it is hidden it is always shown as **** despite the + * length of the PIN 1. Can be made visible with toggle button. + */ + private fun showPinField() { if (viewModel.userPin.length in 4..12) { - binding!!.pinSaved.text = getString(R.string.saved_pin, viewModel.userPin) + binding!!.pinMenuShow.visibility = Button.VISIBLE + if (showPin) + binding!!.pinSaved.text = getString(R.string.saved_pin, viewModel.userPin) + else + binding!!.pinSaved.text = getString(R.string.saved_pin, getString(R.string.hidden_pin)) binding!!.pinMenuAction.text = getString(R.string.pin1_delete) } else { + binding!!.pinMenuShow.visibility = Button.GONE binding!!.pinSaved.text = getString(R.string.saved_pin, getString(R.string.missing)) binding!!.pinMenuAction.text = getString(R.string.pin1_add) } - binding!!.canMenuAction.setOnClickListener { - if (viewModel.userCan.length != 6) { - val action = SettingsFragmentDirections.actionSettingsFragmentToCanFragment(true) - findNavController().navigate(action) - } else { - // If can in ViewModel is 6 we know that we can only delete it. - viewModel.deleteCan(requireContext()) - binding!!.canSaved.text = getString(R.string.saved_can, "puudub") - binding!!.canMenuAction.text = getString(R.string.can_add) - } + } + + /** + * Method that allows the user to delete saved PIN 1 from the device and also to save a new PIN 1 if + * currently there is no PIN 1 saved. + */ + private fun pinAction() { + if (viewModel.userPin.length in 4..12) { + viewModel.deletePin(requireContext()) + showPinField() + } else { + val action = SettingsFragmentDirections.actionSettingsFragmentToPinFragment(true) + findNavController().navigate(action) + } + } + + /** + * Hides the PIN 1 or makes it visible. + */ + private fun togglePin() { + showPin = !showPin + togglePinButton() + showPinField() + } + + /** + * Updates the text on the button that controls the visiblity of the PIN 1. + */ + private fun togglePinButton() { + if (showPin) { + binding!!.pinMenuShow.text = getString(R.string.hide) + } else { + binding!!.pinMenuShow.text = getString(R.string.show) } } diff --git a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/model/SmartCardViewModel.kt b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/model/SmartCardViewModel.kt index 9bfa178..ac14733 100644 --- a/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/model/SmartCardViewModel.kt +++ b/MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/model/SmartCardViewModel.kt @@ -83,4 +83,23 @@ class SmartCardViewModel: ViewModel() { _userCan = "" } + fun storePin(context: Context) { + val sharedPreferences: SharedPreferences = getSharedPreferences(context) + sharedPreferences.edit().putString("PIN1", userPin).apply() + } + + fun checkPin(context: Context) { + val sharedPreferences: SharedPreferences = getSharedPreferences(context) + val foundPin = sharedPreferences.getString("PIN1", null) + foundPin?.let { + _userPin = it + } + } + + fun deletePin(context: Context) { + val sharedPreferences: SharedPreferences = getSharedPreferences(context) + sharedPreferences.edit().remove("PIN1").apply() + _userPin = "" + } + } \ No newline at end of file diff --git a/MobileAuthApp/app/src/main/res/layout/activity_main.xml b/MobileAuthApp/app/src/main/res/layout/activity_main.xml index fe72c5c..2ad4133 100644 --- a/MobileAuthApp/app/src/main/res/layout/activity_main.xml +++ b/MobileAuthApp/app/src/main/res/layout/activity_main.xml @@ -12,7 +12,7 @@ android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="4dp" - android:theme="@style/ThemeOverlay.AppCompat.ActionBar" + android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/MobileAuthApp/app/src/main/res/layout/fragment_settings.xml b/MobileAuthApp/app/src/main/res/layout/fragment_settings.xml index 80bdb53..15d09c3 100644 --- a/MobileAuthApp/app/src/main/res/layout/fragment_settings.xml +++ b/MobileAuthApp/app/src/main/res/layout/fragment_settings.xml @@ -42,11 +42,22 @@ android:textSize="20sp" android:padding="12dp" android:text="@string/saved_pin"/> -