mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-27 06:29:54 +00:00
Add link+sync error flows.
This commit is contained in:
committed by
Greyson Parrelli
parent
e1d4566dfd
commit
df5ef06109
@@ -179,7 +179,7 @@ class LinkDeviceFragment : ComposeFragment() {
|
||||
onLinkNewDeviceClicked = { navController.navigateToQrScannerIfAuthed() },
|
||||
onDeviceSelectedForRemoval = { device -> viewModel.setDeviceToRemove(device) },
|
||||
onDeviceRemovalConfirmed = { device -> viewModel.removeDevice(device) },
|
||||
onSyncFailureRetryRequested = { deviceId -> viewModel.onSyncErrorRetryRequested(deviceId) },
|
||||
onSyncFailureRetryRequested = { viewModel.onSyncErrorRetryRequested() },
|
||||
onSyncFailureIgnored = { viewModel.onSyncErrorIgnored() },
|
||||
onEditDevice = { device ->
|
||||
viewModel.setDeviceToEdit(device)
|
||||
@@ -228,7 +228,7 @@ fun DeviceListScreen(
|
||||
onLinkNewDeviceClicked: () -> Unit = {},
|
||||
onDeviceSelectedForRemoval: (Device?) -> Unit = {},
|
||||
onDeviceRemovalConfirmed: (Device) -> Unit = {},
|
||||
onSyncFailureRetryRequested: (Int?) -> Unit = {},
|
||||
onSyncFailureRetryRequested: () -> Unit = {},
|
||||
onSyncFailureIgnored: () -> Unit = {},
|
||||
onEditDevice: (Device) -> Unit = {}
|
||||
) {
|
||||
@@ -253,15 +253,10 @@ fun DeviceListScreen(
|
||||
title = stringResource(R.string.LinkDeviceFragment__sync_failure_title),
|
||||
body = stringResource(R.string.LinkDeviceFragment__sync_failure_body),
|
||||
confirm = stringResource(R.string.LinkDeviceFragment__sync_failure_retry_button),
|
||||
onConfirm = {
|
||||
if (state.dialogState is DialogState.SyncingFailed) {
|
||||
onSyncFailureRetryRequested(state.dialogState.deviceId)
|
||||
} else {
|
||||
onSyncFailureRetryRequested(null)
|
||||
}
|
||||
},
|
||||
onConfirm = onSyncFailureRetryRequested,
|
||||
dismiss = stringResource(R.string.LinkDeviceFragment__sync_failure_dismiss_button),
|
||||
onDismiss = onSyncFailureIgnored
|
||||
onDismissRequest = onSyncFailureIgnored,
|
||||
onDeny = onSyncFailureIgnored
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.registration.secondary.DeviceNameCipher
|
||||
import org.whispersystems.signalservice.api.NetworkResult
|
||||
import org.whispersystems.signalservice.api.backup.MessageBackupKey
|
||||
import org.whispersystems.signalservice.api.link.LinkedDeviceVerificationCodeResponse
|
||||
import org.whispersystems.signalservice.api.link.TransferArchiveError
|
||||
import org.whispersystems.signalservice.api.link.WaitForLinkedDeviceResponse
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||
@@ -351,6 +352,24 @@ object LinkDeviceRepository {
|
||||
return NetworkResult.NetworkError(IOException("Hit max retries!"))
|
||||
}
|
||||
|
||||
/**
|
||||
* If [createAndUploadArchive] fails to upload an archive, alert the linked device of the failure and if the user will try again
|
||||
*/
|
||||
fun sendTransferArchiveError(deviceId: Int, deviceCreatedAt: Long, error: TransferArchiveError) {
|
||||
val archiveErrorResult = SignalNetwork.linkDevice.setTransferArchiveError(
|
||||
destinationDeviceId = deviceId,
|
||||
destinationDeviceCreated = deviceCreatedAt,
|
||||
error = error
|
||||
)
|
||||
|
||||
when (archiveErrorResult) {
|
||||
is NetworkResult.Success -> Log.i(TAG, "[sendTransferArchiveError] Successfully sent transfer archive error.")
|
||||
is NetworkResult.ApplicationError -> throw archiveErrorResult.throwable
|
||||
is NetworkResult.NetworkError -> Log.w(TAG, "[sendTransferArchiveError] Network error when sending transfer archive error.", archiveErrorResult.exception)
|
||||
is NetworkResult.StatusCodeError -> Log.w(TAG, "[sendTransferArchiveError] Status code error when sending transfer archive error.", archiveErrorResult.exception)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the name of a linked device and sends a sync message if successful
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ data class LinkDeviceSettingsState(
|
||||
data object Unlinking : DialogState
|
||||
data object SyncingMessages : DialogState
|
||||
data object SyncingTimedOut : DialogState
|
||||
data class SyncingFailed(val deviceId: Int) : DialogState
|
||||
data class SyncingFailed(val deviceId: Int, val deviceCreatedAt: Long) : DialogState
|
||||
}
|
||||
|
||||
sealed interface OneTimeEvent {
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.linkdevice.LinkDeviceSettingsState.QrCodeState
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.api.backup.MessageBackupKey
|
||||
import org.whispersystems.signalservice.api.link.TransferArchiveError
|
||||
import org.whispersystems.signalservice.api.link.WaitForLinkedDeviceResponse
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@@ -260,7 +261,7 @@ class LinkDeviceViewModel : ViewModel() {
|
||||
Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive! Result: $uploadResult")
|
||||
_state.update {
|
||||
it.copy(
|
||||
dialogState = DialogState.SyncingFailed(waitResult.id)
|
||||
dialogState = DialogState.SyncingFailed(waitResult.id, waitResult.created)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -309,16 +310,29 @@ class LinkDeviceViewModel : ViewModel() {
|
||||
return this.getQueryParameter("capabilities")?.split(",")?.contains("backup") == true
|
||||
}
|
||||
|
||||
fun onSyncErrorIgnored() {
|
||||
fun onSyncErrorIgnored() = viewModelScope.launch(Dispatchers.IO) {
|
||||
val dialogState = _state.value.dialogState
|
||||
if (dialogState is DialogState.SyncingFailed) {
|
||||
Log.i(TAG, "Alerting linked device of sync failure - will not retry")
|
||||
LinkDeviceRepository.sendTransferArchiveError(dialogState.deviceId, dialogState.deviceCreatedAt, TransferArchiveError.CONTINUE_WITHOUT_UPLOAD)
|
||||
}
|
||||
|
||||
_state.update {
|
||||
it.copy(dialogState = DialogState.None)
|
||||
it.copy(
|
||||
linkDeviceResult = LinkDeviceResult.None,
|
||||
dialogState = DialogState.None
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSyncErrorRetryRequested(deviceId: Int?) = viewModelScope.launch(Dispatchers.IO) {
|
||||
if (deviceId != null) {
|
||||
fun onSyncErrorRetryRequested() = viewModelScope.launch(Dispatchers.IO) {
|
||||
val dialogState = _state.value.dialogState
|
||||
if (dialogState is DialogState.SyncingFailed) {
|
||||
Log.i(TAG, "Alerting linked device of sync failure - will retry")
|
||||
LinkDeviceRepository.sendTransferArchiveError(dialogState.deviceId, dialogState.deviceCreatedAt, TransferArchiveError.RELINK_REQUESTED)
|
||||
|
||||
Log.i(TAG, "Need to unlink device first...")
|
||||
val success = LinkDeviceRepository.removeDevice(deviceId)
|
||||
val success = LinkDeviceRepository.removeDevice(dialogState.deviceId)
|
||||
if (!success) {
|
||||
Log.w(TAG, "Failed to remove device! We did our best. Continuing.")
|
||||
}
|
||||
@@ -326,6 +340,7 @@ class LinkDeviceViewModel : ViewModel() {
|
||||
|
||||
_state.update {
|
||||
it.copy(
|
||||
linkDeviceResult = LinkDeviceResult.None,
|
||||
dialogState = DialogState.None,
|
||||
oneTimeEvent = OneTimeEvent.LaunchQrCodeScanner
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user