Fix progress display hiding way before registration navigation.

Fixes #13850
Closes #13898

Co-authored-by: Sagar <sagar.0dev@gmail.com>
This commit is contained in:
Cody Henthorne 2025-01-15 12:47:43 -05:00 committed by GitHub
parent 93604f53d4
commit e9d80f4379
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 78 additions and 127 deletions

View file

@ -81,7 +81,6 @@ internal class ConfirmSvrPinFragment : BaseSvrPinFragment<ConfirmSvrPinViewModel
SaveAnimation.NONE -> confirm.cancelSpinning()
SaveAnimation.LOADING -> confirm.setSpinning()
SaveAnimation.SUCCESS -> {
confirm.cancelSpinning()
requireActivity().setResult(Activity.RESULT_OK)
closeNavGraphBranch()
RegistrationUtil.maybeMarkRegistrationComplete()

View file

@ -83,7 +83,6 @@ class RegistrationActivity : BaseActivity() {
if (!needsProfile && !needsPin) {
sharedViewModel.completeRegistration()
}
sharedViewModel.setInProgress(false)
val startIntent = MainActivity.clearTop(this).apply {
if (needsPin) {

View file

@ -86,13 +86,8 @@ class RegistrationViewModel : ViewModel() {
private val password = Util.getSecret(18)
private val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
Log.w(TAG, "CoroutineExceptionHandler invoked.", exception)
store.update {
it.copy(
networkError = exception,
inProgress = false
)
}
Log.w(TAG, "CoroutineExceptionHandler invoked!")
handleGenericError(exception)
}
val uiState = store.asLiveData()
@ -238,8 +233,7 @@ class RegistrationViewModel : ViewModel() {
store.update {
it.copy(
canSkipSms = true,
isReRegister = true,
inProgress = false
isReRegister = true
)
}
return
@ -263,8 +257,7 @@ class RegistrationViewModel : ViewModel() {
isReRegister = true,
canSkipSms = true,
svr2AuthCredentials = svrCredentialsResult.svr2Credentials,
svr3AuthCredentials = svrCredentialsResult.svr3Credentials,
inProgress = false
svr3AuthCredentials = svrCredentialsResult.svr3Credentials
)
}
return@launch
@ -315,7 +308,7 @@ class RegistrationViewModel : ViewModel() {
if (e164 == null) {
Log.w(TAG, "Phone number was null after confirmation.")
onErrorOccurred()
setInProgress(false)
return
}
@ -404,8 +397,7 @@ class RegistrationViewModel : ViewModel() {
nextVerificationAttempt = RegistrationRepository.deriveTimestamp(networkResult.headers, networkResult.body.nextVerificationAttempt),
allowedToRequestCode = networkResult.body.allowedToRequestCode,
challengesRequested = Challenge.parse(networkResult.body.requestedInformation),
verified = networkResult.body.verified,
inProgress = false
verified = networkResult.body.verified
)
}
},
@ -451,12 +443,6 @@ class RegistrationViewModel : ViewModel() {
val session = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a push challenge token.") }
if (!Challenge.parse(session.body.requestedInformation).contains(Challenge.PUSH)) {
Log.d(TAG, "Push submission no longer necessary, bailing.")
store.update {
it.copy(
inProgress = false
)
}
return@launch bail { Log.i(TAG, "Push challenge token no longer needed, bailing.") }
}
@ -486,8 +472,7 @@ class RegistrationViewModel : ViewModel() {
nextSmsTimestamp = sessionResult.nextSmsTimestamp,
nextCallTimestamp = sessionResult.nextCallTimestamp,
isAllowedToRequestCode = sessionResult.allowedToRequestCode,
challengesRequested = emptyList(),
inProgress = false
challengesRequested = emptyList()
)
}
return true
@ -498,8 +483,7 @@ class RegistrationViewModel : ViewModel() {
store.update {
it.copy(
registrationCheckpoint = RegistrationCheckpoint.CHALLENGE_RECEIVED,
challengesRequested = sessionResult.challenges,
inProgress = false
challengesRequested = sessionResult.challenges
)
}
return false
@ -534,9 +518,10 @@ class RegistrationViewModel : ViewModel() {
is AlreadyVerified -> Log.i(TAG, "Received AlreadyVerified", sessionResult.getCause())
}
setInProgress(false)
store.update {
it.copy(
inProgress = false,
sessionStateError = sessionResult
)
}
@ -548,6 +533,7 @@ class RegistrationViewModel : ViewModel() {
*/
private suspend fun handleRegistrationResult(context: Context, registrationData: RegistrationData, registrationResult: RegisterAccountResult, reglockEnabled: Boolean): Boolean {
Log.v(TAG, "handleRegistrationResult()")
var stayInProgress = false
when (registrationResult) {
is RegisterAccountResult.Success -> {
Log.i(TAG, "Register account result: Success! Registration lock: $reglockEnabled")
@ -567,6 +553,7 @@ class RegistrationViewModel : ViewModel() {
is RegisterAccountResult.RegistrationLocked -> {
Log.i(TAG, "Account is registration locked!", registrationResult.getCause())
stayInProgress = true
}
is RegisterAccountResult.SvrWrongPin -> {
@ -582,9 +569,9 @@ class RegistrationViewModel : ViewModel() {
is RegisterAccountResult.ValidationError,
is RegisterAccountResult.UnknownError -> Log.i(TAG, "Received error when trying to register!", registrationResult.getCause())
}
setInProgress(false)
store.update {
it.copy(
inProgress = stayInProgress,
registerAccountError = registrationResult
)
}
@ -636,7 +623,6 @@ class RegistrationViewModel : ViewModel() {
updateSvrTriesRemaining(0)
setUserSkippedReRegisterFlow(true)
}
setInProgress(false)
}
return
}
@ -647,19 +633,17 @@ class RegistrationViewModel : ViewModel() {
Log.d(TAG, "Found recovery password, attempting to re-register.")
viewModelScope.launch(context = coroutineExceptionHandler) {
verifyReRegisterInternal(context, pin, SignalStore.svr.masterKey)
setInProgress(false)
}
} else {
Log.d(TAG, "Entered PIN did not match local PIN hash.")
wrongPinHandler()
setInProgress(false)
}
return
}
Log.w(TAG, "Could not get credentials to skip SMS registration, aborting!")
store.update {
it.copy(canSkipSms = false, inProgress = false)
it.copy(canSkipSms = false)
}
}
@ -857,8 +841,7 @@ class RegistrationViewModel : ViewModel() {
store.update {
it.copy(
registrationCheckpoint = RegistrationCheckpoint.LOCAL_REGISTRATION_COMPLETE,
inProgress = false
registrationCheckpoint = RegistrationCheckpoint.LOCAL_REGISTRATION_COMPLETE
)
}
}
@ -898,14 +881,6 @@ class RegistrationViewModel : ViewModel() {
return RegistrationData(code, e164, password, RegistrationRepository.getRegistrationId(), RegistrationRepository.getProfileKey(e164), currentState.fcmToken, RegistrationRepository.getPniRegistrationId(), recoveryPassword)
}
/**
* This is a generic error UI handler that re-enables the UI so that the user can recover from errors.
* Do not forget to log any errors when calling this method!
*/
private fun onErrorOccurred() {
setInProgress(false)
}
/**
* Used for early returns in order to end the in-progress visual state, as well as print a log message explaining what happened.
*

View file

@ -198,6 +198,7 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
object : AssertedSuccessListener<Boolean>() {
override fun onSuccess(result: Boolean?) {
findNavController().safeNavigate(EnterCodeFragmentDirections.actionRequireKbsLockPin(timeRemaining))
sharedViewModel.setInProgress(false)
}
}
)
@ -265,6 +266,7 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
private fun popBackStack() {
sharedViewModel.setRegistrationCheckpoint(RegistrationCheckpoint.PUSH_NETWORK_AUDITED)
NavHostFragment.findNavController(this).popBackStack()
sharedViewModel.setInProgress(false)
}
@Subscribe(threadMode = ThreadMode.MAIN)

View file

@ -35,6 +35,7 @@ import com.google.android.material.textfield.TextInputEditText
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber
import org.signal.core.util.ThreadUtil
import org.signal.core.util.isNotNullOrBlank
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.LoggingFragment
@ -114,7 +115,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
sharedViewModel.uiState.observe(viewLifecycleOwner) { sharedState ->
presentRegisterButton(sharedState)
presentProgressBar(sharedState.inProgress, sharedState.isReRegister)
updateEnabledControls(sharedState.inProgress, sharedState.isReRegister)
sharedState.networkError?.let {
presentNetworkError(it)
@ -400,6 +401,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
private fun presentRegistrationLocked(timeRemaining: Long) {
findNavController().safeNavigate(EnterPhoneNumberFragmentDirections.actionPhoneNumberRegistrationLock(timeRemaining))
sharedViewModel.setInProgress(false)
}
private fun presentRateLimitedDialog() {
@ -408,10 +410,12 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
private fun presentAccountLocked() {
findNavController().safeNavigate(EnterPhoneNumberFragmentDirections.actionPhoneNumberAccountLocked())
ThreadUtil.postToMain { sharedViewModel.setInProgress(false) }
}
private fun moveToCaptcha() {
findNavController().safeNavigate(EnterPhoneNumberFragmentDirections.actionRequestCaptcha())
ThreadUtil.postToMain { sharedViewModel.setInProgress(false) }
}
private fun presentRemoteErrorDialog(message: String, positiveButtonListener: DialogInterface.OnClickListener? = null) {
@ -491,12 +495,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
}
}
private fun presentProgressBar(showProgress: Boolean, isReRegister: Boolean) {
if (showProgress) {
binding.registerButton.setSpinning()
} else {
binding.registerButton.cancelSpinning()
}
private fun updateEnabledControls(showProgress: Boolean, isReRegister: Boolean) {
binding.countryCode.isEnabled = !showProgress
binding.number.isEnabled = !showProgress
binding.cancelButton.visible = !showProgress && isReRegister

View file

@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.registration.ui.RegistrationViewModel
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.SupportEmailUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration_pin_restore_entry_v2) {
@ -76,21 +77,24 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
binding.pinRestoreKeyboardToggle.setIconResource(getPinEntryKeyboardType().other.iconResource)
registrationViewModel.uiState.observe(viewLifecycleOwner, ::updateViewState)
LiveDataUtil
.combineLatest(registrationViewModel.uiState, reRegisterViewModel.uiState) { reg, rereg -> reg to rereg }
.observe(viewLifecycleOwner) { (registrationState, reRegisterState) -> updateViewState(registrationState, reRegisterState) }
}
private fun updateViewState(state: RegistrationState) {
private fun updateViewState(state: RegistrationState, reRegisterState: ReRegisterWithPinState) {
if (state.networkError != null) {
genericErrorDialog()
registrationViewModel.networkErrorShown()
} else if (!state.canSkipSms) {
findNavController().safeNavigate(ReRegisterWithPinFragmentDirections.actionReRegisterWithPinFragmentToEnterPhoneNumberFragment())
registrationViewModel.setInProgress(false)
} else if (state.isRegistrationLockEnabled && state.svrTriesRemaining == 0) {
Log.w(TAG, "Unable to continue skip flow, KBS is locked")
onAccountLocked()
} else {
presentProgress(state.inProgress)
presentTriesRemaining(state.svrTriesRemaining)
presentTriesRemaining(reRegisterState, state.svrTriesRemaining)
}
state.registerAccountError?.let { error ->
@ -131,14 +135,15 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
context = requireContext(),
pin = pin,
wrongPinHandler = {
registrationViewModel.setInProgress(false)
reRegisterViewModel.markIncorrectGuess()
}
)
}
private fun presentTriesRemaining(triesRemaining: Int) {
if (reRegisterViewModel.hasIncorrectGuess) {
if (triesRemaining == 1 && !reRegisterViewModel.isLocalVerification) {
private fun presentTriesRemaining(reRegisterState: ReRegisterWithPinState, triesRemaining: Int) {
if (reRegisterState.hasIncorrectGuess) {
if (triesRemaining == 1 && !reRegisterState.isLocalVerification) {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.PinRestoreEntryFragment_incorrect_pin)
.setMessage(resources.getQuantityString(R.plurals.PinRestoreEntryFragment_you_have_d_attempt_remaining, triesRemaining, triesRemaining))
@ -155,7 +160,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
} else {
if (triesRemaining == 1) {
binding.pinRestoreForgotPin.visibility = View.VISIBLE
if (!reRegisterViewModel.isLocalVerification) {
if (!reRegisterState.isLocalVerification) {
MaterialAlertDialogBuilder(requireContext())
.setMessage(resources.getQuantityString(R.plurals.PinRestoreEntryFragment_you_have_d_attempt_remaining, triesRemaining, triesRemaining))
.setPositiveButton(android.R.string.ok, null)

View file

@ -6,21 +6,17 @@
package org.thoughtcrime.securesms.registration.ui.reregisterwithpin
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import org.signal.core.util.logging.Log
class ReRegisterWithPinViewModel : ViewModel() {
companion object {
private val TAG = Log.tag(ReRegisterWithPinViewModel::class.java)
}
private val store = MutableStateFlow(ReRegisterWithPinState())
val uiState = store.asLiveData()
val isLocalVerification: Boolean
get() = store.value.isLocalVerification
val hasIncorrectGuess: Boolean
get() = store.value.hasIncorrectGuess
fun markAsRemoteVerification() {
store.update {

View file

@ -83,7 +83,6 @@ class RegistrationActivity : BaseActivity() {
if (!needsProfile && !needsPin) {
sharedViewModel.completeRegistration()
}
sharedViewModel.setInProgress(false)
val startIntent = MainActivity.clearTop(this)

View file

@ -90,13 +90,8 @@ class RegistrationViewModel : ViewModel() {
private val password = Util.getSecret(18)
private val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
Log.w(TAG, "CoroutineExceptionHandler invoked.", exception)
store.update {
it.copy(
networkError = exception,
inProgress = false
)
}
Log.w(TAG, "CoroutineExceptionHandler invoked!")
handleGenericError(exception)
}
val state: StateFlow<RegistrationState> = store
@ -244,8 +239,7 @@ class RegistrationViewModel : ViewModel() {
store.update {
it.copy(
canSkipSms = true,
isReRegister = true,
inProgress = false
isReRegister = true
)
}
return
@ -269,8 +263,7 @@ class RegistrationViewModel : ViewModel() {
isReRegister = true,
canSkipSms = true,
svr2AuthCredentials = svrCredentialsResult.svr2Credentials,
svr3AuthCredentials = svrCredentialsResult.svr3Credentials,
inProgress = false
svr3AuthCredentials = svrCredentialsResult.svr3Credentials
)
}
return@launch
@ -321,7 +314,7 @@ class RegistrationViewModel : ViewModel() {
if (e164 == null) {
Log.w(TAG, "Phone number was null after confirmation.")
onErrorOccurred()
setInProgress(false)
return
}
@ -410,8 +403,7 @@ class RegistrationViewModel : ViewModel() {
nextVerificationAttempt = RegistrationRepository.deriveTimestamp(networkResult.headers, networkResult.body.nextVerificationAttempt),
allowedToRequestCode = networkResult.body.allowedToRequestCode,
challengesRequested = Challenge.parse(networkResult.body.requestedInformation),
verified = networkResult.body.verified,
inProgress = false
verified = networkResult.body.verified
)
}
},
@ -457,12 +449,6 @@ class RegistrationViewModel : ViewModel() {
val session = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a push challenge token.") }
if (!Challenge.parse(session.body.requestedInformation).contains(Challenge.PUSH)) {
Log.d(TAG, "Push submission no longer necessary, bailing.")
store.update {
it.copy(
inProgress = false
)
}
return@launch bail { Log.i(TAG, "Push challenge token no longer needed, bailing.") }
}
@ -492,8 +478,7 @@ class RegistrationViewModel : ViewModel() {
nextSmsTimestamp = sessionResult.nextSmsTimestamp,
nextCallTimestamp = sessionResult.nextCallTimestamp,
isAllowedToRequestCode = sessionResult.allowedToRequestCode,
challengesRequested = emptyList(),
inProgress = false
challengesRequested = emptyList()
)
}
return true
@ -504,8 +489,7 @@ class RegistrationViewModel : ViewModel() {
store.update {
it.copy(
registrationCheckpoint = RegistrationCheckpoint.CHALLENGE_RECEIVED,
challengesRequested = sessionResult.challenges,
inProgress = false
challengesRequested = sessionResult.challenges
)
}
return false
@ -540,10 +524,11 @@ class RegistrationViewModel : ViewModel() {
is AlreadyVerified -> Log.i(TAG, "Received AlreadyVerified", sessionResult.getCause())
}
setInProgress(false)
store.update {
it.copy(
sessionStateError = sessionResult
sessionStateError = sessionResult,
inProgress = false
)
}
return false
@ -554,6 +539,7 @@ class RegistrationViewModel : ViewModel() {
*/
private suspend fun handleRegistrationResult(context: Context, registrationData: RegistrationData, registrationResult: RegisterAccountResult, reglockEnabled: Boolean): Boolean {
Log.v(TAG, "handleRegistrationResult()")
var stayInProgress = false
when (registrationResult) {
is RegisterAccountResult.Success -> {
Log.i(TAG, "Register account result: Success! Registration lock: $reglockEnabled")
@ -573,6 +559,7 @@ class RegistrationViewModel : ViewModel() {
is RegisterAccountResult.RegistrationLocked -> {
Log.i(TAG, "Account is registration locked!", registrationResult.getCause())
stayInProgress = true
}
is RegisterAccountResult.SvrWrongPin -> {
@ -588,10 +575,10 @@ class RegistrationViewModel : ViewModel() {
is RegisterAccountResult.ValidationError,
is RegisterAccountResult.UnknownError -> Log.i(TAG, "Received error when trying to register!", registrationResult.getCause())
}
setInProgress(false)
store.update {
it.copy(
registerAccountError = registrationResult
registerAccountError = registrationResult,
inProgress = stayInProgress
)
}
return false
@ -649,7 +636,6 @@ class RegistrationViewModel : ViewModel() {
updateSvrTriesRemaining(0)
setUserSkippedReRegisterFlow(true)
}
setInProgress(false)
}
return
}
@ -662,19 +648,17 @@ class RegistrationViewModel : ViewModel() {
val masterKey = SignalStore.svr.masterKey
setRecoveryPassword(masterKey.deriveRegistrationRecoveryPassword())
verifyReRegisterInternal(context, pin, masterKey)
setInProgress(false)
}
} else {
Log.d(TAG, "Entered PIN did not match local PIN hash.")
wrongPinHandler()
setInProgress(false)
}
return
}
Log.w(TAG, "Could not get credentials to skip SMS registration, aborting!")
store.update {
it.copy(canSkipSms = false, inProgress = false)
it.copy(canSkipSms = false)
}
}
@ -875,8 +859,7 @@ class RegistrationViewModel : ViewModel() {
store.update {
it.copy(
registrationCheckpoint = RegistrationCheckpoint.LOCAL_REGISTRATION_COMPLETE,
inProgress = false
registrationCheckpoint = RegistrationCheckpoint.LOCAL_REGISTRATION_COMPLETE
)
}
}
@ -916,14 +899,6 @@ class RegistrationViewModel : ViewModel() {
return RegistrationData(code, e164, password, RegistrationRepository.getRegistrationId(), RegistrationRepository.getProfileKey(e164), currentState.fcmToken, RegistrationRepository.getPniRegistrationId(), recoveryPassword)
}
/**
* This is a generic error UI handler that re-enables the UI so that the user can recover from errors.
* Do not forget to log any errors when calling this method!
*/
private fun onErrorOccurred() {
setInProgress(false)
}
/**
* Used for early returns in order to end the in-progress visual state, as well as print a log message explaining what happened.
*

View file

@ -198,6 +198,7 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
object : AssertedSuccessListener<Boolean>() {
override fun onSuccess(result: Boolean?) {
findNavController().safeNavigate(EnterCodeFragmentDirections.actionRequireKbsLockPin(timeRemaining))
sharedViewModel.setInProgress(false)
}
}
)
@ -265,6 +266,7 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
private fun popBackStack() {
sharedViewModel.setRegistrationCheckpoint(RegistrationCheckpoint.PUSH_NETWORK_AUDITED)
NavHostFragment.findNavController(this).popBackStack()
sharedViewModel.setInProgress(false)
}
@Subscribe(threadMode = ThreadMode.MAIN)

View file

@ -36,6 +36,7 @@ import com.google.android.material.textfield.TextInputEditText
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber
import org.signal.core.util.ThreadUtil
import org.signal.core.util.isNotNullOrBlank
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.LoggingFragment
@ -119,7 +120,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
sharedViewModel.uiState.observe(viewLifecycleOwner) { sharedState ->
presentRegisterButton(sharedState)
presentProgressBar(sharedState.inProgress, sharedState.isReRegister)
updateEnabledControls(sharedState.inProgress, sharedState.isReRegister)
sharedState.networkError?.let {
presentNetworkError(it)
@ -412,6 +413,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
private fun presentRegistrationLocked(timeRemaining: Long) {
findNavController().safeNavigate(EnterPhoneNumberFragmentDirections.actionPhoneNumberRegistrationLock(timeRemaining))
sharedViewModel.setInProgress(false)
}
private fun presentRateLimitedDialog() {
@ -420,10 +422,12 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
private fun presentAccountLocked() {
findNavController().safeNavigate(EnterPhoneNumberFragmentDirections.actionPhoneNumberAccountLocked())
ThreadUtil.postToMain { sharedViewModel.setInProgress(false) }
}
private fun moveToCaptcha() {
findNavController().safeNavigate(EnterPhoneNumberFragmentDirections.actionRequestCaptcha())
ThreadUtil.postToMain { sharedViewModel.setInProgress(false) }
}
private fun presentRemoteErrorDialog(message: String, positiveButtonListener: DialogInterface.OnClickListener? = null) {
@ -513,12 +517,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
}
}
private fun presentProgressBar(showProgress: Boolean, isReRegister: Boolean) {
if (showProgress) {
binding.registerButton.setSpinning()
} else {
binding.registerButton.cancelSpinning()
}
private fun updateEnabledControls(showProgress: Boolean, isReRegister: Boolean) {
binding.countryCode.isEnabled = !showProgress
binding.number.isEnabled = !showProgress
binding.cancelButton.visible = !showProgress && isReRegister

View file

@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.registrationv3.ui.phonenumber.EnterPhoneNumber
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.SupportEmailUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration_pin_restore_entry_v2) {
@ -77,21 +78,24 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
binding.pinRestoreKeyboardToggle.setIconResource(getPinEntryKeyboardType().other.iconResource)
registrationViewModel.uiState.observe(viewLifecycleOwner, ::updateViewState)
LiveDataUtil
.combineLatest(registrationViewModel.uiState, reRegisterViewModel.uiState) { reg, rereg -> reg to rereg }
.observe(viewLifecycleOwner) { (registrationState, reRegisterState) -> updateViewState(registrationState, reRegisterState) }
}
private fun updateViewState(state: RegistrationState) {
private fun updateViewState(state: RegistrationState, reRegisterState: ReRegisterWithPinState) {
if (state.networkError != null) {
genericErrorDialog()
registrationViewModel.networkErrorShown()
} else if (!state.canSkipSms) {
findNavController().safeNavigate(ReRegisterWithPinFragmentDirections.actionReRegisterWithPinFragmentToEnterPhoneNumberFragment(EnterPhoneNumberMode.NORMAL))
registrationViewModel.setInProgress(false)
} else if (state.isRegistrationLockEnabled && state.svrTriesRemaining == 0) {
Log.w(TAG, "Unable to continue skip flow, KBS is locked")
onAccountLocked()
} else {
presentProgress(state.inProgress)
presentTriesRemaining(state.svrTriesRemaining)
presentTriesRemaining(reRegisterState, state.svrTriesRemaining)
}
state.registerAccountError?.let { error ->
@ -132,14 +136,15 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
context = requireContext(),
pin = pin,
wrongPinHandler = {
registrationViewModel.setInProgress(false)
reRegisterViewModel.markIncorrectGuess()
}
)
}
private fun presentTriesRemaining(triesRemaining: Int) {
if (reRegisterViewModel.hasIncorrectGuess) {
if (triesRemaining == 1 && !reRegisterViewModel.isLocalVerification) {
private fun presentTriesRemaining(reRegisterState: ReRegisterWithPinState, triesRemaining: Int) {
if (reRegisterState.hasIncorrectGuess) {
if (triesRemaining == 1 && !reRegisterState.isLocalVerification) {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.PinRestoreEntryFragment_incorrect_pin)
.setMessage(resources.getQuantityString(R.plurals.PinRestoreEntryFragment_you_have_d_attempt_remaining, triesRemaining, triesRemaining))
@ -156,7 +161,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
} else {
if (triesRemaining == 1) {
binding.pinRestoreForgotPin.visibility = View.VISIBLE
if (!reRegisterViewModel.isLocalVerification) {
if (!reRegisterState.isLocalVerification) {
MaterialAlertDialogBuilder(requireContext())
.setMessage(resources.getQuantityString(R.plurals.PinRestoreEntryFragment_you_have_d_attempt_remaining, triesRemaining, triesRemaining))
.setPositiveButton(android.R.string.ok, null)

View file

@ -6,21 +6,17 @@
package org.thoughtcrime.securesms.registrationv3.ui.reregisterwithpin
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import org.signal.core.util.logging.Log
class ReRegisterWithPinViewModel : ViewModel() {
companion object {
private val TAG = Log.tag(ReRegisterWithPinViewModel::class.java)
}
private val store = MutableStateFlow(ReRegisterWithPinState())
val uiState = store.asLiveData()
val isLocalVerification: Boolean
get() = store.value.isLocalVerification
val hasIncorrectGuess: Boolean
get() = store.value.hasIncorrectGuess
fun markAsRemoteVerification() {
store.update {