Integrate message backup frequency.
This commit is contained in:
parent
de3b0d4ca2
commit
49ba83dda8
7 changed files with 70 additions and 37 deletions
|
@ -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<BackupFrequency> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
||||||
}
|
|
|
@ -51,10 +51,10 @@ import org.signal.core.ui.SignalPreview
|
||||||
import org.signal.core.ui.Snackbars
|
import org.signal.core.ui.Snackbars
|
||||||
import org.signal.core.ui.Texts
|
import org.signal.core.ui.Texts
|
||||||
import org.thoughtcrime.securesms.R
|
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.BackupV2Event
|
||||||
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||||
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsFlowActivity
|
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.backup.v2.ui.subscription.getTierDetails
|
||||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||||
import org.thoughtcrime.securesms.conversation.v2.registerForLifecycle
|
import org.thoughtcrime.securesms.conversation.v2.registerForLifecycle
|
||||||
|
@ -132,7 +132,7 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
|
||||||
viewModel.requestSnackbar(RemoteBackupsSettingsState.Snackbar.NONE)
|
viewModel.requestSnackbar(RemoteBackupsSettingsState.Snackbar.NONE)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSelectBackupsFrequencyChange(newFrequency: MessageBackupsFrequency) {
|
override fun onSelectBackupsFrequencyChange(newFrequency: BackupFrequency) {
|
||||||
viewModel.setBackupsFrequency(newFrequency)
|
viewModel.setBackupsFrequency(newFrequency)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ private interface ContentCallbacks {
|
||||||
fun onChangeBackupFrequencyClick() = Unit
|
fun onChangeBackupFrequencyClick() = Unit
|
||||||
fun onDialogDismissed() = Unit
|
fun onDialogDismissed() = Unit
|
||||||
fun onSnackbarDismissed() = Unit
|
fun onSnackbarDismissed() = Unit
|
||||||
fun onSelectBackupsFrequencyChange(newFrequency: MessageBackupsFrequency) = Unit
|
fun onSelectBackupsFrequencyChange(newFrequency: BackupFrequency) = Unit
|
||||||
fun onTurnOffAndDeleteBackupsConfirm() = Unit
|
fun onTurnOffAndDeleteBackupsConfirm() = Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ private fun RemoteBackupsSettingsContent(
|
||||||
messageBackupTier: MessageBackupTier?,
|
messageBackupTier: MessageBackupTier?,
|
||||||
lastBackupTimestamp: Long,
|
lastBackupTimestamp: Long,
|
||||||
canBackUpUsingCellular: Boolean,
|
canBackUpUsingCellular: Boolean,
|
||||||
backupsFrequency: MessageBackupsFrequency,
|
backupsFrequency: BackupFrequency,
|
||||||
requestedDialog: RemoteBackupsSettingsState.Dialog,
|
requestedDialog: RemoteBackupsSettingsState.Dialog,
|
||||||
requestedSnackbar: RemoteBackupsSettingsState.Snackbar,
|
requestedSnackbar: RemoteBackupsSettingsState.Snackbar,
|
||||||
contentCallbacks: ContentCallbacks,
|
contentCallbacks: ContentCallbacks,
|
||||||
|
@ -498,8 +498,8 @@ private fun TurnOffAndDeleteBackupsDialog(
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun BackupFrequencyDialog(
|
private fun BackupFrequencyDialog(
|
||||||
selected: MessageBackupsFrequency,
|
selected: BackupFrequency,
|
||||||
onSelected: (MessageBackupsFrequency) -> Unit,
|
onSelected: (BackupFrequency) -> Unit,
|
||||||
onDismiss: () -> Unit
|
onDismiss: () -> Unit
|
||||||
) {
|
) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
|
@ -520,12 +520,12 @@ private fun BackupFrequencyDialog(
|
||||||
modifier = Modifier.padding(24.dp)
|
modifier = Modifier.padding(24.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
MessageBackupsFrequency.values().forEach {
|
BackupFrequency.values().forEach {
|
||||||
Rows.RadioRow(
|
Rows.RadioRow(
|
||||||
selected = selected == it,
|
selected = selected == it,
|
||||||
text = getTextForFrequency(backupsFrequency = it),
|
text = getTextForFrequency(backupsFrequency = it),
|
||||||
label = when (it) {
|
label = when (it) {
|
||||||
MessageBackupsFrequency.NEVER -> "By tapping \"Back up now\""
|
BackupFrequency.MANUAL -> "By tapping \"Back up now\""
|
||||||
else -> null
|
else -> null
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -554,12 +554,12 @@ private fun BackupFrequencyDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getTextForFrequency(backupsFrequency: MessageBackupsFrequency): String {
|
private fun getTextForFrequency(backupsFrequency: BackupFrequency): String {
|
||||||
return when (backupsFrequency) {
|
return when (backupsFrequency) {
|
||||||
MessageBackupsFrequency.DAILY -> "Daily"
|
BackupFrequency.DAILY -> "Daily"
|
||||||
MessageBackupsFrequency.WEEKLY -> "Weekly"
|
BackupFrequency.WEEKLY -> "Weekly"
|
||||||
MessageBackupsFrequency.MONTHLY -> "Monthly"
|
BackupFrequency.MONTHLY -> "Monthly"
|
||||||
MessageBackupsFrequency.NEVER -> "Manually back up"
|
BackupFrequency.MANUAL -> "Manually back up"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,7 +571,7 @@ private fun RemoteBackupsSettingsContentPreview() {
|
||||||
messageBackupTier = null,
|
messageBackupTier = null,
|
||||||
lastBackupTimestamp = -1,
|
lastBackupTimestamp = -1,
|
||||||
canBackUpUsingCellular = false,
|
canBackUpUsingCellular = false,
|
||||||
backupsFrequency = MessageBackupsFrequency.NEVER,
|
backupsFrequency = BackupFrequency.MANUAL,
|
||||||
requestedDialog = RemoteBackupsSettingsState.Dialog.NONE,
|
requestedDialog = RemoteBackupsSettingsState.Dialog.NONE,
|
||||||
requestedSnackbar = RemoteBackupsSettingsState.Snackbar.NONE,
|
requestedSnackbar = RemoteBackupsSettingsState.Snackbar.NONE,
|
||||||
contentCallbacks = object : ContentCallbacks {},
|
contentCallbacks = object : ContentCallbacks {},
|
||||||
|
@ -628,7 +628,7 @@ private fun TurnOffAndDeleteBackupsDialogPreview() {
|
||||||
private fun BackupFrequencyDialogPreview() {
|
private fun BackupFrequencyDialogPreview() {
|
||||||
Previews.Preview {
|
Previews.Preview {
|
||||||
BackupFrequencyDialog(
|
BackupFrequencyDialog(
|
||||||
selected = MessageBackupsFrequency.DAILY,
|
selected = BackupFrequency.DAILY,
|
||||||
onSelected = {},
|
onSelected = {},
|
||||||
onDismiss = {}
|
onDismiss = {}
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,15 +5,15 @@
|
||||||
|
|
||||||
package org.thoughtcrime.securesms.components.settings.app.chats.backups
|
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.BackupV2Event
|
||||||
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||||
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsFrequency
|
|
||||||
|
|
||||||
data class RemoteBackupsSettingsState(
|
data class RemoteBackupsSettingsState(
|
||||||
val messageBackupsTier: MessageBackupTier? = null,
|
val messageBackupsTier: MessageBackupTier? = null,
|
||||||
val canBackUpUsingCellular: Boolean = false,
|
val canBackUpUsingCellular: Boolean = false,
|
||||||
val backupSize: Long = 0,
|
val backupSize: Long = 0,
|
||||||
val backupsFrequency: MessageBackupsFrequency = MessageBackupsFrequency.DAILY,
|
val backupsFrequency: BackupFrequency = BackupFrequency.DAILY,
|
||||||
val lastBackupTimestamp: Long = 0,
|
val lastBackupTimestamp: Long = 0,
|
||||||
val dialog: Dialog = Dialog.NONE,
|
val dialog: Dialog = Dialog.NONE,
|
||||||
val snackbar: Snackbar = Snackbar.NONE,
|
val snackbar: Snackbar = Snackbar.NONE,
|
||||||
|
|
|
@ -8,11 +8,13 @@ package org.thoughtcrime.securesms.components.settings.app.chats.backups
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.BackupFrequency
|
||||||
import org.thoughtcrime.securesms.backup.v2.BackupV2Event
|
import org.thoughtcrime.securesms.backup.v2.BackupV2Event
|
||||||
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
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.jobs.BackupMessagesJob
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
|
import org.thoughtcrime.securesms.service.MessageBackupListener
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ViewModel for state management of RemoteBackupsSettingsFragment
|
* ViewModel for state management of RemoteBackupsSettingsFragment
|
||||||
|
@ -30,7 +32,8 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
|
||||||
null
|
null
|
||||||
},
|
},
|
||||||
lastBackupTimestamp = SignalStore.backup().lastBackupTime,
|
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)
|
internalState.value = state.value.copy(canBackUpUsingCellular = canBackUpUsingCellular)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setBackupsFrequency(backupsFrequency: MessageBackupsFrequency) {
|
fun setBackupsFrequency(backupsFrequency: BackupFrequency) {
|
||||||
// TODO [message-backups] -- Update via repository?
|
SignalStore.backup().backupFrequency = backupsFrequency
|
||||||
internalState.value = state.value.copy(backupsFrequency = backupsFrequency)
|
internalState.value = state.value.copy(backupsFrequency = backupsFrequency)
|
||||||
|
MessageBackupListener.setNextBackupTimeToIntervalFromNow()
|
||||||
|
MessageBackupListener.schedule(ApplicationDependencies.getApplication())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestDialog(dialog: RemoteBackupsSettingsState.Dialog) {
|
fun requestDialog(dialog: RemoteBackupsSettingsState.Dialog) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.keyvalue
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.backup.RestoreState
|
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.ArchiveServiceCredential
|
||||||
import org.whispersystems.signalservice.api.archive.GetArchiveCdnCredentialsResponse
|
import org.whispersystems.signalservice.api.archive.GetArchiveCdnCredentialsResponse
|
||||||
import org.whispersystems.signalservice.internal.util.JsonUtil
|
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_NEXT_BACKUP_TIME = "backup.nextBackupTime"
|
||||||
private const val KEY_LAST_BACKUP_TIME = "backup.lastBackupTime"
|
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_DIRECTORY = "backup.cdn.directory"
|
||||||
private const val KEY_CDN_BACKUP_MEDIA_DIRECTORY = "backup.cdn.mediaDirectory"
|
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 nextBackupTime: Long by longValue(KEY_NEXT_BACKUP_TIME, -1)
|
||||||
var lastBackupTime: Long by longValue(KEY_LAST_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
|
val totalBackupSize: Long get() = lastBackupProtoSize + usedBackupMediaSpace
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package org.thoughtcrime.securesms.service
|
package org.thoughtcrime.securesms.service
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.BackupFrequency
|
||||||
import org.thoughtcrime.securesms.jobs.BackupMessagesJob
|
import org.thoughtcrime.securesms.jobs.BackupMessagesJob
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags
|
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||||
|
@ -47,6 +48,12 @@ class MessageBackupListener : PersistentAlarmManagerListener() {
|
||||||
var next = now.withHour(hour).withMinute(minute).withSecond(0)
|
var next = now.withHour(hour).withMinute(minute).withSecond(0)
|
||||||
val jitter = Random().nextInt(BACKUP_JITTER_WINDOW_SECONDS) - BACKUP_JITTER_WINDOW_SECONDS / 2
|
val jitter = Random().nextInt(BACKUP_JITTER_WINDOW_SECONDS) - BACKUP_JITTER_WINDOW_SECONDS / 2
|
||||||
next.plusSeconds(jitter.toLong())
|
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)) {
|
if (now.isAfter(next)) {
|
||||||
next = next.plusDays(1)
|
next = next.plusDays(1)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue