diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt index c7c6d6a813..6f1988a206 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt @@ -31,10 +31,12 @@ import androidx.compose.ui.res.vectorResource import androidx.core.app.DialogCompat import androidx.fragment.app.viewModels import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar +import kotlinx.coroutines.launch import org.signal.core.ui.compose.Dialogs import org.signal.core.ui.compose.Dividers import org.signal.core.ui.compose.Previews @@ -112,24 +114,21 @@ class AccountSettingsFragment : ComposeFragment() { val turnOffButton = DialogCompat.requireViewById(dialog, R.id.reminder_disable_turn_off) val changeKeyboard = DialogCompat.requireViewById(dialog, R.id.reminder_change_keyboard) as MaterialButton - changeKeyboard.setOnClickListener { - val newType = PinKeyboardType.fromEditText(pinEditText).other - newType.applyTo( - pinEditText = pinEditText, - toggleTypeButton = changeKeyboard - ) - pinEditText.typeface = Typeface.DEFAULT + dialog.lifecycleScope.launch { + viewModel.state.collect { state -> + state.pinKeyboardType.applyTo( + pinEditText = pinEditText, + toggleTypeButton = changeKeyboard + ) + } } + changeKeyboard.setOnClickListener { viewModel.togglePinKeyboardType() } + pinEditText.post { ViewUtil.focusAndShowKeyboard(pinEditText) } - SignalStore.pin.keyboardType.applyTo( - pinEditText = pinEditText, - toggleTypeButton = changeKeyboard - ) - pinEditText.addTextChangedListener(object : SimpleTextWatcher() { override fun onTextChanged(text: String) { turnOffButton.isEnabled = text.length >= SvrConstants.MINIMUM_PIN_LENGTH @@ -459,6 +458,7 @@ private fun AccountSettingsScreenPreview() { AccountSettingsScreen( state = AccountSettingsState( hasPin = true, + pinKeyboardType = PinKeyboardType.NUMERIC, hasRestoredAep = true, pinRemindersEnabled = true, registrationLockEnabled = true, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsState.kt index d4cd57dade..7945fcda51 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsState.kt @@ -1,7 +1,10 @@ package org.thoughtcrime.securesms.components.settings.app.account +import org.thoughtcrime.securesms.lock.v2.PinKeyboardType + data class AccountSettingsState( val hasPin: Boolean, + val pinKeyboardType: PinKeyboardType, val hasRestoredAep: Boolean, val pinRemindersEnabled: Boolean, val registrationLockEnabled: Boolean, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt index 7ca0ffa42e..66a727d0bd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt @@ -18,9 +18,16 @@ class AccountSettingsViewModel : ViewModel() { store.update { getCurrentState() } } + fun togglePinKeyboardType() { + store.update { previousState -> + previousState.copy(pinKeyboardType = previousState.pinKeyboardType.other) + } + } + private fun getCurrentState(): AccountSettingsState { return AccountSettingsState( hasPin = SignalStore.svr.hasPin() && !SignalStore.svr.hasOptedOut(), + pinKeyboardType = SignalStore.pin.keyboardType, hasRestoredAep = SignalStore.account.restoredAccountEntropyPool, pinRemindersEnabled = SignalStore.pin.arePinRemindersEnabled() && SignalStore.svr.hasPin(), registrationLockEnabled = SignalStore.svr.isRegistrationLockEnabled, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRegistrationLockFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRegistrationLockFragment.kt index ad5d10b01f..5d701ffff4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRegistrationLockFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRegistrationLockFragment.kt @@ -23,7 +23,6 @@ import org.thoughtcrime.securesms.components.ViewBinderDelegate import org.thoughtcrime.securesms.components.settings.app.changenumber.ChangeNumberUtil.changeNumberSuccess import org.thoughtcrime.securesms.databinding.FragmentRegistrationLockBinding import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.lock.v2.SvrConstants import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate @@ -51,9 +50,6 @@ class ChangeNumberRegistrationLockFragment : LoggingFragment(R.layout.fragment_c private var timeRemaining: Long = 0 - private val pinEntryKeyboardType: PinKeyboardType - get() = PinKeyboardType.fromEditText(editText = binding.kbsLockPinInput) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) RegistrationViewDelegate.setDebugLogSubmitMultiTapView(view.findViewById(R.id.kbs_lock_pin_title)) @@ -93,10 +89,7 @@ class ChangeNumberRegistrationLockFragment : LoggingFragment(R.layout.fragment_c handlePinEntry() } - binding.kbsLockKeyboardToggle.setOnClickListener { - updateKeyboard(pinEntryKeyboardType.other) - } - updateKeyboard(pinEntryKeyboardType) + binding.kbsLockKeyboardToggle.setOnClickListener { viewModel.togglePinKeyboardType() } viewModel.liveLockedTimeRemaining.observe(viewLifecycleOwner) { t: Long -> timeRemaining = t } @@ -123,6 +116,11 @@ class ChangeNumberRegistrationLockFragment : LoggingFragment(R.layout.fragment_c if (state.changeNumberOutcome == ChangeNumberOutcome.VerificationCodeWorked) { handleSuccessfulPinEntry(state.enteredPin) } + + state.pinKeyboardType.applyTo( + pinEditText = binding.kbsLockPinInput, + toggleTypeButton = binding.kbsLockKeyboardToggle + ) } private fun handlePinEntry() { @@ -275,13 +273,6 @@ class ChangeNumberRegistrationLockFragment : LoggingFragment(R.layout.fragment_c ViewUtil.focusAndShowKeyboard(binding.kbsLockPinInput) } - private fun updateKeyboard(newType: PinKeyboardType) { - newType.applyTo( - pinEditText = binding.kbsLockPinInput, - toggleTypeButton = binding.kbsLockKeyboardToggle - ) - } - private fun navigateToAccountLocked() { findNavController().safeNavigate(ChangeNumberRegistrationLockFragmentDirections.actionChangeNumberRegistrationLockToChangeNumberAccountLocked()) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberState.kt index 5c2e802ae7..4e19fa8276 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberState.kt @@ -5,6 +5,8 @@ package org.thoughtcrime.securesms.components.settings.app.changenumber +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.registration.data.network.Challenge import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult import org.thoughtcrime.securesms.registration.ui.countrycode.Country @@ -19,6 +21,7 @@ data class ChangeNumberState( val number: NumberViewState = NumberViewState.INITIAL, val enteredCode: String? = null, val enteredPin: String = "", + val pinKeyboardType: PinKeyboardType = SignalStore.pin.keyboardType, val oldPhoneNumber: NumberViewState = NumberViewState.INITIAL, val sessionId: String? = null, val changeNumberOutcome: ChangeNumberOutcome? = null, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModel.kt index 30ec24dab4..f8209b3f65 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModel.kt @@ -150,6 +150,12 @@ class ChangeNumberViewModel : ViewModel() { } } + fun togglePinKeyboardType() { + store.update { previousState -> + previousState.copy(pinKeyboardType = previousState.pinKeyboardType.other) + } + } + fun incrementIncorrectCodeAttempts() { store.update { it.copy(incorrectCodeAttempts = it.incorrectCodeAttempts + 1) diff --git a/app/src/main/java/org/thoughtcrime/securesms/lock/v2/PinKeyboardType.kt b/app/src/main/java/org/thoughtcrime/securesms/lock/v2/PinKeyboardType.kt index 137672b7c3..4919f61387 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/lock/v2/PinKeyboardType.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/lock/v2/PinKeyboardType.kt @@ -24,15 +24,6 @@ enum class PinKeyboardType(val code: String) { */ @JvmStatic fun fromCode(code: String?): PinKeyboardType = entries.firstOrNull { it.code == code } ?: NUMERIC - - /** - * Gets the keyboard type that is associated with an [EditText]'s current input type. - */ - @JvmStatic - fun fromEditText(editText: EditText): PinKeyboardType = when { - (editText.inputType and InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_NUMBER -> NUMERIC - else -> ALPHA_NUMERIC - } } private val inputType: Int by lazy { diff --git a/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreEntryFragment.java b/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreEntryFragment.java index ecec54c20e..a5e14b146e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreEntryFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreEntryFragment.java @@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.pin; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -import android.text.InputType; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -29,7 +28,6 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.jobs.ProfileUploadJob; import org.thoughtcrime.securesms.keyvalue.RestoreDecisionStateUtil; import org.thoughtcrime.securesms.keyvalue.SignalStore; -import org.thoughtcrime.securesms.lock.v2.PinKeyboardType; import org.thoughtcrime.securesms.lock.v2.SvrConstants; import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.profiles.edit.CreateProfileActivity; @@ -100,15 +98,14 @@ public class PinRestoreEntryFragment extends LoggingFragment { onPinSubmitted(); }); - keyboardToggle.setOnClickListener((v) -> { - getPinEntryKeyboardType().getOther().applyTo(pinEntry, keyboardToggle); - }); - getPinEntryKeyboardType().applyTo(pinEntry, keyboardToggle); + keyboardToggle.setOnClickListener((v) -> viewModel.toggleKeyboardType()); } private void initViewModel() { viewModel = new ViewModelProvider(this).get(PinRestoreViewModel.class); + viewModel.getKeyboardType().observe(getViewLifecycleOwner(), keyboardType -> keyboardType.applyTo(pinEntry, keyboardToggle)); + viewModel.triesRemaining.observe(getViewLifecycleOwner(), this::presentTriesRemaining); viewModel.getEvent().observe(getViewLifecycleOwner(), this::presentEvent); } @@ -175,13 +172,9 @@ public class PinRestoreEntryFragment extends LoggingFragment { } } - private PinKeyboardType getPinEntryKeyboardType() { - return PinKeyboardType.fromEditText(pinEntry); - } - private void onPinSubmitted() { pinEntry.setEnabled(false); - viewModel.onPinSubmitted(pinEntry.getText().toString(), getPinEntryKeyboardType()); + viewModel.onPinSubmitted(pinEntry.getText().toString()); pinButton.setSpinning(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreViewModel.kt index 08d7556bec..61cc492de7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreViewModel.kt @@ -7,6 +7,7 @@ import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.schedulers.Schedulers +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.lock.v2.SvrConstants import org.thoughtcrime.securesms.util.DefaultValueLiveData @@ -19,11 +20,18 @@ class PinRestoreViewModel : ViewModel() { @JvmField val triesRemaining: DefaultValueLiveData = DefaultValueLiveData(TriesRemaining(10, false)) + private val _keyboardType = DefaultValueLiveData(SignalStore.pin.keyboardType) + val keyboardType: LiveData = _keyboardType + private val event: SingleLiveEvent = SingleLiveEvent() private val disposables = CompositeDisposable() - fun onPinSubmitted(pin: String, pinKeyboardType: PinKeyboardType) { + fun toggleKeyboardType() { + _keyboardType.value = _keyboardType.value.other + } + + fun onPinSubmitted(pin: String) { val trimmedLength = pin.trim().length if (trimmedLength == 0) { event.postValue(Event.EMPTY_PIN) @@ -35,7 +43,7 @@ class PinRestoreViewModel : ViewModel() { } disposables += Single - .fromCallable { repo.restoreMasterKeyPostRegistration(pin, pinKeyboardType) } + .fromCallable { repo.restoreMasterKeyPostRegistration(pin, _keyboardType.value) } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { result -> @@ -43,16 +51,20 @@ class PinRestoreViewModel : ViewModel() { is SecureValueRecovery.RestoreResponse.Success -> { event.postValue(Event.SUCCESS) } + is SecureValueRecovery.RestoreResponse.PinMismatch -> { event.postValue(Event.PIN_INCORRECT) triesRemaining.postValue(TriesRemaining(result.triesRemaining, true)) } + SecureValueRecovery.RestoreResponse.Missing -> { event.postValue(Event.PIN_LOCKED) } + is SecureValueRecovery.RestoreResponse.NetworkError -> { event.postValue(Event.NETWORK_ERROR) } + is SecureValueRecovery.RestoreResponse.ApplicationError -> { event.postValue(Event.NETWORK_ERROR) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/RegistrationState.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/RegistrationState.kt index 407ed41e45..09f7f13d80 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/RegistrationState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/RegistrationState.kt @@ -10,6 +10,7 @@ import com.google.i18n.phonenumbers.PhoneNumberUtil import com.google.i18n.phonenumbers.Phonenumber import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.registration.data.network.Challenge import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult @@ -48,6 +49,7 @@ data class RegistrationState( val nextVerificationAttempt: Duration = 0.seconds, val verified: Boolean = false, val smsListenerTimeout: Long = 0L, + val pinKeyboardType: PinKeyboardType = SignalStore.pin.keyboardType, val registrationCheckpoint: RegistrationCheckpoint = RegistrationCheckpoint.INITIALIZATION, val networkError: Throwable? = null, val sessionCreationError: RegistrationSessionResult? = null, diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/RegistrationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/RegistrationViewModel.kt index 88707391da..cb84118b8e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/RegistrationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/RegistrationViewModel.kt @@ -211,6 +211,12 @@ class RegistrationViewModel : ViewModel() { return fcmToken } + fun togglePinKeyboardType() { + store.update { previousState -> + previousState.copy(pinKeyboardType = previousState.pinKeyboardType.other) + } + } + fun onBackupSuccessfullyRestored() { val recoveryPassword = SignalStore.svr.recoveryPassword store.update { @@ -723,6 +729,8 @@ class RegistrationViewModel : ViewModel() { fun verifyCodeAndRegisterAccountWithRegistrationLock(context: Context, pin: String) { Log.v(TAG, "verifyCodeAndRegisterAccountWithRegistrationLock()") + SignalStore.pin.keyboardType = store.value.pinKeyboardType + store.update { it.copy( inProgress = true, diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/registrationlock/RegistrationLockFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/registrationlock/RegistrationLockFragment.kt index 239886401b..7b53d65d50 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/registrationlock/RegistrationLockFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/registrationlock/RegistrationLockFragment.kt @@ -19,8 +19,6 @@ import org.thoughtcrime.securesms.LoggingFragment import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.ViewBinderDelegate import org.thoughtcrime.securesms.databinding.FragmentRegistrationLockBinding -import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.lock.v2.SvrConstants import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult @@ -43,9 +41,6 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ private var timeRemaining: Long = 0 - private val pinEntryKeyboardType: PinKeyboardType - get() = PinKeyboardType.fromEditText(editText = binding.kbsLockPinInput) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setDebugLogSubmitMultiTapView(view.findViewById(R.id.kbs_lock_pin_title)) @@ -74,10 +69,7 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ handlePinEntry() } - binding.kbsLockKeyboardToggle.setOnClickListener { - updateKeyboard(pinEntryKeyboardType.other) - } - updateKeyboard(pinEntryKeyboardType) + binding.kbsLockKeyboardToggle.setOnClickListener { viewModel.togglePinKeyboardType() } viewModel.lockedTimeRemaining.observe(viewLifecycleOwner) { t: Long -> timeRemaining = t } @@ -114,6 +106,11 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ handleRegistrationErrorResponse(error) viewModel.registerAccountErrorShown() } + + it.pinKeyboardType.applyTo( + pinEditText = binding.kbsLockPinInput, + toggleTypeButton = binding.kbsLockKeyboardToggle + ) } } @@ -135,8 +132,6 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ return } - SignalStore.pin.keyboardType = pinEntryKeyboardType - binding.kbsLockPinConfirm.setSpinning() viewModel.verifyCodeAndRegisterAccountWithRegistrationLock(requireContext(), pin) @@ -263,13 +258,6 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ ViewUtil.focusAndShowKeyboard(binding.kbsLockPinInput) } - private fun updateKeyboard(newType: PinKeyboardType) { - newType.applyTo( - pinEditText = binding.kbsLockPinInput, - toggleTypeButton = binding.kbsLockKeyboardToggle - ) - } - private fun sendEmailToSupport() { val subject = R.string.RegistrationLockFragment__signal_registration_need_help_with_pin_for_android_v2_pin diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinFragment.kt index 5904d7f5db..1acf612bdd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinFragment.kt @@ -18,7 +18,6 @@ import org.thoughtcrime.securesms.LoggingFragment import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.ViewBinderDelegate import org.thoughtcrime.securesms.databinding.FragmentRegistrationPinRestoreEntryV2Binding -import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.lock.v2.SvrConstants import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate @@ -41,9 +40,6 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration private val binding: FragmentRegistrationPinRestoreEntryV2Binding by ViewBinderDelegate(FragmentRegistrationPinRestoreEntryV2Binding::bind) - private val pinEntryKeyboardType: PinKeyboardType - get() = PinKeyboardType.fromEditText(editText = binding.pinRestorePinInput) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -71,10 +67,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration handlePinEntry() } - binding.pinRestoreKeyboardToggle.setOnClickListener { - updateKeyboard(newType = pinEntryKeyboardType.other) - } - updateKeyboard(newType = pinEntryKeyboardType) + binding.pinRestoreKeyboardToggle.setOnClickListener { reRegisterViewModel.toggleKeyboardType() } LiveDataUtil .combineLatest(registrationViewModel.uiState, reRegisterViewModel.uiState) { reg, rereg -> reg to rereg } @@ -96,6 +89,11 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration presentTriesRemaining(reRegisterState, state.svrTriesRemaining) } + reRegisterState.pinKeyboardType.applyTo( + pinEditText = binding.pinRestorePinInput, + toggleTypeButton = binding.pinRestoreKeyboardToggle + ) + state.registerAccountError?.let { error -> registrationErrorHandler(error) registrationViewModel.registerAccountErrorShown() @@ -193,13 +191,6 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration ViewUtil.focusAndShowKeyboard(binding.pinRestorePinInput) } - private fun updateKeyboard(newType: PinKeyboardType) { - newType.applyTo( - pinEditText = binding.pinRestorePinInput, - toggleTypeButton = binding.pinRestoreKeyboardToggle - ) - } - private fun onNeedHelpClicked() { Log.i(TAG, "User clicked need help dialog.") val message = if (reRegisterViewModel.isLocalVerification) R.string.ReRegisterWithPinFragment_need_help_local else R.string.PinRestoreEntryFragment_your_pin_is_a_d_digit_code diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinState.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinState.kt index cbfb7a5bc3..6f0e179422 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinState.kt @@ -5,8 +5,12 @@ package org.thoughtcrime.securesms.registration.ui.reregisterwithpin +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.lock.v2.PinKeyboardType + data class ReRegisterWithPinState( val isLocalVerification: Boolean = false, val hasIncorrectGuess: Boolean = false, - val localPinMatches: Boolean = false + val localPinMatches: Boolean = false, + val pinKeyboardType: PinKeyboardType = SignalStore.pin.keyboardType ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinViewModel.kt index 9f7e489dc2..cb4b3d1b1b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/reregisterwithpin/ReRegisterWithPinViewModel.kt @@ -29,4 +29,10 @@ class ReRegisterWithPinViewModel : ViewModel() { it.copy(hasIncorrectGuess = true) } } + + fun toggleKeyboardType() { + store.update { previousState -> + previousState.copy(pinKeyboardType = previousState.pinKeyboardType.other) + } + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/RegistrationState.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/RegistrationState.kt index 702dc2e22c..33b2627dfe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/RegistrationState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/RegistrationState.kt @@ -10,6 +10,7 @@ import com.google.i18n.phonenumbers.PhoneNumberUtil import com.google.i18n.phonenumbers.Phonenumber import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.registration.data.network.Challenge import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult @@ -49,6 +50,7 @@ data class RegistrationState( val nextVerificationAttempt: Duration = 0.seconds, val verified: Boolean = false, val smsListenerTimeout: Long = 0L, + val pinKeyboardType: PinKeyboardType = SignalStore.pin.keyboardType, val registrationCheckpoint: RegistrationCheckpoint = RegistrationCheckpoint.INITIALIZATION, val networkError: Throwable? = null, val sessionCreationError: RegistrationSessionResult? = null, diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/RegistrationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/RegistrationViewModel.kt index e232460e0b..e7a88ccdc2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/RegistrationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/RegistrationViewModel.kt @@ -238,6 +238,12 @@ class RegistrationViewModel : ViewModel() { return fcmToken } + fun togglePinKeyboardType() { + store.update { previousState -> + previousState.copy(pinKeyboardType = previousState.pinKeyboardType.other) + } + } + fun onBackupSuccessfullyRestored() { val recoveryPassword = SignalStore.svr.recoveryPassword store.update { @@ -759,6 +765,8 @@ class RegistrationViewModel : ViewModel() { fun verifyCodeAndRegisterAccountWithRegistrationLock(context: Context, pin: String) { Log.v(TAG, "verifyCodeAndRegisterAccountWithRegistrationLock()") + SignalStore.pin.keyboardType = store.value.pinKeyboardType + store.update { it.copy( inProgress = true, @@ -1105,6 +1113,7 @@ class RegistrationViewModel : ViewModel() { RegistrationRepository.registerAccountLocally(context, data) } + is NetworkResult.ApplicationError -> return RegisterLinkDeviceResult.UnexpectedException(result.throwable) is NetworkResult.NetworkError<*> -> return RegisterLinkDeviceResult.NetworkException(result.exception) is NetworkResult.StatusCodeError -> { diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/registrationlock/RegistrationLockFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/registrationlock/RegistrationLockFragment.kt index e1a8cd3c35..895ba839d8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/registrationlock/RegistrationLockFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/registrationlock/RegistrationLockFragment.kt @@ -19,8 +19,6 @@ import org.thoughtcrime.securesms.LoggingFragment import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.ViewBinderDelegate import org.thoughtcrime.securesms.databinding.FragmentRegistrationLockBinding -import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.lock.v2.SvrConstants import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult @@ -43,9 +41,6 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ private var timeRemaining: Long = 0 - private val pinEntryKeyboardType: PinKeyboardType - get() = PinKeyboardType.fromEditText(editText = binding.kbsLockPinInput) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setDebugLogSubmitMultiTapView(view.findViewById(R.id.kbs_lock_pin_title)) @@ -74,10 +69,7 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ handlePinEntry() } - binding.kbsLockKeyboardToggle.setOnClickListener { - updateKeyboard(newType = pinEntryKeyboardType.other) - } - updateKeyboard(newType = pinEntryKeyboardType) + binding.kbsLockKeyboardToggle.setOnClickListener { viewModel.togglePinKeyboardType() } viewModel.lockedTimeRemaining.observe(viewLifecycleOwner) { t: Long -> timeRemaining = t } @@ -114,6 +106,11 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ handleRegistrationErrorResponse(error) viewModel.registerAccountErrorShown() } + + it.pinKeyboardType.applyTo( + pinEditText = binding.kbsLockPinInput, + toggleTypeButton = binding.kbsLockKeyboardToggle + ) } } @@ -135,8 +132,6 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ return } - SignalStore.pin.keyboardType = pinEntryKeyboardType - binding.kbsLockPinConfirm.setSpinning() viewModel.verifyCodeAndRegisterAccountWithRegistrationLock(requireContext(), pin) @@ -263,13 +258,6 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_ ViewUtil.focusAndShowKeyboard(binding.kbsLockPinInput) } - private fun updateKeyboard(newType: PinKeyboardType) { - newType.applyTo( - pinEditText = binding.kbsLockPinInput, - toggleTypeButton = binding.kbsLockKeyboardToggle - ) - } - private fun sendEmailToSupport() { val subject = R.string.RegistrationLockFragment__signal_registration_need_help_with_pin_for_android_v2_pin diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinFragment.kt index d7f8eceaad..db576d44f8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinFragment.kt @@ -18,7 +18,6 @@ import org.thoughtcrime.securesms.LoggingFragment import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.ViewBinderDelegate import org.thoughtcrime.securesms.databinding.FragmentRegistrationPinRestoreEntryV2Binding -import org.thoughtcrime.securesms.lock.v2.PinKeyboardType import org.thoughtcrime.securesms.lock.v2.SvrConstants import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate @@ -42,9 +41,6 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration private val binding: FragmentRegistrationPinRestoreEntryV2Binding by ViewBinderDelegate(FragmentRegistrationPinRestoreEntryV2Binding::bind) - private val pinEntryKeyboardType: PinKeyboardType - get() = PinKeyboardType.fromEditText(editText = binding.pinRestorePinInput) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -72,10 +68,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration handlePinEntry() } - binding.pinRestoreKeyboardToggle.setOnClickListener { - updateKeyboard(newType = pinEntryKeyboardType.other) - } - updateKeyboard(newType = pinEntryKeyboardType) + binding.pinRestoreKeyboardToggle.setOnClickListener { reRegisterViewModel.toggleKeyboardType() } LiveDataUtil .combineLatest(registrationViewModel.uiState, reRegisterViewModel.uiState) { reg, rereg -> reg to rereg } @@ -97,6 +90,11 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration presentTriesRemaining(reRegisterState, state.svrTriesRemaining) } + reRegisterState.pinKeyboardType.applyTo( + pinEditText = binding.pinRestorePinInput, + toggleTypeButton = binding.pinRestoreKeyboardToggle + ) + state.registerAccountError?.let { error -> registrationErrorHandler(error) registrationViewModel.registerAccountErrorShown() @@ -194,13 +192,6 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration ViewUtil.focusAndShowKeyboard(binding.pinRestorePinInput) } - private fun updateKeyboard(newType: PinKeyboardType) { - newType.applyTo( - pinEditText = binding.pinRestorePinInput, - toggleTypeButton = binding.pinRestoreKeyboardToggle - ) - } - private fun onNeedHelpClicked() { Log.i(TAG, "User clicked need help dialog.") val message = if (reRegisterViewModel.isLocalVerification) R.string.ReRegisterWithPinFragment_need_help_local else R.string.PinRestoreEntryFragment_your_pin_is_a_d_digit_code diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinState.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinState.kt index 2557fc3273..b5de7f7853 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinState.kt @@ -5,8 +5,12 @@ package org.thoughtcrime.securesms.registrationv3.ui.reregisterwithpin +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.lock.v2.PinKeyboardType + data class ReRegisterWithPinState( val isLocalVerification: Boolean = false, val hasIncorrectGuess: Boolean = false, - val localPinMatches: Boolean = false + val localPinMatches: Boolean = false, + val pinKeyboardType: PinKeyboardType = SignalStore.pin.keyboardType ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinViewModel.kt index 63842b75cd..493a03b720 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/reregisterwithpin/ReRegisterWithPinViewModel.kt @@ -29,4 +29,10 @@ class ReRegisterWithPinViewModel : ViewModel() { it.copy(hasIncorrectGuess = true) } } + + fun toggleKeyboardType() { + store.update { previousState -> + previousState.copy(pinKeyboardType = previousState.pinKeyboardType.other) + } + } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsScreenTest.kt b/app/src/test/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsScreenTest.kt index a45fdd69d0..dbb2b2cb50 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsScreenTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsScreenTest.kt @@ -22,6 +22,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config +import org.thoughtcrime.securesms.lock.v2.PinKeyboardType @RunWith(RobolectricTestRunner::class) @Config(application = Application::class) @@ -364,6 +365,7 @@ class AccountSettingsScreenTest { private fun createState( hasPin: Boolean = true, + pinKeyboardType: PinKeyboardType = PinKeyboardType.NUMERIC, hasRestoredAep: Boolean = true, pinRemindersEnabled: Boolean = true, registrationLockEnabled: Boolean = true, @@ -373,6 +375,7 @@ class AccountSettingsScreenTest { ): AccountSettingsState { return AccountSettingsState( hasPin = hasPin, + pinKeyboardType = pinKeyboardType, hasRestoredAep = hasRestoredAep, pinRemindersEnabled = pinRemindersEnabled, registrationLockEnabled = registrationLockEnabled,