Create PinCodeStore and migrate code to fragment

This commit is contained in:
ganfra 2020-07-29 11:38:04 +02:00
parent ecdef52829
commit 5426e43cbb
7 changed files with 156 additions and 77 deletions

View file

@ -48,6 +48,7 @@ import im.vector.riotx.features.notifications.NotificationBroadcastReceiver
import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.notifications.NotificationUtils
import im.vector.riotx.features.notifications.PushRuleTriggerListener
import im.vector.riotx.features.pin.PinCodeStore
import im.vector.riotx.features.popup.PopupAlertManager
import im.vector.riotx.features.rageshake.BugReporter
import im.vector.riotx.features.rageshake.VectorFileLogger
@ -132,6 +133,8 @@ interface VectorComponent {
fun uiStateRepository(): UiStateRepository
fun pinCodeStore(): PinCodeStore
fun emojiDataSource(): EmojiDataSource
fun alertManager(): PopupAlertManager

View file

@ -31,6 +31,8 @@ import im.vector.riotx.core.error.DefaultErrorFormatter
import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.features.navigation.DefaultNavigator
import im.vector.riotx.features.navigation.Navigator
import im.vector.riotx.features.pin.PinCodeStore
import im.vector.riotx.features.pin.SharedPrefPinCodeStore
import im.vector.riotx.features.ui.SharedPreferencesUiStateRepository
import im.vector.riotx.features.ui.UiStateRepository
@ -86,4 +88,7 @@ abstract class VectorModule {
@Binds
abstract fun bindUiStateRepository(repository: SharedPreferencesUiStateRepository): UiStateRepository
@Binds
abstract fun bindPinCodeStore(store: SharedPrefPinCodeStore): PinCodeStore
}

View file

@ -18,14 +18,9 @@ package im.vector.riotx.features.pin
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar
import com.beautycoder.pflockscreen.PFFLockScreenConfiguration
import com.beautycoder.pflockscreen.fragments.PFLockScreenFragment
import com.beautycoder.pflockscreen.fragments.PFLockScreenFragment.OnPFLockScreenCodeCreateListener
import im.vector.riotx.R
import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.core.extensions.addFragment
import im.vector.riotx.core.platform.ToolbarConfigurable
import im.vector.riotx.core.platform.VectorBaseActivity
@ -41,74 +36,12 @@ class PinActivity : VectorBaseActivity(), ToolbarConfigurable {
override fun getLayoutRes() = R.layout.activity_simple
override fun initUiAndData() {
showCreateFragment()
if (isFirstCreation()) {
addFragment(R.id.simpleFragmentContainer, PinFragment::class.java)
}
}
override fun configure(toolbar: Toolbar) {
configureToolbar(toolbar)
}
private fun showCreateFragment() {
val createFragment = PFLockScreenFragment()
val builder = PFFLockScreenConfiguration.Builder(this)
.setNewCodeValidation(true)
.setTitle("Choose a PIN for security")
.setNewCodeValidationTitle("Confirm PIN")
.setMode(PFFLockScreenConfiguration.MODE_CREATE)
createFragment.setConfiguration(builder.build())
createFragment.setCodeCreateListener(object : OnPFLockScreenCodeCreateListener {
override fun onNewCodeValidationFailed() {
}
override fun onCodeCreated(encodedCode: String) {
showAuthFragment(encodedCode)
}
})
replaceFragment(R.id.simpleFragmentContainer, createFragment)
}
private fun showAuthFragment(encodedCode: String) {
val authFragment = PFLockScreenFragment()
val builder = PFFLockScreenConfiguration.Builder(this)
.setUseFingerprint(true)
.setTitle("Enter your PIN")
.setLeftButton("Forgot PIN?")
.setClearCodeOnError(true)
.setMode(PFFLockScreenConfiguration.MODE_AUTH)
authFragment.setConfiguration(builder.build())
authFragment.setEncodedPinCode(encodedCode)
authFragment.setOnLeftButtonClickListener {
displayForgotPinWarningDialog()
}
authFragment.setLoginListener(object : PFLockScreenFragment.OnPFLockScreenLoginListener {
override fun onPinLoginFailed() {
}
override fun onFingerprintSuccessful() {
Toast.makeText(this@PinActivity, "Pin successful", Toast.LENGTH_LONG).show()
finish()
}
override fun onFingerprintLoginFailed() {
}
override fun onCodeInputSuccessful() {
Toast.makeText(this@PinActivity, "Pin successful", Toast.LENGTH_LONG).show()
finish()
}
})
replaceFragment(R.id.simpleFragmentContainer, authFragment)
}
private fun displayForgotPinWarningDialog() {
AlertDialog.Builder(this)
.setTitle("Reset pin")
.setMessage("To reset your PIN, you'll need to re-login and create a new one.")
.setPositiveButton("Reset pin") { _, _ ->
showCreateFragment()
}
.setNegativeButton(R.string.cancel, null)
.show()
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotx.features.pin
import android.content.SharedPreferences
import androidx.core.content.edit
import javax.inject.Inject
interface PinCodeStore {
fun storeEncodedPin(encodePin: String)
fun deleteEncodedPin()
fun getEncodedPin(): String?
}
class SharedPrefPinCodeStore @Inject constructor(private val sharedPreferences: SharedPreferences) : PinCodeStore {
override fun storeEncodedPin(encodePin: String) {
sharedPreferences.edit {
putString(ENCODED_PIN_CODE_KEY, encodePin)
}
}
override fun deleteEncodedPin() {
sharedPreferences.edit {
remove(ENCODED_PIN_CODE_KEY)
}
}
override fun getEncodedPin(): String? {
return sharedPreferences.getString(ENCODED_PIN_CODE_KEY, null)
}
companion object {
const val ENCODED_PIN_CODE_KEY = "ENCODED_PIN_CODE_KEY"
}
}

View file

@ -18,14 +18,20 @@ package im.vector.riotx.features.pin
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.beautycoder.pflockscreen.PFFLockScreenConfiguration
import com.beautycoder.pflockscreen.fragments.PFLockScreenFragment
import im.vector.riotx.R
import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.core.platform.VectorBaseFragment
import timber.log.Timber
import javax.inject.Inject
class PinFragment @Inject constructor(
private val pinCodeStore: PinCodeStore,
private val viewModelFactory: PinViewModel.Factory
) : VectorBaseFragment(), PinViewModel.Factory by viewModelFactory {
@ -35,7 +41,79 @@ class PinFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Initialize your view, subscribe to viewModel...
val encodedPinCode = pinCodeStore.getEncodedPin()
if (encodedPinCode.isNullOrBlank()) {
showCreateFragment()
} else {
showAuthFragment(encodedPinCode)
}
}
private fun showCreateFragment() {
val createFragment = PFLockScreenFragment()
val builder = PFFLockScreenConfiguration.Builder(requireContext())
.setNewCodeValidation(true)
.setTitle("Choose a PIN for security")
.setNewCodeValidationTitle("Confirm PIN")
.setMode(PFFLockScreenConfiguration.MODE_CREATE)
createFragment.setConfiguration(builder.build())
createFragment.setCodeCreateListener(object : PFLockScreenFragment.OnPFLockScreenCodeCreateListener {
override fun onNewCodeValidationFailed() {
Toast.makeText(requireContext(), "Failed to validate pin, please tap a new one.", Toast.LENGTH_SHORT).show()
}
override fun onCodeCreated(encodedCode: String) {
pinCodeStore.storeEncodedPin(encodedCode)
vectorBaseActivity.finish()
}
})
replaceFragment(R.id.pinFragmentContainer, createFragment)
}
private fun showAuthFragment(encodedCode: String) {
val authFragment = PFLockScreenFragment()
val builder = PFFLockScreenConfiguration.Builder(requireContext())
.setUseFingerprint(true)
.setTitle("Enter your PIN")
.setLeftButton("Forgot PIN?")
.setClearCodeOnError(true)
.setMode(PFFLockScreenConfiguration.MODE_AUTH)
authFragment.setConfiguration(builder.build())
authFragment.setEncodedPinCode(encodedCode)
authFragment.setOnLeftButtonClickListener {
displayForgotPinWarningDialog()
}
authFragment.setLoginListener(object : PFLockScreenFragment.OnPFLockScreenLoginListener {
override fun onPinLoginFailed() {
}
override fun onFingerprintSuccessful() {
Toast.makeText(requireContext(), "Pin successful", Toast.LENGTH_LONG).show()
vectorBaseActivity.finish()
}
override fun onFingerprintLoginFailed() {
}
override fun onCodeInputSuccessful() {
Toast.makeText(requireContext(), "Pin successful", Toast.LENGTH_LONG).show()
vectorBaseActivity.finish()
}
})
replaceFragment(R.id.pinFragmentContainer, authFragment)
}
private fun displayForgotPinWarningDialog() {
AlertDialog.Builder(requireContext())
.setTitle("Reset pin")
.setMessage("To reset your PIN, you'll need to re-login and create a new one.")
.setPositiveButton("Reset pin") { _, _ ->
pinCodeStore.deleteEncodedPin()
vectorBaseActivity.finish()
}
.setNegativeButton(R.string.cancel, null)
.show()
}
override fun onDestroyView() {

View file

@ -158,6 +158,7 @@ class VectorPreferences @Inject constructor(private val context: Context) {
// Security
const val SETTINGS_SECURITY_USE_FLAG_SECURE = "SETTINGS_SECURITY_USE_FLAG_SECURE"
const val SETTINGS_SECURITY_USE_PIN_CODE_FLAG = "SETTINGS_SECURITY_USE_PIN_CODE_FLAG"
// other
const val SETTINGS_MEDIA_SAVING_PERIOD_KEY = "SETTINGS_MEDIA_SAVING_PERIOD_KEY"
@ -810,4 +811,11 @@ class VectorPreferences @Inject constructor(private val context: Context) {
fun useFlagSecure(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_FLAG_SECURE, false)
}
/**
* The user enable protecting app access with pin code
*/
fun useFlagPinCode(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_FLAG_SECURE, false)
}
}

View file

@ -6,11 +6,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PinFragment"
<FrameLayout
android:id="@+id/pinFragmentContainer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"