mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Convert registration error handling from callbacks to observers.
This commit is contained in:
@@ -11,6 +11,9 @@ import com.google.i18n.phonenumbers.Phonenumber
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||
import org.whispersystems.signalservice.api.svr.Svr3Credentials
|
||||
import org.whispersystems.signalservice.internal.push.AuthCredentials
|
||||
|
||||
@@ -45,7 +48,10 @@ data class RegistrationState(
|
||||
val verified: Boolean = false,
|
||||
val smsListenerTimeout: Long = 0L,
|
||||
val registrationCheckpoint: RegistrationCheckpoint = RegistrationCheckpoint.INITIALIZATION,
|
||||
val networkError: Throwable? = null
|
||||
val networkError: Throwable? = null,
|
||||
val sessionCreationError: RegistrationSessionResult? = null,
|
||||
val sessionStateError: VerificationCodeRequestResult? = null,
|
||||
val registerAccountError: RegisterAccountResult? = null
|
||||
) {
|
||||
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ import org.thoughtcrime.securesms.registration.data.RegistrationRepository
|
||||
import org.thoughtcrime.securesms.registration.data.network.BackupAuthCheckResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionCheckResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionCreationResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.AlreadyVerified
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.AttemptsExhausted
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.ChallengeRequired
|
||||
@@ -96,8 +96,6 @@ class RegistrationViewModel : ViewModel() {
|
||||
|
||||
val incorrectCodeAttempts = store.map { it.incorrectCodeAttempts }.asLiveData()
|
||||
|
||||
val inProgress = store.map { it.inProgress }.asLiveData()
|
||||
|
||||
val svrTriesRemaining: Int
|
||||
get() = store.value.svrTriesRemaining
|
||||
|
||||
@@ -158,6 +156,24 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun sessionCreationErrorShown() {
|
||||
store.update {
|
||||
it.copy(sessionCreationError = null)
|
||||
}
|
||||
}
|
||||
|
||||
fun sessionStateErrorShown() {
|
||||
store.update {
|
||||
it.copy(sessionStateError = null)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerAccountErrorShown() {
|
||||
store.update {
|
||||
it.copy(registerAccountError = null)
|
||||
}
|
||||
}
|
||||
|
||||
fun incrementIncorrectCodeAttempts() {
|
||||
store.update {
|
||||
it.copy(incorrectCodeAttempts = it.incorrectCodeAttempts + 1)
|
||||
@@ -202,7 +218,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun onUserConfirmedPhoneNumber(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
||||
fun onUserConfirmedPhoneNumber(context: Context) {
|
||||
setRegistrationCheckpoint(RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED)
|
||||
val state = store.value
|
||||
|
||||
@@ -253,11 +269,11 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
val validSession = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for confirming the entered E164.") }
|
||||
val validSession = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for confirming the entered E164.") }
|
||||
|
||||
if (validSession.body.verified) {
|
||||
Log.i(TAG, "Session is already verified, registering account.")
|
||||
registerVerifiedSession(context, validSession.body.id, errorHandler)
|
||||
registerVerifiedSession(context, validSession.body.id)
|
||||
return@launch
|
||||
}
|
||||
|
||||
@@ -269,25 +285,25 @@ class RegistrationViewModel : ViewModel() {
|
||||
} else {
|
||||
val challenges = validSession.body.requestedInformation
|
||||
Log.i(TAG, "Not allowed to request code! Remaining challenges: ${challenges.joinToString()}")
|
||||
handleSessionStateResult(context, ChallengeRequired(Challenge.parse(validSession.body.requestedInformation)), errorHandler)
|
||||
handleSessionStateResult(context, ChallengeRequired(Challenge.parse(validSession.body.requestedInformation)))
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
requestSmsCodeInternal(context, validSession.body.id, e164, errorHandler)
|
||||
requestSmsCodeInternal(context, validSession.body.id, e164)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestSmsCode(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
||||
fun requestSmsCode(context: Context) {
|
||||
val e164 = getCurrentE164() ?: return bail { Log.i(TAG, "Phone number was null after confirmation.") }
|
||||
|
||||
viewModelScope.launch {
|
||||
val validSession = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for requesting an SMS code.") }
|
||||
requestSmsCodeInternal(context, validSession.body.id, e164, errorHandler)
|
||||
val validSession = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for requesting an SMS code.") }
|
||||
requestSmsCodeInternal(context, validSession.body.id, e164)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestVerificationCall(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
||||
fun requestVerificationCall(context: Context) {
|
||||
val e164 = getCurrentE164()
|
||||
|
||||
if (e164 == null) {
|
||||
@@ -297,7 +313,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
val validSession = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for requesting a verification call.") }
|
||||
val validSession = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for requesting a verification call.") }
|
||||
Log.d(TAG, "Requesting voice call code…")
|
||||
val codeRequestResponse = RegistrationRepository.requestSmsCode(
|
||||
context = context,
|
||||
@@ -308,14 +324,14 @@ class RegistrationViewModel : ViewModel() {
|
||||
)
|
||||
Log.d(TAG, "Voice code request network call completed.")
|
||||
|
||||
handleSessionStateResult(context, codeRequestResponse, errorHandler)
|
||||
handleSessionStateResult(context, codeRequestResponse)
|
||||
if (codeRequestResponse is Success) {
|
||||
Log.d(TAG, "Voice code request was successful.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun requestSmsCodeInternal(context: Context, sessionId: String, e164: String, errorHandler: (RegistrationResult) -> Unit) {
|
||||
private suspend fun requestSmsCodeInternal(context: Context, sessionId: String, e164: String) {
|
||||
var smsListenerReady = false
|
||||
Log.d(TAG, "Initializing SMS listener.")
|
||||
if (store.value.smsListenerTimeout < System.currentTimeMillis()) {
|
||||
@@ -341,7 +357,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
)
|
||||
Log.d(TAG, "SMS code request network call completed.")
|
||||
|
||||
handleSessionStateResult(context, codeRequestResponse, errorHandler)
|
||||
handleSessionStateResult(context, codeRequestResponse)
|
||||
|
||||
if (codeRequestResponse is Success) {
|
||||
Log.d(TAG, "SMS code request was successful.")
|
||||
@@ -353,7 +369,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getOrCreateValidSession(context: Context, errorHandler: (RegistrationResult) -> Unit): RegistrationSessionMetadataResponse? {
|
||||
private suspend fun getOrCreateValidSession(context: Context): RegistrationSessionMetadataResponse? {
|
||||
Log.v(TAG, "getOrCreateValidSession()")
|
||||
val e164 = getCurrentE164() ?: throw IllegalStateException("E164 required to create session!")
|
||||
val mccMncProducer = MccMncProducer(context)
|
||||
@@ -379,11 +395,17 @@ class RegistrationViewModel : ViewModel() {
|
||||
)
|
||||
}
|
||||
},
|
||||
errorHandler = errorHandler
|
||||
errorHandler = { error ->
|
||||
store.update {
|
||||
it.copy(
|
||||
sessionCreationError = error
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun submitCaptchaToken(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
||||
fun submitCaptchaToken(context: Context) {
|
||||
val e164 = getCurrentE164() ?: throw IllegalStateException("Can't submit captcha token if no phone number is set!")
|
||||
val captchaToken = store.value.captchaToken ?: throw IllegalStateException("Can't submit captcha token if no captcha token is set!")
|
||||
|
||||
@@ -392,16 +414,16 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
val session = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a captcha token.") }
|
||||
val session = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a captcha token.") }
|
||||
Log.d(TAG, "Submitting captcha token…")
|
||||
val captchaSubmissionResult = RegistrationRepository.submitCaptchaToken(context, e164, password, session.body.id, captchaToken)
|
||||
Log.d(TAG, "Captcha token submitted.")
|
||||
|
||||
handleSessionStateResult(context, captchaSubmissionResult, errorHandler)
|
||||
handleSessionStateResult(context, captchaSubmissionResult)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestAndSubmitPushToken(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
||||
fun requestAndSubmitPushToken(context: Context) {
|
||||
Log.v(TAG, "validatePushToken()")
|
||||
|
||||
addPresentedChallenge(Challenge.PUSH)
|
||||
@@ -410,7 +432,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
|
||||
viewModelScope.launch {
|
||||
Log.d(TAG, "Getting session in order to perform push token verification…")
|
||||
val session = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a push challenge token.") }
|
||||
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.")
|
||||
@@ -425,14 +447,14 @@ class RegistrationViewModel : ViewModel() {
|
||||
Log.d(TAG, "Requesting push challenge token…")
|
||||
val pushSubmissionResult = RegistrationRepository.requestAndVerifyPushToken(context, session.body.id, e164, password)
|
||||
Log.d(TAG, "Push challenge token submitted.")
|
||||
handleSessionStateResult(context, pushSubmissionResult, errorHandler)
|
||||
handleSessionStateResult(context, pushSubmissionResult)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the request was successful and execution should continue
|
||||
*/
|
||||
private suspend fun handleSessionStateResult(context: Context, sessionResult: RegistrationResult, errorHandler: (RegistrationResult) -> Unit): Boolean {
|
||||
private suspend fun handleSessionStateResult(context: Context, sessionResult: VerificationCodeRequestResult): Boolean {
|
||||
Log.v(TAG, "handleSessionStateResult()")
|
||||
when (sessionResult) {
|
||||
is UnknownError -> {
|
||||
@@ -492,14 +514,18 @@ class RegistrationViewModel : ViewModel() {
|
||||
is AlreadyVerified -> Log.i(TAG, "Received AlreadyVerified", sessionResult.getCause())
|
||||
}
|
||||
setInProgress(false)
|
||||
errorHandler(sessionResult)
|
||||
store.update {
|
||||
it.copy(
|
||||
sessionStateError = sessionResult
|
||||
)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the request was successful and execution should continue
|
||||
*/
|
||||
private suspend fun handleRegistrationResult(context: Context, registrationData: RegistrationData, registrationResult: RegisterAccountResult, reglockEnabled: Boolean, errorHandler: (RegisterAccountResult) -> Unit): Boolean {
|
||||
private suspend fun handleRegistrationResult(context: Context, registrationData: RegistrationData, registrationResult: RegisterAccountResult, reglockEnabled: Boolean): Boolean {
|
||||
Log.v(TAG, "handleRegistrationResult()")
|
||||
when (registrationResult) {
|
||||
is RegisterAccountResult.Success -> {
|
||||
@@ -521,6 +547,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
is RegisterAccountResult.RegistrationLocked -> {
|
||||
Log.i(TAG, "Account is registration locked!", registrationResult.getCause())
|
||||
}
|
||||
|
||||
is RegisterAccountResult.SvrWrongPin -> {
|
||||
Log.i(TAG, "Received wrong SVR PIN response! ${registrationResult.triesRemaining} tries remaining.")
|
||||
updateSvrTriesRemaining(registrationResult.triesRemaining)
|
||||
@@ -535,7 +562,11 @@ class RegistrationViewModel : ViewModel() {
|
||||
is RegisterAccountResult.UnknownError -> Log.i(TAG, "Received error when trying to register!", registrationResult.getCause())
|
||||
}
|
||||
setInProgress(false)
|
||||
errorHandler(registrationResult)
|
||||
store.update {
|
||||
it.copy(
|
||||
registerAccountError = registrationResult
|
||||
)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -564,7 +595,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun verifyReRegisterWithPin(context: Context, pin: String, wrongPinHandler: () -> Unit, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
||||
fun verifyReRegisterWithPin(context: Context, pin: String, wrongPinHandler: () -> Unit) {
|
||||
setInProgress(true)
|
||||
|
||||
// Local recovery password
|
||||
@@ -572,7 +603,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
if (RegistrationRepository.doesPinMatchLocalHash(pin)) {
|
||||
Log.d(TAG, "Found recovery password, attempting to re-register.")
|
||||
viewModelScope.launch(context = coroutineExceptionHandler) {
|
||||
verifyReRegisterInternal(context, pin, SignalStore.svr.getOrCreateMasterKey(), registrationErrorHandler)
|
||||
verifyReRegisterInternal(context, pin, SignalStore.svr.getOrCreateMasterKey())
|
||||
setInProgress(false)
|
||||
}
|
||||
} else {
|
||||
@@ -594,7 +625,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
val masterKey = RegistrationRepository.fetchMasterKeyFromSvrRemote(pin, svr2Credentials, svr3Credentials)
|
||||
setRecoveryPassword(masterKey.deriveRegistrationRecoveryPassword())
|
||||
updateSvrTriesRemaining(10)
|
||||
verifyReRegisterInternal(context, pin, masterKey, registrationErrorHandler)
|
||||
verifyReRegisterInternal(context, pin, masterKey)
|
||||
} catch (rejectedPin: SvrWrongPinException) {
|
||||
Log.w(TAG, "Submitted PIN was rejected by SVR.", rejectedPin)
|
||||
updateSvrTriesRemaining(rejectedPin.triesRemaining)
|
||||
@@ -615,7 +646,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun verifyReRegisterInternal(context: Context, pin: String, masterKey: MasterKey, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
||||
private suspend fun verifyReRegisterInternal(context: Context, pin: String, masterKey: MasterKey) {
|
||||
Log.v(TAG, "verifyReRegisterInternal()")
|
||||
updateFcmToken(context)
|
||||
|
||||
@@ -625,7 +656,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
val result = resultAndRegLockStatus.first
|
||||
val reglockEnabled = resultAndRegLockStatus.second
|
||||
|
||||
handleRegistrationResult(context, registrationData, result, reglockEnabled, registrationErrorHandler)
|
||||
handleRegistrationResult(context, registrationData, result, reglockEnabled)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -652,7 +683,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
return Pair(RegistrationRepository.registerAccount(context = context, sessionId = sessionId, registrationData = registrationData, pin = pin) { masterKey }, true)
|
||||
}
|
||||
|
||||
fun verifyCodeWithoutRegistrationLock(context: Context, code: String, submissionErrorHandler: (RegistrationResult) -> Unit, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
||||
fun verifyCodeWithoutRegistrationLock(context: Context, code: String) {
|
||||
Log.v(TAG, "verifyCodeWithoutRegistrationLock()")
|
||||
store.update {
|
||||
it.copy(
|
||||
@@ -665,15 +696,13 @@ class RegistrationViewModel : ViewModel() {
|
||||
viewModelScope.launch(context = coroutineExceptionHandler) {
|
||||
verifyCodeInternal(
|
||||
context = context,
|
||||
pin = null,
|
||||
registrationLocked = false,
|
||||
submissionErrorHandler = submissionErrorHandler,
|
||||
registrationErrorHandler = registrationErrorHandler
|
||||
pin = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun verifyCodeAndRegisterAccountWithRegistrationLock(context: Context, pin: String, submissionErrorHandler: (RegistrationResult) -> Unit, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
||||
fun verifyCodeAndRegisterAccountWithRegistrationLock(context: Context, pin: String) {
|
||||
Log.v(TAG, "verifyCodeAndRegisterAccountWithRegistrationLock()")
|
||||
store.update {
|
||||
it.copy(
|
||||
@@ -684,15 +713,13 @@ class RegistrationViewModel : ViewModel() {
|
||||
viewModelScope.launch {
|
||||
verifyCodeInternal(
|
||||
context = context,
|
||||
pin = pin,
|
||||
registrationLocked = true,
|
||||
submissionErrorHandler = submissionErrorHandler,
|
||||
registrationErrorHandler = registrationErrorHandler
|
||||
pin = pin
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun verifyCodeInternal(context: Context, registrationLocked: Boolean, pin: String?, submissionErrorHandler: (RegistrationResult) -> Unit, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
||||
private suspend fun verifyCodeInternal(context: Context, registrationLocked: Boolean, pin: String?) {
|
||||
Log.d(TAG, "Getting valid session in order to submit verification code.")
|
||||
|
||||
if (registrationLocked && pin.isNullOrBlank()) {
|
||||
@@ -701,7 +728,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
|
||||
var reglock = registrationLocked
|
||||
|
||||
val sessionId = getOrCreateValidSession(context, submissionErrorHandler)?.body?.id ?: return
|
||||
val sessionId = getOrCreateValidSession(context)?.body?.id ?: return
|
||||
val registrationData = getRegistrationData()
|
||||
|
||||
Log.d(TAG, "Submitting verification code…")
|
||||
@@ -714,7 +741,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
Log.d(TAG, "Verification code submission network call completed. Submission successful? $submissionSuccessful Account already verified? $alreadyVerified")
|
||||
|
||||
if (!submissionSuccessful && !alreadyVerified) {
|
||||
handleSessionStateResult(context, verificationResponse, submissionErrorHandler)
|
||||
handleSessionStateResult(context, verificationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -758,16 +785,16 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
handleRegistrationResult(context, registrationData, result, reglock, registrationErrorHandler)
|
||||
handleRegistrationResult(context, registrationData, result, reglock)
|
||||
} else {
|
||||
Log.w(TAG, "No registration response received!")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun registerVerifiedSession(context: Context, sessionId: String, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
||||
private suspend fun registerVerifiedSession(context: Context, sessionId: String) {
|
||||
val registrationData = getRegistrationData()
|
||||
val registrationResponse: RegisterAccountResult = RegistrationRepository.registerAccount(context, sessionId, registrationData)
|
||||
handleRegistrationResult(context, registrationData, registrationResponse, false, registrationErrorHandler)
|
||||
handleRegistrationResult(context, registrationData, registrationResponse, false)
|
||||
}
|
||||
|
||||
private suspend fun onSuccessfulRegistration(context: Context, registrationData: RegistrationData, remoteResult: RegistrationRepository.AccountRegistrationResult, reglockEnabled: Boolean) {
|
||||
@@ -813,7 +840,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
RegistrationUtil.maybeMarkRegistrationComplete()
|
||||
}
|
||||
|
||||
fun clearNetworkError() {
|
||||
fun networkErrorShown() {
|
||||
store.update {
|
||||
it.copy(networkError = null)
|
||||
}
|
||||
|
||||
@@ -11,12 +11,10 @@ import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import org.signal.core.util.logging.Log
|
||||
@@ -76,7 +74,7 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
}
|
||||
|
||||
binding.code.setOnCompleteListener {
|
||||
sharedViewModel.verifyCodeWithoutRegistrationLock(requireContext(), it, ::handleSessionErrorResponse, ::handleRegistrationErrorResponse)
|
||||
sharedViewModel.verifyCodeWithoutRegistrationLock(requireContext(), it)
|
||||
}
|
||||
|
||||
binding.havingTroubleButton.setOnClickListener {
|
||||
@@ -86,14 +84,14 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
binding.callMeCountDown.apply {
|
||||
setTextResources(R.string.RegistrationActivity_call, R.string.RegistrationActivity_call_me_instead_available_in)
|
||||
setOnClickListener {
|
||||
sharedViewModel.requestVerificationCall(requireContext(), ::handleSessionErrorResponse)
|
||||
sharedViewModel.requestVerificationCall(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
binding.resendSmsCountDown.apply {
|
||||
setTextResources(R.string.RegistrationActivity_resend_code, R.string.RegistrationActivity_resend_sms_available_in)
|
||||
setOnClickListener {
|
||||
sharedViewModel.requestSmsCode(requireContext(), ::handleSessionErrorResponse)
|
||||
sharedViewModel.requestSmsCode(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +112,16 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
}
|
||||
|
||||
sharedViewModel.uiState.observe(viewLifecycleOwner) {
|
||||
it.sessionStateError?.let { error ->
|
||||
handleSessionErrorResponse(error)
|
||||
sharedViewModel.sessionStateErrorShown()
|
||||
}
|
||||
|
||||
it.registerAccountError?.let { error ->
|
||||
handleRegistrationErrorResponse(error)
|
||||
sharedViewModel.registerAccountErrorShown()
|
||||
}
|
||||
|
||||
binding.resendSmsCountDown.startCountDownTo(it.nextSmsTimestamp)
|
||||
binding.callMeCountDown.startCountDownTo(it.nextCallTimestamp)
|
||||
if (it.inProgress) {
|
||||
@@ -132,29 +140,25 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSessionErrorResponse(result: RegistrationResult) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
when (result) {
|
||||
is VerificationCodeRequestResult.Success -> binding.keyboard.displaySuccess()
|
||||
is VerificationCodeRequestResult.RateLimited -> presentRateLimitedDialog()
|
||||
is VerificationCodeRequestResult.AttemptsExhausted -> presentAccountLocked()
|
||||
is VerificationCodeRequestResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
||||
else -> presentGenericError(result)
|
||||
}
|
||||
private fun handleSessionErrorResponse(result: VerificationCodeRequestResult) {
|
||||
when (result) {
|
||||
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||
is VerificationCodeRequestResult.RateLimited -> presentRateLimitedDialog()
|
||||
is VerificationCodeRequestResult.AttemptsExhausted -> presentAccountLocked()
|
||||
is VerificationCodeRequestResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
||||
else -> presentGenericError(result)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRegistrationErrorResponse(result: RegisterAccountResult) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
when (result) {
|
||||
is RegisterAccountResult.Success -> binding.keyboard.displaySuccess()
|
||||
is RegisterAccountResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
||||
is RegisterAccountResult.AuthorizationFailed -> presentIncorrectCodeDialog()
|
||||
is RegisterAccountResult.AttemptsExhausted -> presentAccountLocked()
|
||||
is RegisterAccountResult.RateLimited -> presentRateLimitedDialog()
|
||||
when (result) {
|
||||
is RegisterAccountResult.Success -> throw IllegalStateException("Register account error handler called on successful response!")
|
||||
is RegisterAccountResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
||||
is RegisterAccountResult.AuthorizationFailed -> presentIncorrectCodeDialog()
|
||||
is RegisterAccountResult.AttemptsExhausted -> presentAccountLocked()
|
||||
is RegisterAccountResult.RateLimited -> presentRateLimitedDialog()
|
||||
|
||||
else -> presentGenericError(result)
|
||||
}
|
||||
else -> presentGenericError(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,19 +206,17 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
private fun presentIncorrectCodeDialog() {
|
||||
sharedViewModel.incrementIncorrectCodeAttempts()
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
Toast.makeText(requireContext(), R.string.RegistrationActivity_incorrect_code, Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(requireContext(), R.string.RegistrationActivity_incorrect_code, Toast.LENGTH_LONG).show()
|
||||
|
||||
binding.keyboard.displayFailure().addListener(object : AssertedSuccessListener<Boolean?>() {
|
||||
override fun onSuccess(result: Boolean?) {
|
||||
binding.callMeCountDown.visibility = View.VISIBLE
|
||||
binding.resendSmsCountDown.visibility = View.VISIBLE
|
||||
binding.wrongNumber.visibility = View.VISIBLE
|
||||
binding.code.clear()
|
||||
binding.keyboard.displayKeyboard()
|
||||
}
|
||||
})
|
||||
}
|
||||
binding.keyboard.displayFailure().addListener(object : AssertedSuccessListener<Boolean?>() {
|
||||
override fun onSuccess(result: Boolean?) {
|
||||
binding.callMeCountDown.visibility = View.VISIBLE
|
||||
binding.resendSmsCountDown.visibility = View.VISIBLE
|
||||
binding.wrongNumber.visibility = View.VISIBLE
|
||||
binding.code.clear()
|
||||
binding.keyboard.displayKeyboard()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun presentGenericError(requestResult: RegistrationResult) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.core.view.MenuProvider
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
@@ -36,7 +35,6 @@ 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 kotlinx.coroutines.launch
|
||||
import org.signal.core.util.isNotNullOrBlank
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.LoggingFragment
|
||||
@@ -46,8 +44,9 @@ import org.thoughtcrime.securesms.databinding.FragmentRegistrationEnterPhoneNumb
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
|
||||
import org.thoughtcrime.securesms.registration.data.RegistrationRepository
|
||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionCheckResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionCreationResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
|
||||
import org.thoughtcrime.securesms.registration.ui.RegistrationCheckpoint
|
||||
@@ -116,10 +115,21 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
|
||||
sharedState.networkError?.let {
|
||||
presentNetworkError(it)
|
||||
sharedViewModel.networkErrorShown()
|
||||
}
|
||||
|
||||
sharedState.sessionCreationError?.let {
|
||||
handleSessionCreationError(it)
|
||||
sharedViewModel.sessionCreationErrorShown()
|
||||
}
|
||||
|
||||
sharedState.sessionStateError?.let {
|
||||
handleSessionStateError(it)
|
||||
sharedViewModel.sessionStateErrorShown()
|
||||
}
|
||||
|
||||
if (sharedState.challengesRequested.contains(Challenge.CAPTCHA) && sharedState.captchaToken.isNotNullOrBlank()) {
|
||||
sharedViewModel.submitCaptchaToken(requireContext(), ::handleErrorResponse)
|
||||
sharedViewModel.submitCaptchaToken(requireContext())
|
||||
} else if (sharedState.challengesRemaining.isNotEmpty()) {
|
||||
handleChallenges(sharedState.challengesRemaining)
|
||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED && sharedState.canSkipSms) {
|
||||
@@ -184,7 +194,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
}
|
||||
|
||||
private fun performPushChallenge() {
|
||||
sharedViewModel.requestAndSubmitPushToken(requireContext(), ::handleErrorResponse)
|
||||
sharedViewModel.requestAndSubmitPushToken(requireContext())
|
||||
}
|
||||
|
||||
private fun initializeInputFields() {
|
||||
@@ -294,67 +304,82 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
Log.i(TAG, "Unknown error during verification code request", networkError)
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(R.string.RegistrationActivity_unable_to_connect_to_service)
|
||||
setPositiveButton(android.R.string.ok) { _, _ -> sharedViewModel.clearNetworkError() }
|
||||
setOnCancelListener { sharedViewModel.clearNetworkError() }
|
||||
setOnDismissListener { sharedViewModel.clearNetworkError() }
|
||||
setPositiveButton(android.R.string.ok, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleErrorResponse(result: RegistrationResult) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
if (!result.isSuccess()) {
|
||||
Log.i(TAG, "Handling error response.", result.getCause())
|
||||
private fun handleSessionCreationError(result: RegistrationSessionResult) {
|
||||
if (!result.isSuccess()) {
|
||||
Log.i(TAG, "Handling error response.", result.getCause())
|
||||
}
|
||||
when (result) {
|
||||
is RegistrationSessionCheckResult.Success,
|
||||
is RegistrationSessionCreationResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||
is RegistrationSessionCreationResult.AttemptsExhausted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_service))
|
||||
is RegistrationSessionCreationResult.MalformedRequest -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
|
||||
is RegistrationSessionCreationResult.RateLimited -> {
|
||||
Log.i(TAG, "Session creation rate limited! Next attempt: ${result.timeRemaining.milliseconds}")
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, result.timeRemaining.milliseconds.toString()))
|
||||
}
|
||||
when (result) {
|
||||
is RegistrationSessionCreationResult.Success,
|
||||
is VerificationCodeRequestResult.Success -> Unit
|
||||
|
||||
is RegistrationSessionCreationResult.AttemptsExhausted,
|
||||
is VerificationCodeRequestResult.AttemptsExhausted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_service))
|
||||
is RegistrationSessionCreationResult.ServerUnableToParse -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
is RegistrationSessionCheckResult.SessionNotFound -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
is RegistrationSessionCheckResult.UnknownError,
|
||||
is RegistrationSessionCreationResult.UnknownError -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
}
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.ChallengeRequired -> {
|
||||
handleChallenges(result.challenges)
|
||||
}
|
||||
private fun handleSessionStateError(result: VerificationCodeRequestResult) {
|
||||
if (!result.isSuccess()) {
|
||||
Log.i(TAG, "Handling error response.", result.getCause())
|
||||
}
|
||||
when (result) {
|
||||
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||
|
||||
is VerificationCodeRequestResult.ExternalServiceFailure -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
is VerificationCodeRequestResult.ImpossibleNumber -> {
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid, fragmentViewModel.phoneNumber?.toE164()))
|
||||
setPositiveButton(android.R.string.ok, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
is VerificationCodeRequestResult.AttemptsExhausted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_service))
|
||||
|
||||
is VerificationCodeRequestResult.InvalidTransportModeFailure -> {
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(R.string.RegistrationActivity_we_couldnt_send_you_a_verification_code)
|
||||
setPositiveButton(R.string.RegistrationActivity_voice_call) { _, _ ->
|
||||
sharedViewModel.requestVerificationCall(requireContext(), ::handleErrorResponse)
|
||||
}
|
||||
setNegativeButton(R.string.RegistrationActivity_cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
is RegistrationSessionCreationResult.MalformedRequest,
|
||||
is VerificationCodeRequestResult.MalformedRequest -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
|
||||
is VerificationCodeRequestResult.MustRetry -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
is VerificationCodeRequestResult.NonNormalizedNumber -> handleNonNormalizedNumberError(result.originalNumber, result.normalizedNumber, fragmentViewModel.mode)
|
||||
is RegistrationSessionCreationResult.RateLimited -> {
|
||||
Log.i(TAG, "Session creation rate limited! Next attempt: ${result.timeRemaining.milliseconds}")
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, result.timeRemaining.milliseconds.toString()))
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.RateLimited -> {
|
||||
Log.i(TAG, "Code request rate limited! Next attempt: ${result.timeRemaining.milliseconds}")
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, result.timeRemaining.milliseconds.toString()))
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.TokenNotAccepted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_we_need_to_verify_that_youre_human)) { _, _ -> moveToCaptcha() }
|
||||
else -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
is VerificationCodeRequestResult.ChallengeRequired -> {
|
||||
handleChallenges(result.challenges)
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.ExternalServiceFailure -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
is VerificationCodeRequestResult.ImpossibleNumber -> {
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid, fragmentViewModel.phoneNumber?.toE164()))
|
||||
setPositiveButton(android.R.string.ok, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.InvalidTransportModeFailure -> {
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(R.string.RegistrationActivity_we_couldnt_send_you_a_verification_code)
|
||||
setPositiveButton(R.string.RegistrationActivity_voice_call) { _, _ ->
|
||||
sharedViewModel.requestVerificationCall(requireContext())
|
||||
}
|
||||
setNegativeButton(R.string.RegistrationActivity_cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.MalformedRequest -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
|
||||
is VerificationCodeRequestResult.MustRetry -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
is VerificationCodeRequestResult.NonNormalizedNumber -> handleNonNormalizedNumberError(result.originalNumber, result.normalizedNumber, fragmentViewModel.mode)
|
||||
|
||||
is VerificationCodeRequestResult.RateLimited -> {
|
||||
Log.i(TAG, "Code request rate limited! Next attempt: ${result.timeRemaining.milliseconds}")
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, result.timeRemaining.milliseconds.toString()))
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.TokenNotAccepted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_we_need_to_verify_that_youre_human)) { _, _ -> moveToCaptcha() }
|
||||
|
||||
is VerificationCodeRequestResult.RegistrationLocked -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
is VerificationCodeRequestResult.AlreadyVerified -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
is VerificationCodeRequestResult.NoSuchSession -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
is VerificationCodeRequestResult.UnknownError -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,8 +415,8 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
phoneNumberInputLayout.setText(phoneNumber.nationalNumber.toString())
|
||||
when (mode) {
|
||||
RegistrationRepository.Mode.SMS_WITH_LISTENER,
|
||||
RegistrationRepository.Mode.SMS_WITHOUT_LISTENER -> sharedViewModel.requestSmsCode(requireContext(), ::handleErrorResponse)
|
||||
RegistrationRepository.Mode.PHONE_CALL -> sharedViewModel.requestVerificationCall(requireContext(), ::handleErrorResponse)
|
||||
RegistrationRepository.Mode.SMS_WITHOUT_LISTENER -> sharedViewModel.requestSmsCode(requireContext())
|
||||
RegistrationRepository.Mode.PHONE_CALL -> sharedViewModel.requestVerificationCall(requireContext())
|
||||
}
|
||||
dialogInterface.dismiss()
|
||||
}
|
||||
@@ -510,7 +535,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
if (missingFcmConsentRequired) {
|
||||
handlePromptForNoPlayServices()
|
||||
} else {
|
||||
sharedViewModel.onUserConfirmedPhoneNumber(requireContext(), ::handleErrorResponse)
|
||||
sharedViewModel.onUserConfirmedPhoneNumber(requireContext())
|
||||
}
|
||||
}
|
||||
setNegativeButton(R.string.RegistrationActivity_edit_number) { _, _ -> handleConfirmNumberDialogCanceled() }
|
||||
@@ -525,7 +550,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
setMessage(R.string.RegistrationActivity_this_device_is_missing_google_play_services)
|
||||
setPositiveButton(R.string.RegistrationActivity_i_understand) { _, _ ->
|
||||
Log.d(TAG, "User confirmed number.")
|
||||
sharedViewModel.onUserConfirmedPhoneNumber(requireContext(), ::handleErrorResponse)
|
||||
sharedViewModel.onUserConfirmedPhoneNumber(requireContext())
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
setOnCancelListener { fragmentViewModel.clearError() }
|
||||
|
||||
@@ -24,7 +24,6 @@ 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.RegistrationResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
|
||||
import org.thoughtcrime.securesms.registration.ui.RegistrationViewModel
|
||||
@@ -101,12 +100,22 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
binding.kbsLockPinInputLabel.text = requireContext().resources.getQuantityString(R.plurals.RegistrationLockFragment__d_attempts_remaining, triesRemaining, triesRemaining)
|
||||
}
|
||||
|
||||
viewModel.inProgress.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
viewModel.uiState.observe(viewLifecycleOwner) {
|
||||
if (it.inProgress) {
|
||||
binding.kbsLockPinConfirm.setSpinning()
|
||||
} else {
|
||||
binding.kbsLockPinConfirm.cancelSpinning()
|
||||
}
|
||||
|
||||
it.sessionStateError?.let { error ->
|
||||
handleSessionErrorResponse(error)
|
||||
viewModel.sessionStateErrorShown()
|
||||
}
|
||||
|
||||
it.registerAccountError?.let { error ->
|
||||
handleRegistrationErrorResponse(error)
|
||||
viewModel.registerAccountErrorShown()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,12 +141,12 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
|
||||
binding.kbsLockPinConfirm.setSpinning()
|
||||
|
||||
viewModel.verifyCodeAndRegisterAccountWithRegistrationLock(requireContext(), pin, ::handleSessionErrorResponse, ::handleRegistrationErrorResponse)
|
||||
viewModel.verifyCodeAndRegisterAccountWithRegistrationLock(requireContext(), pin)
|
||||
}
|
||||
|
||||
private fun handleSessionErrorResponse(requestResult: RegistrationResult) {
|
||||
private fun handleSessionErrorResponse(requestResult: VerificationCodeRequestResult) {
|
||||
when (requestResult) {
|
||||
is VerificationCodeRequestResult.Success -> Unit
|
||||
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||
is VerificationCodeRequestResult.RateLimited -> onRateLimited()
|
||||
is VerificationCodeRequestResult.AttemptsExhausted -> {
|
||||
findNavController().safeNavigate(RegistrationLockFragmentDirections.actionAccountLocked())
|
||||
@@ -159,7 +168,7 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
|
||||
private fun handleRegistrationErrorResponse(result: RegisterAccountResult) {
|
||||
when (result) {
|
||||
is RegisterAccountResult.Success -> Unit
|
||||
is RegisterAccountResult.Success -> throw IllegalStateException("Register account error handler called on successful response!")
|
||||
is RegisterAccountResult.RateLimited -> onRateLimited()
|
||||
is RegisterAccountResult.AttemptsExhausted -> {
|
||||
findNavController().safeNavigate(RegistrationLockFragmentDirections.actionAccountLocked())
|
||||
|
||||
@@ -82,6 +82,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
|
||||
private fun updateViewState(state: RegistrationState) {
|
||||
if (state.networkError != null) {
|
||||
genericErrorDialog()
|
||||
registrationViewModel.networkErrorShown()
|
||||
} else if (!state.canSkipSms) {
|
||||
findNavController().safeNavigate(ReRegisterWithPinFragmentDirections.actionReRegisterWithPinFragmentToEnterPhoneNumberFragment())
|
||||
} else if (state.isRegistrationLockEnabled && state.svrTriesRemaining == 0) {
|
||||
@@ -91,6 +92,11 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
|
||||
presentProgress(state.inProgress)
|
||||
presentTriesRemaining(state.svrTriesRemaining)
|
||||
}
|
||||
|
||||
state.registerAccountError?.let { error ->
|
||||
registrationErrorHandler(error)
|
||||
registrationViewModel.registerAccountErrorShown()
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentProgress(inProgress: Boolean) {
|
||||
@@ -126,8 +132,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
|
||||
pin = pin,
|
||||
wrongPinHandler = {
|
||||
reRegisterViewModel.markIncorrectGuess()
|
||||
},
|
||||
registrationErrorHandler = ::registrationErrorHandler
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -251,7 +256,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
|
||||
|
||||
private fun registrationErrorHandler(result: RegisterAccountResult) {
|
||||
when (result) {
|
||||
is RegisterAccountResult.Success -> Log.d(TAG, "Register account was successful.")
|
||||
is RegisterAccountResult.Success -> throw IllegalStateException("Register account error handler called on successful response!")
|
||||
is RegisterAccountResult.AuthorizationFailed,
|
||||
is RegisterAccountResult.MalformedRequest,
|
||||
is RegisterAccountResult.UnknownError,
|
||||
|
||||
Reference in New Issue
Block a user