Add insufficient storage error message to link+sync.

This commit is contained in:
Michelle Tang
2025-06-09 11:55:49 -04:00
committed by Greyson Parrelli
parent e0726ce62f
commit 59b747ee63
6 changed files with 106 additions and 32 deletions

View File

@@ -314,27 +314,38 @@ fun DeviceListScreen(
)
}
is DialogState.SyncingFailed -> {
if (state.dialogState.canRetry) {
Dialogs.SimpleAlertDialog(
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 = onSyncFailureRetryRequested,
dismiss = stringResource(R.string.LinkDeviceFragment__sync_failure_dismiss_button),
onDismissRequest = onSyncFailureIgnored,
onDeny = onSyncFailureIgnored
)
} else {
Dialogs.AdvancedAlertDialog(
title = stringResource(R.string.LinkDeviceFragment__sync_failure_title),
body = stringResource(R.string.LinkDeviceFragment__sync_failure_body_unretryable),
positive = stringResource(R.string.LinkDeviceFragment__contact_support),
onPositive = onSyncFailureContactSupport,
neutral = stringResource(R.string.LinkDeviceFragment__learn_more),
onNeutral = onSyncFailureLearnMore,
negative = stringResource(R.string.LinkDeviceFragment__continue),
onNegative = onSyncFailureIgnored
)
when (state.dialogState.syncFailType) {
LinkDeviceSettingsState.SyncFailType.NOT_RETRYABLE -> {
Dialogs.AdvancedAlertDialog(
title = stringResource(R.string.LinkDeviceFragment__sync_failure_title),
body = stringResource(R.string.LinkDeviceFragment__sync_failure_body_unretryable),
positive = stringResource(R.string.LinkDeviceFragment__contact_support),
onPositive = onSyncFailureContactSupport,
neutral = stringResource(R.string.LinkDeviceFragment__learn_more),
onNeutral = onSyncFailureLearnMore,
negative = stringResource(R.string.LinkDeviceFragment__continue),
onNegative = onSyncFailureIgnored
)
}
LinkDeviceSettingsState.SyncFailType.RETRYABLE -> {
Dialogs.SimpleAlertDialog(
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 = onSyncFailureRetryRequested,
dismiss = stringResource(R.string.LinkDeviceFragment__sync_failure_dismiss_button),
onDismissRequest = onSyncFailureIgnored,
onDeny = onSyncFailureIgnored
)
}
LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE -> {
Dialogs.SimpleMessageDialog(
message = stringResource(R.string.LinkDeviceFragment__you_dont_have_enough),
dismiss = stringResource(id = R.string.LinkDeviceFragment__ok),
onDismiss = onSyncFailureRetryRequested,
title = stringResource(R.string.LinkDeviceFragment__not_enough_storage_space)
)
}
}
}
DialogState.SyncingTimedOut -> {
@@ -681,7 +692,11 @@ private fun DeviceListScreenSyncingFailedPreview() {
Previews.Preview {
DeviceListScreen(
state = LinkDeviceSettingsState(
dialogState = DialogState.SyncingFailed(1, 1, false),
dialogState = DialogState.SyncingFailed(
deviceId = 1,
deviceCreatedAt = 1,
syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_RETRYABLE
),
seenQrEducationSheet = true,
seenBioAuthEducationSheet = true
)
@@ -716,3 +731,21 @@ private fun DeviceListScreenDeviceUnlinkedPreview() {
)
}
}
@SignalPreview
@Composable
private fun DeviceListScreenNotEnoughStoragePreview() {
Previews.Preview {
DeviceListScreen(
state = LinkDeviceSettingsState(
dialogState = DialogState.SyncingFailed(
deviceId = 1,
deviceCreatedAt = 1,
syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE
),
seenQrEducationSheet = true,
seenBioAuthEducationSheet = true
)
)
}
}

View File

@@ -10,6 +10,7 @@ import org.signal.core.util.logging.logI
import org.signal.core.util.logging.logW
import org.signal.libsignal.protocol.InvalidKeyException
import org.signal.libsignal.protocol.ecc.Curve
import org.thoughtcrime.securesms.backup.BackupFileIOError
import org.thoughtcrime.securesms.backup.v2.ArchiveValidator
import org.thoughtcrime.securesms.backup.v2.BackupRepository
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
@@ -263,7 +264,12 @@ object LinkDeviceRepository {
)
} catch (e: Exception) {
Log.w(TAG, "[createAndUploadArchive] Failed to export a backup!", e)
return LinkUploadArchiveResult.BackupCreationFailure(e)
val cause = e.cause
return if (cause is IOException && BackupFileIOError.getFromException(cause) == BackupFileIOError.NOT_ENOUGH_SPACE) {
LinkUploadArchiveResult.NotEnoughSpace
} else {
LinkUploadArchiveResult.BackupCreationFailure(e)
}
}
Log.d(TAG, "[createAndUploadArchive] Successfully created backup.")
stopwatch.split("create-backup")
@@ -440,6 +446,7 @@ object LinkDeviceRepository {
data object Success : LinkUploadArchiveResult
data object BackupCreationCancelled : LinkUploadArchiveResult
data class BackupCreationFailure(val exception: Exception) : LinkUploadArchiveResult
data object NotEnoughSpace : LinkUploadArchiveResult
data class BadRequest(val exception: IOException) : LinkUploadArchiveResult
data class NetworkError(val exception: IOException) : LinkUploadArchiveResult
}

View File

@@ -32,7 +32,7 @@ data class LinkDeviceSettingsState(
data object Unlinking : DialogState
data class SyncingMessages(val deviceId: Int, val deviceCreatedAt: Long) : DialogState
data object SyncingTimedOut : DialogState
data class SyncingFailed(val deviceId: Int, val deviceCreatedAt: Long, val canRetry: Boolean) : DialogState
data class SyncingFailed(val deviceId: Int, val deviceCreatedAt: Long, val syncFailType: SyncFailType) : DialogState
data class DeviceUnlinked(val deviceCreatedAt: Long) : DialogState
data object LoadingDebugLog : DialogState
data object ContactSupport : DialogState
@@ -55,4 +55,10 @@ data class LinkDeviceSettingsState(
enum class QrCodeState {
NONE, VALID_WITH_SYNC, VALID_WITHOUT_SYNC, INVALID
}
enum class SyncFailType {
NOT_RETRYABLE,
RETRYABLE,
NOT_ENOUGH_SPACE
}
}

View File

@@ -339,17 +339,39 @@ class LinkDeviceViewModel : ViewModel() {
}
loadDevices()
}
is LinkDeviceRepository.LinkUploadArchiveResult.BackupCreationFailure,
is LinkDeviceRepository.LinkUploadArchiveResult.BadRequest,
is LinkDeviceRepository.LinkUploadArchiveResult.NetworkError -> {
Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive! Result: $uploadResult")
val canRetry = uploadResult !is LinkDeviceRepository.LinkUploadArchiveResult.BackupCreationFailure
is LinkDeviceRepository.LinkUploadArchiveResult.NotEnoughSpace -> {
Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive because there is not enough space")
_state.update {
it.copy(
dialogState = DialogState.SyncingFailed(
deviceId = waitResult.id,
deviceCreatedAt = waitResult.created,
canRetry = canRetry
syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE
)
)
}
}
is LinkDeviceRepository.LinkUploadArchiveResult.BackupCreationFailure -> {
Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive because of backup creation failure")
_state.update {
it.copy(
dialogState = DialogState.SyncingFailed(
deviceId = waitResult.id,
deviceCreatedAt = waitResult.created,
syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_RETRYABLE
)
)
}
}
is LinkDeviceRepository.LinkUploadArchiveResult.BadRequest,
is LinkDeviceRepository.LinkUploadArchiveResult.NetworkError -> {
Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive! Result: $uploadResult")
_state.update {
it.copy(
dialogState = DialogState.SyncingFailed(
deviceId = waitResult.id,
deviceCreatedAt = waitResult.created,
syncFailType = LinkDeviceSettingsState.SyncFailType.RETRYABLE
)
)
}
@@ -457,11 +479,13 @@ class LinkDeviceViewModel : ViewModel() {
}
}
val shouldLaunchQrScanner = !(dialogState is DialogState.SyncingFailed && dialogState.syncFailType != LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE)
_state.update {
it.copy(
linkDeviceResult = LinkDeviceResult.None,
dialogState = DialogState.None,
oneTimeEvent = OneTimeEvent.LaunchQrCodeScanner
oneTimeEvent = if (shouldLaunchQrScanner) OneTimeEvent.LaunchQrCodeScanner else OneTimeEvent.None
)
}
}