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