diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/ArchiveUploadProgress.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/ArchiveUploadProgress.kt
index f7a2073e6c..6f861efb00 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/ArchiveUploadProgress.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/ArchiveUploadProgress.kt
@@ -104,6 +104,10 @@ object ArchiveUploadProgress {
updateState(PROGRESS_NONE)
}
+ fun onValidationFailure() {
+ updateState(PROGRESS_NONE)
+ }
+
private fun updateState(state: ArchiveUploadProgressState, notify: Boolean = true) {
uploadProgress = state
SignalStore.backup.archiveUploadState = state
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt
index 9c57ebabc7..4515e752a2 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt
@@ -204,14 +204,27 @@ object BackupRepository {
}
/**
- * Whether the "Could not complete backup" row should be displayed in settings.
+ * Whether the "Backup Failed" row should be displayed in settings.
+ * Shown when the initial backup creation has failed
*/
fun shouldDisplayBackupFailedSettingsRow(): Boolean {
if (shouldNotDisplayBackupFailedMessaging()) {
return false
}
- return SignalStore.backup.hasBackupFailure
+ return !SignalStore.backup.hasBackupBeenUploaded && SignalStore.backup.hasBackupFailure
+ }
+
+ /**
+ * Whether the "Could not complete backup" row should be displayed in settings.
+ * Shown when a new backup could not be created but there is an existing one already
+ */
+ fun shouldDisplayCouldNotCompleteBackupSettingsRow(): Boolean {
+ if (shouldNotDisplayBackupFailedMessaging()) {
+ return false
+ }
+
+ return SignalStore.backup.hasBackupBeenUploaded && SignalStore.backup.hasBackupFailure
}
/**
@@ -230,7 +243,8 @@ object BackupRepository {
}
/**
- * Whether or not the "Could not complete backup" sheet should be displayed.
+ * Whether or not the "Backup failed" sheet should be displayed.
+ * Should only be displayed if this is the failure of the initial backup creation.
*/
@JvmStatic
fun shouldDisplayBackupFailedSheet(): Boolean {
@@ -238,7 +252,19 @@ object BackupRepository {
return false
}
- return System.currentTimeMillis().milliseconds > SignalStore.backup.nextBackupFailureSheetSnoozeTime
+ return !SignalStore.backup.hasBackupBeenUploaded && System.currentTimeMillis().milliseconds > SignalStore.backup.nextBackupFailureSheetSnoozeTime
+ }
+
+ /**
+ * Whether or not the "Could not complete backup" sheet should be displayed.
+ */
+ @JvmStatic
+ fun shouldDisplayCouldNotCompleteBackupSheet(): Boolean {
+ if (shouldNotDisplayBackupFailedMessaging()) {
+ return false
+ }
+
+ return SignalStore.backup.hasBackupBeenUploaded && System.currentTimeMillis().milliseconds > SignalStore.backup.nextBackupFailureSheetSnoozeTime
}
fun snoozeYourMediaWillBeDeletedTodaySheet() {
@@ -249,7 +275,7 @@ object BackupRepository {
* Whether or not the "Your media will be deleted today" sheet should be displayed.
*/
suspend fun shouldDisplayYourMediaWillBeDeletedTodaySheet(): Boolean {
- if (shouldNotDisplayBackupFailedMessaging() || !SignalStore.backup.optimizeStorage) {
+ if (shouldNotDisplayBackupFailedMessaging() || !SignalStore.backup.hasBackupBeenUploaded || !SignalStore.backup.optimizeStorage) {
return false
}
@@ -285,7 +311,7 @@ object BackupRepository {
}
private fun shouldNotDisplayBackupFailedMessaging(): Boolean {
- return !RemoteConfig.messageBackups || !SignalStore.backup.areBackupsEnabled || !SignalStore.backup.hasBackupBeenUploaded
+ return !RemoteConfig.messageBackups || !SignalStore.backup.areBackupsEnabled
}
/**
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertBottomSheet.kt
index 436c410271..44070c7671 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertBottomSheet.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertBottomSheet.kt
@@ -57,6 +57,8 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobs.BackupMessagesJob
import org.thoughtcrime.securesms.jobs.BackupRestoreMediaJob
import org.thoughtcrime.securesms.payments.FiatMoneyUtil
+import org.thoughtcrime.securesms.util.CommunicationActions
+import org.thoughtcrime.securesms.util.PlayStoreUtil
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.milliseconds
@@ -67,6 +69,8 @@ import org.signal.core.ui.R as CoreUiR
*/
class BackupAlertBottomSheet : UpgradeToPaidTierBottomSheet() {
+ override val peekHeightPercentage: Float = 0.75f
+
companion object {
private const val ARG_ALERT = "alert"
@@ -126,6 +130,8 @@ class BackupAlertBottomSheet : UpgradeToPaidTierBottomSheet() {
}
is BackupAlert.DiskFull -> Unit
+ is BackupAlert.BackupFailed ->
+ PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext())
}
dismissAllowingStateLoss()
@@ -144,6 +150,8 @@ class BackupAlertBottomSheet : UpgradeToPaidTierBottomSheet() {
is BackupAlert.DiskFull -> {
displaySkipRestoreDialog()
}
+ // TODO [backups] - Update support URL with backups page
+ BackupAlert.BackupFailed -> CommunicationActions.openBrowserLink(requireContext(), requireContext().getString(R.string.backup_support_url))
}
dismissAllowingStateLoss()
@@ -153,7 +161,7 @@ class BackupAlertBottomSheet : UpgradeToPaidTierBottomSheet() {
super.onDismiss(dialog)
when (backupAlert) {
- is BackupAlert.CouldNotCompleteBackup -> BackupRepository.markBackupFailedSheetDismissed()
+ is BackupAlert.CouldNotCompleteBackup, BackupAlert.BackupFailed -> BackupRepository.markBackupFailedSheetDismissed()
is BackupAlert.MediaWillBeDeletedToday -> BackupRepository.snoozeYourMediaWillBeDeletedTodaySheet()
else -> Unit
}
@@ -261,6 +269,7 @@ private fun BackupAlertSheetContent(
is BackupAlert.MediaBackupsAreOff -> MediaBackupsAreOffBody(backupAlert.endOfPeriodSeconds, mediaTtl)
BackupAlert.MediaWillBeDeletedToday -> MediaWillBeDeletedTodayBody()
is BackupAlert.DiskFull -> DiskFullBody(requiredSpace = backupAlert.requiredSpace)
+ BackupAlert.BackupFailed -> BackupFailedBody()
}
val secondaryActionResource = rememberSecondaryActionResource(backupAlert = backupAlert)
@@ -366,12 +375,22 @@ private fun DiskFullBody(requiredSpace: String) {
)
}
+@Composable
+private fun BackupFailedBody() {
+ Text(
+ text = stringResource(id = R.string.BackupAlertBottomSheet__an_error_occurred),
+ textAlign = TextAlign.Center,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.padding(bottom = 36.dp)
+ )
+}
+
@Composable
private fun rememberBackupsIconColors(backupAlert: BackupAlert): BackupsIconColors {
return remember(backupAlert) {
when (backupAlert) {
BackupAlert.FailedToRenew, is BackupAlert.MediaBackupsAreOff -> error("Not icon-based options.")
- is BackupAlert.CouldNotCompleteBackup, is BackupAlert.DiskFull -> BackupsIconColors.Warning
+ is BackupAlert.CouldNotCompleteBackup, BackupAlert.BackupFailed, is BackupAlert.DiskFull -> BackupsIconColors.Warning
BackupAlert.MediaWillBeDeletedToday -> BackupsIconColors.Error
}
}
@@ -385,6 +404,7 @@ private fun titleString(backupAlert: BackupAlert): String {
is BackupAlert.MediaBackupsAreOff -> stringResource(R.string.BackupAlertBottomSheet__your_backups_subscription_expired)
BackupAlert.MediaWillBeDeletedToday -> stringResource(R.string.BackupAlertBottomSheet__your_media_will_be_deleted_today)
is BackupAlert.DiskFull -> stringResource(R.string.BackupAlertBottomSheet__free_up_s_on_this_device, backupAlert.requiredSpace)
+ BackupAlert.BackupFailed -> stringResource(R.string.BackupAlertBottomSheet__backup_failed)
}
}
@@ -399,6 +419,7 @@ private fun primaryActionString(
is BackupAlert.MediaBackupsAreOff -> stringResource(R.string.BackupAlertBottomSheet__subscribe_for_s_month, pricePerMonth)
BackupAlert.MediaWillBeDeletedToday -> stringResource(R.string.BackupAlertBottomSheet__download_media_now)
is BackupAlert.DiskFull -> stringResource(R.string.BackupAlertBottomSheet__got_it)
+ is BackupAlert.BackupFailed -> stringResource(R.string.BackupAlertBottomSheet__check_for_update)
}
}
@@ -411,6 +432,7 @@ private fun rememberSecondaryActionResource(backupAlert: BackupAlert): Int {
is BackupAlert.MediaBackupsAreOff -> R.string.BackupAlertBottomSheet__not_now
BackupAlert.MediaWillBeDeletedToday -> R.string.BackupAlertBottomSheet__dont_download_media
is BackupAlert.DiskFull -> R.string.BackupAlertBottomSheet__skip_restore
+ is BackupAlert.BackupFailed -> R.string.BackupAlertBottomSheet__learn_more
}
}
}
@@ -471,6 +493,17 @@ private fun BackupAlertSheetContentPreviewDiskFull() {
}
}
+@SignalPreview
+@Composable
+private fun BackupAlertSheetContentPreviewBackupFailed() {
+ Previews.BottomSheetPreview {
+ BackupAlertSheetContent(
+ backupAlert = BackupAlert.BackupFailed,
+ mediaTtl = 60.days
+ )
+ }
+}
+
/**
* All necessary information to display the sheet should be handed in through the specific alert.
*/
@@ -485,6 +518,12 @@ sealed class BackupAlert : Parcelable {
val daysSinceLastBackup: Int
) : BackupAlert()
+ /**
+ * This value is driven by the same watermarking system for [CouldNotCompleteBackup] so that only one of these sheets is shown by the system
+ * This value is driven by failure to complete the initial backup.
+ */
+ data object BackupFailed : BackupAlert()
+
/**
* This value is driven by InAppPayment state, and will be automatically cleared when the sheet is displayed.
*/
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertDelegate.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertDelegate.kt
index 18b7249b80..f6057c6840 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertDelegate.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertDelegate.kt
@@ -22,11 +22,11 @@ object BackupAlertDelegate {
lifecycle.coroutineScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
if (BackupRepository.shouldDisplayBackupFailedSheet()) {
+ BackupAlertBottomSheet.create(BackupAlert.BackupFailed).show(fragmentManager, null)
+ } else if (BackupRepository.shouldDisplayCouldNotCompleteBackupSheet()) {
BackupAlertBottomSheet.create(BackupAlert.CouldNotCompleteBackup(daysSinceLastBackup = SignalStore.backup.daysSinceLastBackup)).show(fragmentManager, null)
- }
-
- if (BackupRepository.shouldDisplayYourMediaWillBeDeletedTodaySheet()) {
- BackupAlertBottomSheet.create(BackupAlert.MediaWillBeDeletedToday)
+ } else if (BackupRepository.shouldDisplayYourMediaWillBeDeletedTodaySheet()) {
+ BackupAlertBottomSheet.create(BackupAlert.MediaWillBeDeletedToday).show(fragmentManager, null)
}
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/status/BackupStatusBanner.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/status/BackupStatusBanner.kt
index 2e00cf5d81..b69594ff8e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/status/BackupStatusBanner.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/status/BackupStatusBanner.kt
@@ -195,6 +195,12 @@ fun BackupStatusBannerPreview() {
BackupStatusBanner(
data = BackupStatusData.CouldNotCompleteBackup
)
+
+ HorizontalDivider()
+
+ BackupStatusBanner(
+ data = BackupStatusData.BackupFailed
+ )
}
}
}
@@ -235,6 +241,19 @@ sealed interface BackupStatusData {
override val iconColors: BackupsIconColors = BackupsIconColors.Warning
}
+ /**
+ * Initial backup creation failure
+ */
+ data object BackupFailed : BackupStatusData {
+ override val iconRes: Int = R.drawable.symbol_backup_error_24
+
+ override val title: String
+ @Composable
+ get() = stringResource(androidx.biometric.R.string.default_error_msg)
+
+ override val iconColors: BackupsIconColors = BackupsIconColors.Warning
+ }
+
/**
* User does not have enough space on their device to complete backup restoration
*/
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/status/BackupStatusRow.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/status/BackupStatusRow.kt
index 4dd17140f2..d39f831a5e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/status/BackupStatusRow.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/status/BackupStatusRow.kt
@@ -20,17 +20,19 @@ import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.withLink
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.signal.core.ui.Previews
@@ -48,10 +50,13 @@ import org.signal.core.ui.R as CoreUiR
fun BackupStatusRow(
backupStatusData: BackupStatusData,
onSkipClick: () -> Unit = {},
- onCancelClick: () -> Unit = {}
+ onCancelClick: () -> Unit = {},
+ onLearnMoreClick: () -> Unit = {}
) {
Column {
- if (backupStatusData !is BackupStatusData.CouldNotCompleteBackup) {
+ if (backupStatusData !is BackupStatusData.CouldNotCompleteBackup &&
+ backupStatusData !is BackupStatusData.BackupFailed
+ ) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(horizontal = dimensionResource(CoreUiR.dimen.gutter))
@@ -120,6 +125,40 @@ fun BackupStatusRow(
modifier = Modifier.padding(horizontal = dimensionResource(CoreUiR.dimen.gutter))
)
}
+ BackupStatusData.BackupFailed -> {
+ val inlineContentMap = mapOf(
+ "yellow_bullet" to InlineTextContent(
+ Placeholder(12.sp, 12.sp, PlaceholderVerticalAlign.TextCenter)
+ ) {
+ Box(
+ modifier = Modifier
+ .size(12.dp)
+ .background(color = backupStatusData.iconColors.foreground, shape = CircleShape)
+ )
+ }
+ )
+
+ Text(
+ text = buildAnnotatedString {
+ appendInlineContent("yellow_bullet")
+ append(" ")
+ append(stringResource(R.string.BackupStatusRow__your_last_backup_latest_version))
+ append(" ")
+ withLink(
+ LinkAnnotation.Clickable(
+ stringResource(R.string.BackupStatusRow__learn_more),
+ styles = TextLinkStyles(style = SpanStyle(color = MaterialTheme.colorScheme.primary))
+ ) {
+ onLearnMoreClick()
+ }
+ ) {
+ append(stringResource(R.string.BackupStatusRow__learn_more))
+ }
+ },
+ inlineContent = inlineContentMap,
+ modifier = Modifier.padding(horizontal = dimensionResource(CoreUiR.dimen.gutter))
+ )
+ }
}
}
}
@@ -241,3 +280,13 @@ fun BackupStatusRowCouldNotCompleteBackupPreview() {
)
}
}
+
+@SignalPreview
+@Composable
+fun BackupStatusRowBackupFailedPreview() {
+ Previews.Preview {
+ BackupStatusRow(
+ backupStatusData = BackupStatusData.BackupFailed
+ )
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt
index 2e6c21768c..ba77211323 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt
@@ -215,7 +215,7 @@ private fun AppSettingsContent(
}
}
- BackupFailureState.COULD_NOT_COMPLETE_BACKUP -> {
+ BackupFailureState.BACKUP_FAILED, BackupFailureState.COULD_NOT_COMPLETE_BACKUP -> {
item {
Dividers.Default()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsViewModel.kt
index 8b30532c5f..7d0ba2ddfa 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsViewModel.kt
@@ -72,6 +72,8 @@ class AppSettingsViewModel : ViewModel() {
private fun getBackupFailureState(): BackupFailureState {
return if (BackupRepository.shouldDisplayBackupFailedSettingsRow()) {
+ BackupFailureState.BACKUP_FAILED
+ } else if (BackupRepository.shouldDisplayCouldNotCompleteBackupSettingsRow()) {
BackupFailureState.COULD_NOT_COMPLETE_BACKUP
} else if (SignalStore.backup.subscriptionStateMismatchDetected) {
BackupFailureState.SUBSCRIPTION_STATE_MISMATCH
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/BackupFailureState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/BackupFailureState.kt
index d971b2d322..c3b3666d09 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/BackupFailureState.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/BackupFailureState.kt
@@ -10,6 +10,7 @@ package org.thoughtcrime.securesms.components.settings.app
*/
enum class BackupFailureState {
NONE,
+ BACKUP_FAILED,
COULD_NOT_COMPLETE_BACKUP,
SUBSCRIPTION_STATE_MISMATCH
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt
index 671dc83bb6..873dffc941 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt
@@ -83,6 +83,8 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.backup.ArchiveUploadProgress
import org.thoughtcrime.securesms.backup.v2.BackupFrequency
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
+import org.thoughtcrime.securesms.backup.v2.ui.BackupAlert
+import org.thoughtcrime.securesms.backup.v2.ui.BackupAlertBottomSheet
import org.thoughtcrime.securesms.backup.v2.ui.status.BackupStatusData
import org.thoughtcrime.securesms.backup.v2.ui.status.BackupStatusRow
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
@@ -233,6 +235,10 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
requireActivity().finish()
requireActivity().startActivity(AppSettingsActivity.help(requireContext(), HelpFragment.REMOTE_BACKUPS_INDEX))
}
+
+ override fun onLearnMoreAboutBackupFailure() {
+ BackupAlertBottomSheet.create(BackupAlert.BackupFailed).show(parentFragmentManager, null)
+ }
}
private fun displayBackupKey() {
@@ -314,6 +320,7 @@ private interface ContentCallbacks {
fun onRenewLostSubscription() = Unit
fun onLearnMoreAboutLostSubscription() = Unit
fun onContactSupport() = Unit
+ fun onLearnMoreAboutBackupFailure() = Unit
}
@Composable
@@ -392,7 +399,8 @@ private fun RemoteBackupsSettingsContent(
BackupStatusRow(
backupStatusData = backupRestoreState.backupStatusData,
onCancelClick = contentCallbacks::onCancelMediaRestore,
- onSkipClick = contentCallbacks::onSkipMediaRestore
+ onSkipClick = contentCallbacks::onSkipMediaRestore,
+ onLearnMoreClick = contentCallbacks::onLearnMoreAboutBackupFailure
)
}
} else if (backupRestoreState is BackupRestoreState.Ready && backupState is RemoteBackupsSettingsState.BackupState.Canceled) {
@@ -420,7 +428,8 @@ private fun RemoteBackupsSettingsContent(
BackupStatusRow(
backupStatusData = backupRestoreState.backupStatusData,
onCancelClick = contentCallbacks::onCancelMediaRestore,
- onSkipClick = contentCallbacks::onSkipMediaRestore
+ onSkipClick = contentCallbacks::onSkipMediaRestore,
+ onLearnMoreClick = contentCallbacks::onLearnMoreAboutBackupFailure
)
}
}
@@ -920,8 +929,14 @@ private fun InProgressBackupRow(
)
}
+ val inProgressText = if (totalProgress == null || totalProgress == 0) {
+ stringResource(R.string.RemoteBackupsSettingsFragment__processing_backup)
+ } else {
+ stringResource(R.string.RemoteBackupsSettingsFragment__d_slash_d, progress ?: 0, totalProgress)
+ }
+
Text(
- text = stringResource(R.string.RemoteBackupsSettingsFragment__d_slash_d, progress ?: 0, totalProgress ?: 0),
+ text = inProgressText,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsViewModel.kt
index e2852c2deb..915af9618a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsViewModel.kt
@@ -92,6 +92,8 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
} else if (SignalStore.backup.totalRestorableAttachmentSize > 0L) {
_restoreState.update { BackupRestoreState.Ready(SignalStore.backup.totalRestorableAttachmentSize.bytes.toUnitString()) }
} else if (BackupRepository.shouldDisplayBackupFailedSettingsRow()) {
+ _restoreState.update { BackupRestoreState.FromBackupStatusData(BackupStatusData.BackupFailed) }
+ } else if (BackupRepository.shouldDisplayCouldNotCompleteBackupSettingsRow()) {
_restoreState.update { BackupRestoreState.FromBackupStatusData(BackupStatusData.CouldNotCompleteBackup) }
} else {
_restoreState.update { BackupRestoreState.None }
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt
index 0516e1af7d..f2c06ba2e4 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt
@@ -101,8 +101,8 @@ class BackupMessagesJob private constructor(parameters: Parameters) : Job(parame
return Result.retry(defaultBackoff())
}
is ArchiveValidator.ValidationResult.ValidationError -> {
- // TODO [backup] UX
Log.w(TAG, "The backup file fails validation! Message: " + result.exception.message)
+ ArchiveUploadProgress.onValidationFailure()
return Result.failure()
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8ba143f27c..fe4257b44c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -7504,6 +7504,12 @@
Skip restore?
If you skip restore the remaining media and attachments in your backup can be downloaded at a later time when storage space becomes available.
+
+ Backup failed
+
+ An error occurred and your backup could not be completed. Make sure you\'re on the latest version of Signal and try again. If this problem persists, contact support.
+
+ Check for update
@@ -7536,7 +7542,11 @@
Skip download
- Your last backup couldn\'t be completed. Make sure your phone is connected to Wi-F and tap "Back up now" to try again.
+ Your last backup couldn\'t be completed. Make sure your phone is connected to Wi-Fi and tap \"Back up now\" to try again.
+
+ Your last backup couldn\'t be completed. Make sure you\'re on the latest version of Signal and try again.
+
+ Learn more
@@ -7740,6 +7750,8 @@
Renew
Learn more
+
+ Processing backup…
- You have %1$s of backup data that’s not on this device. Your backup will be deleted when your subscription ends in %2$d day.