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 16db7954e5..0e922f53dd 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
@@ -38,6 +38,7 @@ import org.signal.core.ui.Previews
import org.signal.core.ui.SignalPreview
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
+import org.thoughtcrime.securesms.database.model.databaseprotos.InAppPaymentData
/**
* Notifies the user of an issue with their backup.
@@ -70,12 +71,10 @@ class BackupAlertBottomSheet : ComposeBottomSheetDialogFragment() {
@Stable
private fun performPrimaryAction() {
when (backupAlert) {
- BackupAlert.GENERIC -> {
+ BackupAlert.COULD_NOT_COMPLETE_BACKUP -> {
// TODO [message-backups] -- Back up now
}
- BackupAlert.PAYMENT_PROCESSING -> {
- // TODO [message-backups] -- Silence
- }
+ BackupAlert.PAYMENT_PROCESSING -> Unit
BackupAlert.MEDIA_BACKUPS_ARE_OFF -> {
// TODO [message-backups] -- Download media now
}
@@ -91,7 +90,7 @@ class BackupAlertBottomSheet : ComposeBottomSheetDialogFragment() {
@Stable
private fun performSecondaryAction() {
when (backupAlert) {
- BackupAlert.GENERIC -> {
+ BackupAlert.COULD_NOT_COMPLETE_BACKUP -> {
// TODO [message-backups] - Dismiss and notify later
}
BackupAlert.PAYMENT_PROCESSING -> error("PAYMENT_PROCESSING state does not support a secondary action.")
@@ -101,9 +100,7 @@ class BackupAlertBottomSheet : ComposeBottomSheetDialogFragment() {
BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> {
// TODO [message-backups] - Silence forever
}
- BackupAlert.DISK_FULL -> {
- // TODO [message-backups] - Silence forever, cancel any in-flight downloads?
- }
+ BackupAlert.DISK_FULL -> Unit
}
dismissAllowingStateLoss()
@@ -144,9 +141,13 @@ private fun BackupAlertSheetContent(
)
when (backupAlert) {
- BackupAlert.GENERIC -> GenericBody()
- BackupAlert.PAYMENT_PROCESSING -> PaymentProcessingBody()
- BackupAlert.MEDIA_BACKUPS_ARE_OFF -> MediaBackupsAreOffBody()
+ BackupAlert.COULD_NOT_COMPLETE_BACKUP -> CouldNotCompleteBackup(
+ daysSinceLastBackup = 7 // TODO [message-backups]
+ )
+ BackupAlert.PAYMENT_PROCESSING -> PaymentProcessingBody(
+ paymentMethodType = InAppPaymentData.PaymentMethodType.GOOGLE_PAY // TODO [message-backups] -- Get this data from elsewhere... The active subscription object?
+ )
+ BackupAlert.MEDIA_BACKUPS_ARE_OFF -> MediaBackupsAreOffBody(30) // TODO [message-backups] -- Get this value from backend
BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> MediaWillBeDeletedTodayBody()
BackupAlert.DISK_FULL -> DiskFullBody(
requiredSpace = "12 GB", // TODO [message-backups] Where does this value come from?
@@ -175,23 +176,54 @@ private fun BackupAlertSheetContent(
}
@Composable
-private fun GenericBody() {
- Text(text = "TODO", modifier = Modifier.padding(bottom = 60.dp))
+private fun CouldNotCompleteBackup(
+ daysSinceLastBackup: Int
+) {
+ Text(
+ text = stringResource(id = R.string.BackupAlertBottomSheet__your_device_hasnt, daysSinceLastBackup),
+ modifier = Modifier.padding(bottom = 60.dp)
+ )
}
@Composable
-private fun PaymentProcessingBody() {
- Text(text = "TODO", modifier = Modifier.padding(bottom = 60.dp))
+private fun PaymentProcessingBody(paymentMethodType: InAppPaymentData.PaymentMethodType) {
+ Text(
+ text = stringResource(id = R.string.BackupAlertBottomSheet__were_having_trouble_collecting__google_pay),
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(bottom = 60.dp)
+ )
}
@Composable
-private fun MediaBackupsAreOffBody() {
- Text(text = "TODO", modifier = Modifier.padding(bottom = 60.dp))
+private fun MediaBackupsAreOffBody(
+ daysUntilDeletion: Long
+) {
+ Text(
+ text = stringResource(id = R.string.BackupAlertBottomSheet__your_signal_media_backup_plan, daysUntilDeletion),
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(bottom = 24.dp)
+ )
+
+ Text(
+ text = stringResource(id = R.string.BackupAlertBottomSheet__you_can_begin_paying_for_backups_again),
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(bottom = 36.dp)
+ )
}
@Composable
private fun MediaWillBeDeletedTodayBody() {
- Text(text = "TODO", modifier = Modifier.padding(bottom = 60.dp))
+ Text(
+ text = stringResource(id = R.string.BackupAlertBottomSheet__your_signal_media_backup_plan_has_been),
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(bottom = 24.dp)
+ )
+
+ Text(
+ text = stringResource(id = R.string.BackupAlertBottomSheet__you_can_begin_paying_for_backups_again),
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(bottom = 36.dp)
+ )
}
@Composable
@@ -216,7 +248,7 @@ private fun DiskFullBody(
private fun rememberBackupsIconColors(backupAlert: BackupAlert): BackupsIconColors {
return remember(backupAlert) {
when (backupAlert) {
- BackupAlert.GENERIC, BackupAlert.PAYMENT_PROCESSING, BackupAlert.DISK_FULL -> BackupsIconColors.Warning
+ BackupAlert.COULD_NOT_COMPLETE_BACKUP, BackupAlert.PAYMENT_PROCESSING, BackupAlert.DISK_FULL -> BackupsIconColors.Warning
BackupAlert.MEDIA_BACKUPS_ARE_OFF, BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> BackupsIconColors.Error
}
}
@@ -227,10 +259,10 @@ private fun rememberBackupsIconColors(backupAlert: BackupAlert): BackupsIconColo
private fun rememberTitleResource(backupAlert: BackupAlert): Int {
return remember(backupAlert) {
when (backupAlert) {
- BackupAlert.GENERIC -> R.string.default_error_msg // TODO [message-backups] -- Finalized copy
- BackupAlert.PAYMENT_PROCESSING -> R.string.default_error_msg // TODO [message-backups] -- Finalized copy
- BackupAlert.MEDIA_BACKUPS_ARE_OFF -> R.string.default_error_msg // TODO [message-backups] -- Finalized copy
- BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> R.string.default_error_msg // TODO [message-backups] -- Finalized copy
+ BackupAlert.COULD_NOT_COMPLETE_BACKUP -> R.string.BackupAlertBottomSheet__couldnt_complete_backup
+ BackupAlert.PAYMENT_PROCESSING -> R.string.BackupAlertBottomSheet__cant_process_backup_payment
+ BackupAlert.MEDIA_BACKUPS_ARE_OFF -> R.string.BackupAlertBottomSheet__media_backups_are_off
+ BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> R.string.BackupAlertBottomSheet__your_media_will_be_deleted_today
BackupAlert.DISK_FULL -> R.string.BackupAlertBottomSheet__cant_complete_download
}
}
@@ -240,10 +272,10 @@ private fun rememberTitleResource(backupAlert: BackupAlert): Int {
private fun rememberPrimaryActionResource(backupAlert: BackupAlert): Int {
return remember(backupAlert) {
when (backupAlert) {
- BackupAlert.GENERIC -> android.R.string.ok // TODO [message-backups] -- Finalized copy
- BackupAlert.PAYMENT_PROCESSING -> android.R.string.ok // TODO [message-backups] -- Finalized copy
- BackupAlert.MEDIA_BACKUPS_ARE_OFF -> android.R.string.ok // TODO [message-backups] -- Finalized copy
- BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> android.R.string.ok // TODO [message-backups] -- Finalized copy
+ BackupAlert.COULD_NOT_COMPLETE_BACKUP -> android.R.string.ok // TODO [message-backups] -- Finalized copy
+ BackupAlert.PAYMENT_PROCESSING -> android.R.string.ok
+ BackupAlert.MEDIA_BACKUPS_ARE_OFF -> R.string.BackupAlertBottomSheet__download_media_now
+ BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> R.string.BackupAlertBottomSheet__download_media_now
BackupAlert.DISK_FULL -> android.R.string.ok
}
}
@@ -253,10 +285,10 @@ private fun rememberPrimaryActionResource(backupAlert: BackupAlert): Int {
private fun rememberSecondaryActionResource(backupAlert: BackupAlert): Int {
return remember(backupAlert) {
when (backupAlert) {
- BackupAlert.GENERIC -> android.R.string.cancel // TODO [message-backups] -- Finalized copy
+ BackupAlert.COULD_NOT_COMPLETE_BACKUP -> android.R.string.cancel // TODO [message-backups] -- Finalized copy
BackupAlert.PAYMENT_PROCESSING -> -1
- BackupAlert.MEDIA_BACKUPS_ARE_OFF -> android.R.string.cancel // TODO [message-backups] -- Finalized copy
- BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> android.R.string.cancel // TODO [message-backups] -- Finalized copy
+ BackupAlert.MEDIA_BACKUPS_ARE_OFF -> R.string.BackupAlertBottomSheet__download_later
+ BackupAlert.MEDIA_WILL_BE_DELETED_TODAY -> R.string.BackupAlertBottomSheet__dont_download_media
BackupAlert.DISK_FULL -> R.string.BackupAlertBottomSheet__skip
}
}
@@ -267,7 +299,7 @@ private fun rememberSecondaryActionResource(backupAlert: BackupAlert): Int {
private fun BackupAlertSheetContentPreviewGeneric() {
Previews.BottomSheetPreview {
BackupAlertSheetContent(
- backupAlert = BackupAlert.GENERIC,
+ backupAlert = BackupAlert.COULD_NOT_COMPLETE_BACKUP,
onPrimaryActionClick = {},
onSecondaryActionClick = {}
)
@@ -324,7 +356,7 @@ private fun BackupAlertSheetContentPreviewDiskFull() {
@Parcelize
enum class BackupAlert : Parcelable {
- GENERIC,
+ COULD_NOT_COMPLETE_BACKUP,
PAYMENT_PROCESSING,
MEDIA_BACKUPS_ARE_OFF,
MEDIA_WILL_BE_DELETED_TODAY,
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
new file mode 100644
index 0000000000..542e9bc6c5
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/BackupAlertDelegate.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2024 Signal Messenger, LLC
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+package org.thoughtcrime.securesms.backup.v2.ui
+
+import androidx.fragment.app.FragmentManager
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.coroutineScope
+import androidx.lifecycle.repeatOnLifecycle
+import kotlinx.coroutines.launch
+
+/**
+ * Delegate that controls whether and which backup alert sheet is displayed.
+ */
+object BackupAlertDelegate {
+ @JvmStatic
+ fun delegate(fragmentManager: FragmentManager, lifecycle: Lifecycle) {
+ lifecycle.coroutineScope.launch {
+ lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ // TODO [message-backups]
+ // 1. Get unnotified backup upload failures
+ // 2. Get unnotified backup download failures
+ // 3. Get unnotified backup payment failures
+
+ // Decide which do display
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java
index 945a43ae67..5fda31912a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java
@@ -90,6 +90,7 @@ import org.thoughtcrime.securesms.MainNavigator;
import org.thoughtcrime.securesms.MuteDialog;
import org.thoughtcrime.securesms.NewConversationActivity;
import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.backup.v2.ui.BackupAlertDelegate;
import org.thoughtcrime.securesms.badges.models.Badge;
import org.thoughtcrime.securesms.badges.self.expired.ExpiredOneTimeBadgeBottomSheetDialogFragment;
import org.thoughtcrime.securesms.badges.self.expired.MonthlyDonationCanceledBottomSheetDialogFragment;
@@ -277,6 +278,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
getViewLifecycleOwner().getLifecycle().addObserver(new TerminalDonationDelegate(getParentFragmentManager(), getViewLifecycleOwner()));
+ BackupAlertDelegate.delegate(getParentFragmentManager(), getViewLifecycleOwner().getLifecycle());
lifecycleDisposable = new LifecycleDisposable();
lifecycleDisposable.bindTo(getViewLifecycleOwner());
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5bd4540c05..9d0650b90c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -6996,16 +6996,40 @@
Downloading backup data…
+
+ Media backups are off
+
+ Your Signal media backup plan has been canceled because we couldn\'t process your payment. You have %1$d days to download any media stored in your backup. After %1$d days, the media in your backup will be deleted.
+
+ You can begin paying for backups again at any time to continue backing up all your media.
+
+ Your media will be deleted today
+
+ Your Signal media backup plan has been canceled because we couldn\'t process your payment. This is your last chance to download the media in your backup before it is deleted.
Can\'t complete download
Your device does not have enough free space. Free up to %1$s of space to download the media stored in your backup.
If you choose \"Skip\" the media in your backup will be deleted in %1$d days.
+
+ Can\'t process backup payment
+
+ We\'re having trouble collecting your recurring monthly backup payment. Make sure your payment method is up to date. If it isn\'t, update it in Google Pay. Signal will try to process the payment again in a few days.
+
+ Couldn\'t complete backup
+
+ Your device hasn\'t completed a backup for %1$d days. Make sure your device is connected to wi-fi and tap \"Back up now.\"
Learn more
Skip
+
+ Download media now
+
+ Download later
+
+ Don\'t download media