diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/EnterBackupKeyViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/EnterBackupKeyViewModel.kt index 1d2a91971d..58ecdc331a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/EnterBackupKeyViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/EnterBackupKeyViewModel.kt @@ -28,7 +28,7 @@ class EnterBackupKeyViewModel : ViewModel() { fun updateBackupKey(key: String) { _state.update { - val newKey = key.removeIllegalCharacters().take(length) + val newKey = key.removeIllegalCharacters().take(length).lowercase() copy(backupKey = newKey, backupKeyValid = validate(length, newKey)) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RemoteRestoreActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RemoteRestoreActivity.kt index 5de8a3bdf4..39b0222403 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RemoteRestoreActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RemoteRestoreActivity.kt @@ -394,8 +394,8 @@ fun RestoreFailedDialog( onDismiss: () -> Unit = {} ) { Dialogs.SimpleAlertDialog( - title = "Restore Failed", // TODO [backups] Remote restore error placeholder copy - body = "Unable to restore from backup. Please try again.", // TODO [backups] Placeholder copy + title = stringResource(R.string.RemoteRestoreActivity__couldnt_transfer), + body = stringResource(R.string.RemoteRestoreActivity__error_occurred), confirm = stringResource(android.R.string.ok), onConfirm = onDismiss, onDismiss = onDismiss diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RestoreViaQrFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RestoreViaQrFragment.kt index cc221d7199..31635784c7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RestoreViaQrFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RestoreViaQrFragment.kt @@ -49,6 +49,7 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull @@ -64,6 +65,7 @@ import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.settings.app.usernamelinks.QrCode import org.thoughtcrime.securesms.components.settings.app.usernamelinks.QrCodeData import org.thoughtcrime.securesms.compose.ComposeFragment +import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult import org.thoughtcrime.securesms.registrationv3.ui.RegistrationViewModel import org.thoughtcrime.securesms.registrationv3.ui.shared.RegistrationScreen import org.thoughtcrime.securesms.util.navigation.safeNavigate @@ -95,6 +97,24 @@ class RestoreViaQrFragment : ComposeFragment() { } } + viewLifecycleOwner.lifecycleScope.launch { + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { + viewModel + .state + .mapNotNull { it.registerAccountResult } + .filter { it !is RegisterAccountResult.Success } + .distinctUntilChanged() + .collect { result -> + when (result) { + is RegisterAccountResult.AttemptsExhausted -> { + findNavController().safeNavigate(RestoreViaQrFragmentDirections.goToAccountLocked()) + } + else -> Unit + } + } + } + } + viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { sharedViewModel @@ -103,7 +123,7 @@ class RestoreViaQrFragment : ComposeFragment() { .filterNotNull() .collect { sharedViewModel.registerAccountErrorShown() - viewModel.handleRegistrationFailure() + viewModel.handleRegistrationFailure(it) } } } @@ -252,8 +272,14 @@ private fun RestoreViaQrScreen( if (state.isRegistering) { Dialogs.IndeterminateProgressDialog() } else if (state.showRegistrationError) { + val message = when (state.registerAccountResult) { + is RegisterAccountResult.IncorrectRecoveryPassword -> stringResource(R.string.RestoreViaQr_registration_error) + is RegisterAccountResult.RateLimited -> stringResource(R.string.RegistrationActivity_you_have_made_too_many_attempts_please_try_again_later) + else -> stringResource(R.string.RegistrationActivity_error_connecting_to_service) + } + Dialogs.SimpleMessageDialog( - message = stringResource(R.string.RegistrationActivity_error_connecting_to_service), + message = message, onDismiss = onRegistrationErrorDismiss, dismiss = stringResource(android.R.string.ok) ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RestoreViaQrViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RestoreViaQrViewModel.kt index e96f7067b7..44d8082c5b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RestoreViaQrViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RestoreViaQrViewModel.kt @@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.components.settings.app.usernamelinks.QrCodeDa import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult import org.whispersystems.signalservice.api.registration.ProvisioningSocket import org.whispersystems.signalservice.internal.crypto.SecondaryProvisioningCipher import java.io.Closeable @@ -62,13 +63,15 @@ class RestoreViaQrViewModel : ViewModel() { } } - fun handleRegistrationFailure() { + fun handleRegistrationFailure(registerAccountResult: RegisterAccountResult) { store.update { if (it.isRegistering) { + Log.w(TAG, "Unable to register [${registerAccountResult::class.simpleName}]", registerAccountResult.getCause()) it.copy( isRegistering = false, provisioningMessage = null, - showRegistrationError = true + showRegistrationError = true, + registerAccountResult = registerAccountResult ) } else { it @@ -77,7 +80,14 @@ class RestoreViaQrViewModel : ViewModel() { } fun clearRegistrationError() { - store.update { it.copy(showRegistrationError = false) } + store.update { + it.copy( + showRegistrationError = false, + registerAccountResult = null + ) + } + + restart() } override fun onCleared() { @@ -179,6 +189,7 @@ class RestoreViaQrViewModel : ViewModel() { val provisioningMessage: RegistrationProvisionMessage? = null, val showProvisioningError: Boolean = false, val showRegistrationError: Boolean = false, + val registerAccountResult: RegisterAccountResult? = null, val currentSocketId: Int? = null ) diff --git a/app/src/main/res/navigation/registration_v3.xml b/app/src/main/res/navigation/registration_v3.xml index 5d1f87c574..5a602be39c 100644 --- a/app/src/main/res/navigation/registration_v3.xml +++ b/app/src/main/res/navigation/registration_v3.xml @@ -70,6 +70,15 @@ app:popExitAnim="@anim/nav_default_pop_exit_anim" app:popUpTo="@id/signup"/> + Fetching backup details… Skip restore + + Couldn\'t finish transfer + + An error occurred and your account couldn’t be transferred. Try again by choosing your transfer method. Notify me for Mentions @@ -7986,6 +7990,8 @@ Scanned on old device Retry + + An error occurred and your account couldn’t be transferred. Try again by scanning the QR code again. Transfer account