From 49ba83dda8ec7e9457dc620c960693f91590161e Mon Sep 17 00:00:00 2001 From: Clark Date: Mon, 6 May 2024 13:14:04 -0400 Subject: [PATCH] Integrate message backup frequency. --- .../securesms/backup/v2/BackupFrequency.kt | 34 +++++++++++++++++++ .../subscription/MessageBackupsFrequency.kt | 16 --------- .../backups/RemoteBackupsSettingsFragment.kt | 30 ++++++++-------- .../backups/RemoteBackupsSettingsState.kt | 4 +-- .../backups/RemoteBackupsSettingsViewModel.kt | 13 ++++--- .../securesms/keyvalue/BackupValues.kt | 3 ++ .../service/MessageBackupListener.kt | 7 ++++ 7 files changed, 70 insertions(+), 37 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupFrequency.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsFrequency.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupFrequency.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupFrequency.kt new file mode 100644 index 0000000000..fbeab9dcec --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupFrequency.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.backup.v2 + +import org.signal.core.util.LongSerializer + +/** + * Describes how often a users messages are backed up. + */ +enum class BackupFrequency(val id: Int) { + DAILY(0), + WEEKLY(1), + MONTHLY(2), + MANUAL(-1); + + companion object Serializer : LongSerializer { + override fun serialize(data: BackupFrequency): Long { + return data.id.toLong() + } + + override fun deserialize(data: Long): BackupFrequency { + return when (data.toInt()) { + MANUAL.id -> MANUAL + DAILY.id -> DAILY + WEEKLY.id -> WEEKLY + MONTHLY.id -> MONTHLY + else -> MANUAL + } + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsFrequency.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsFrequency.kt deleted file mode 100644 index 3adb6d9e58..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsFrequency.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2024 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.thoughtcrime.securesms.backup.v2.ui.subscription - -/** - * Describes how often a users messages are backed up. - */ -enum class MessageBackupsFrequency { - DAILY, - WEEKLY, - MONTHLY, - NEVER -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsFragment.kt index a38091eb99..000eaa3b4b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsFragment.kt @@ -51,10 +51,10 @@ import org.signal.core.ui.SignalPreview import org.signal.core.ui.Snackbars import org.signal.core.ui.Texts import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.backup.v2.BackupFrequency import org.thoughtcrime.securesms.backup.v2.BackupV2Event import org.thoughtcrime.securesms.backup.v2.MessageBackupTier import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsFlowActivity -import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsFrequency import org.thoughtcrime.securesms.backup.v2.ui.subscription.getTierDetails import org.thoughtcrime.securesms.compose.ComposeFragment import org.thoughtcrime.securesms.conversation.v2.registerForLifecycle @@ -132,7 +132,7 @@ class RemoteBackupsSettingsFragment : ComposeFragment() { viewModel.requestSnackbar(RemoteBackupsSettingsState.Snackbar.NONE) } - override fun onSelectBackupsFrequencyChange(newFrequency: MessageBackupsFrequency) { + override fun onSelectBackupsFrequencyChange(newFrequency: BackupFrequency) { viewModel.setBackupsFrequency(newFrequency) } @@ -170,7 +170,7 @@ private interface ContentCallbacks { fun onChangeBackupFrequencyClick() = Unit fun onDialogDismissed() = Unit fun onSnackbarDismissed() = Unit - fun onSelectBackupsFrequencyChange(newFrequency: MessageBackupsFrequency) = Unit + fun onSelectBackupsFrequencyChange(newFrequency: BackupFrequency) = Unit fun onTurnOffAndDeleteBackupsConfirm() = Unit } @@ -179,7 +179,7 @@ private fun RemoteBackupsSettingsContent( messageBackupTier: MessageBackupTier?, lastBackupTimestamp: Long, canBackUpUsingCellular: Boolean, - backupsFrequency: MessageBackupsFrequency, + backupsFrequency: BackupFrequency, requestedDialog: RemoteBackupsSettingsState.Dialog, requestedSnackbar: RemoteBackupsSettingsState.Snackbar, contentCallbacks: ContentCallbacks, @@ -498,8 +498,8 @@ private fun TurnOffAndDeleteBackupsDialog( @OptIn(ExperimentalMaterial3Api::class) @Composable private fun BackupFrequencyDialog( - selected: MessageBackupsFrequency, - onSelected: (MessageBackupsFrequency) -> Unit, + selected: BackupFrequency, + onSelected: (BackupFrequency) -> Unit, onDismiss: () -> Unit ) { AlertDialog( @@ -520,12 +520,12 @@ private fun BackupFrequencyDialog( modifier = Modifier.padding(24.dp) ) - MessageBackupsFrequency.values().forEach { + BackupFrequency.values().forEach { Rows.RadioRow( selected = selected == it, text = getTextForFrequency(backupsFrequency = it), label = when (it) { - MessageBackupsFrequency.NEVER -> "By tapping \"Back up now\"" + BackupFrequency.MANUAL -> "By tapping \"Back up now\"" else -> null }, modifier = Modifier @@ -554,12 +554,12 @@ private fun BackupFrequencyDialog( } @Composable -private fun getTextForFrequency(backupsFrequency: MessageBackupsFrequency): String { +private fun getTextForFrequency(backupsFrequency: BackupFrequency): String { return when (backupsFrequency) { - MessageBackupsFrequency.DAILY -> "Daily" - MessageBackupsFrequency.WEEKLY -> "Weekly" - MessageBackupsFrequency.MONTHLY -> "Monthly" - MessageBackupsFrequency.NEVER -> "Manually back up" + BackupFrequency.DAILY -> "Daily" + BackupFrequency.WEEKLY -> "Weekly" + BackupFrequency.MONTHLY -> "Monthly" + BackupFrequency.MANUAL -> "Manually back up" } } @@ -571,7 +571,7 @@ private fun RemoteBackupsSettingsContentPreview() { messageBackupTier = null, lastBackupTimestamp = -1, canBackUpUsingCellular = false, - backupsFrequency = MessageBackupsFrequency.NEVER, + backupsFrequency = BackupFrequency.MANUAL, requestedDialog = RemoteBackupsSettingsState.Dialog.NONE, requestedSnackbar = RemoteBackupsSettingsState.Snackbar.NONE, contentCallbacks = object : ContentCallbacks {}, @@ -628,7 +628,7 @@ private fun TurnOffAndDeleteBackupsDialogPreview() { private fun BackupFrequencyDialogPreview() { Previews.Preview { BackupFrequencyDialog( - selected = MessageBackupsFrequency.DAILY, + selected = BackupFrequency.DAILY, onSelected = {}, onDismiss = {} ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsState.kt index 799f72f397..a25ab14b30 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsState.kt @@ -5,15 +5,15 @@ package org.thoughtcrime.securesms.components.settings.app.chats.backups +import org.thoughtcrime.securesms.backup.v2.BackupFrequency import org.thoughtcrime.securesms.backup.v2.BackupV2Event import org.thoughtcrime.securesms.backup.v2.MessageBackupTier -import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsFrequency data class RemoteBackupsSettingsState( val messageBackupsTier: MessageBackupTier? = null, val canBackUpUsingCellular: Boolean = false, val backupSize: Long = 0, - val backupsFrequency: MessageBackupsFrequency = MessageBackupsFrequency.DAILY, + val backupsFrequency: BackupFrequency = BackupFrequency.DAILY, val lastBackupTimestamp: Long = 0, val dialog: Dialog = Dialog.NONE, val snackbar: Snackbar = Snackbar.NONE, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsViewModel.kt index f67fad72e6..713249f229 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/backups/RemoteBackupsSettingsViewModel.kt @@ -8,11 +8,13 @@ package org.thoughtcrime.securesms.components.settings.app.chats.backups import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import org.thoughtcrime.securesms.backup.v2.BackupFrequency import org.thoughtcrime.securesms.backup.v2.BackupV2Event import org.thoughtcrime.securesms.backup.v2.MessageBackupTier -import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsFrequency +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobs.BackupMessagesJob import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.service.MessageBackupListener /** * ViewModel for state management of RemoteBackupsSettingsFragment @@ -30,7 +32,8 @@ class RemoteBackupsSettingsViewModel : ViewModel() { null }, lastBackupTimestamp = SignalStore.backup().lastBackupTime, - backupSize = SignalStore.backup().totalBackupSize + backupSize = SignalStore.backup().totalBackupSize, + backupsFrequency = SignalStore.backup().backupFrequency ) ) @@ -41,9 +44,11 @@ class RemoteBackupsSettingsViewModel : ViewModel() { internalState.value = state.value.copy(canBackUpUsingCellular = canBackUpUsingCellular) } - fun setBackupsFrequency(backupsFrequency: MessageBackupsFrequency) { - // TODO [message-backups] -- Update via repository? + fun setBackupsFrequency(backupsFrequency: BackupFrequency) { + SignalStore.backup().backupFrequency = backupsFrequency internalState.value = state.value.copy(backupsFrequency = backupsFrequency) + MessageBackupListener.setNextBackupTimeToIntervalFromNow() + MessageBackupListener.schedule(ApplicationDependencies.getApplication()) } fun requestDialog(dialog: RemoteBackupsSettingsState.Dialog) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt index c93ed9f5bb..cd0dda6db2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.keyvalue import com.fasterxml.jackson.annotation.JsonProperty import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.backup.RestoreState +import org.thoughtcrime.securesms.backup.v2.BackupFrequency import org.whispersystems.signalservice.api.archive.ArchiveServiceCredential import org.whispersystems.signalservice.api.archive.GetArchiveCdnCredentialsResponse import org.whispersystems.signalservice.internal.util.JsonUtil @@ -24,6 +25,7 @@ internal class BackupValues(store: KeyValueStore) : SignalStoreValues(store) { private const val KEY_NEXT_BACKUP_TIME = "backup.nextBackupTime" private const val KEY_LAST_BACKUP_TIME = "backup.lastBackupTime" + private const val KEY_BACKUP_FREQUENCY = "backup.backupFrequency" private const val KEY_CDN_BACKUP_DIRECTORY = "backup.cdn.directory" private const val KEY_CDN_BACKUP_MEDIA_DIRECTORY = "backup.cdn.mediaDirectory" @@ -55,6 +57,7 @@ internal class BackupValues(store: KeyValueStore) : SignalStoreValues(store) { var nextBackupTime: Long by longValue(KEY_NEXT_BACKUP_TIME, -1) var lastBackupTime: Long by longValue(KEY_LAST_BACKUP_TIME, -1) + var backupFrequency: BackupFrequency by enumValue(KEY_BACKUP_FREQUENCY, BackupFrequency.MANUAL, BackupFrequency.Serializer) val totalBackupSize: Long get() = lastBackupProtoSize + usedBackupMediaSpace diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/MessageBackupListener.kt b/app/src/main/java/org/thoughtcrime/securesms/service/MessageBackupListener.kt index ddd95042e8..e5471aeeb4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/MessageBackupListener.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/MessageBackupListener.kt @@ -6,6 +6,7 @@ package org.thoughtcrime.securesms.service import android.content.Context +import org.thoughtcrime.securesms.backup.v2.BackupFrequency import org.thoughtcrime.securesms.jobs.BackupMessagesJob import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.util.FeatureFlags @@ -47,6 +48,12 @@ class MessageBackupListener : PersistentAlarmManagerListener() { var next = now.withHour(hour).withMinute(minute).withSecond(0) val jitter = Random().nextInt(BACKUP_JITTER_WINDOW_SECONDS) - BACKUP_JITTER_WINDOW_SECONDS / 2 next.plusSeconds(jitter.toLong()) + next = when (SignalStore.backup().backupFrequency) { + BackupFrequency.DAILY -> next.plusDays(1) + BackupFrequency.MANUAL -> next.plusDays(365) + BackupFrequency.MONTHLY -> next.plusDays(30) + BackupFrequency.WEEKLY -> next.plusDays(7) + } if (now.isAfter(next)) { next = next.plusDays(1) }