Add warning dialogs when mixing local backups and optimize media.

This commit is contained in:
Cody Henthorne
2026-07-06 13:39:23 -03:00
committed by Alex Hart
parent 5a6b0cbfef
commit 9be6f488c4
8 changed files with 76 additions and 12 deletions
@@ -33,6 +33,7 @@ sealed interface LocalBackupsSettingsCallback {
fun onLearnMoreClick()
fun onLaunchBackupLocationPickerClick()
fun onTurnOffAndDeleteConfirmed()
fun onViewOptimizeStorageSettingClick()
object Empty : LocalBackupsSettingsCallback {
override fun onNavigationClick() = Unit
@@ -43,6 +44,7 @@ sealed interface LocalBackupsSettingsCallback {
override fun onLearnMoreClick() = Unit
override fun onLaunchBackupLocationPickerClick() = Unit
override fun onTurnOffAndDeleteConfirmed() = Unit
override fun onViewOptimizeStorageSettingClick() = Unit
}
}
@@ -144,4 +146,8 @@ class DefaultLocalBackupsSettingsCallback(
override fun onTurnOffAndDeleteConfirmed() {
viewModel.turnOffAndDelete(fragment.requireContext())
}
override fun onViewOptimizeStorageSettingClick() {
fragment.findNavController().safeNavigate(R.id.action_direct_to_storagePreferenceFragment)
}
}
@@ -53,6 +53,7 @@ internal fun LocalBackupsSettingsScreen(
val context = LocalContext.current
var showChooseLocationDialog by rememberSaveable { mutableStateOf(false) }
var showTurnOffAndDeleteDialog by rememberSaveable { mutableStateOf(false) }
var showOptimizeStorageWarningDialog by rememberSaveable { mutableStateOf(false) }
val learnMore = stringResource(id = R.string.BackupsPreferenceFragment__learn_more)
val restoreText = stringResource(id = R.string.OnDeviceBackupsScreen__to_restore_a_backup, learnMore).trim()
@@ -80,6 +81,14 @@ internal fun LocalBackupsSettingsScreen(
educationSheetMessage = stringResource(R.string.RemoteBackupsSettingsFragment__to_view_your_key)
)
val proceedWithTurnOn = {
if (BackupUtil.isUserSelectionRequired(context)) {
showChooseLocationDialog = true
} else {
callback.onTurnOnClick()
}
}
Scaffolds.Settings(
title = stringResource(id = R.string.RemoteBackupsSettingsFragment__on_device_backups),
navigationIcon = ImageVector.vectorResource(CoreUiR.drawable.symbol_arrow_start_24),
@@ -104,11 +113,10 @@ internal fun LocalBackupsSettingsScreen(
Buttons.MediumTonal(
onClick = {
// For the SAF-based flow, present an in-screen dialog before launching the picker.
if (BackupUtil.isUserSelectionRequired(context)) {
showChooseLocationDialog = true
if (state.optimizeStorageEnabled) {
showOptimizeStorageWarningDialog = true
} else {
callback.onTurnOnClick()
proceedWithTurnOn()
}
},
enabled = state.canTurnOn,
@@ -220,6 +228,24 @@ internal fun LocalBackupsSettingsScreen(
)
}
if (showOptimizeStorageWarningDialog) {
Dialogs.AdvancedAlertDialog(
body = stringResource(id = R.string.OnDeviceBackupsScreen__you_have_optimize_signal_storage_on),
positive = stringResource(id = R.string.OnDeviceBackupsScreen__view_setting),
neutral = stringResource(id = R.string.OnDeviceBackupsScreen__continue_without_turning_off),
negative = stringResource(id = android.R.string.cancel),
onPositive = {
showOptimizeStorageWarningDialog = false
callback.onViewOptimizeStorageSettingClick()
},
onNeutral = {
showOptimizeStorageWarningDialog = false
proceedWithTurnOn()
},
onNegative = { showOptimizeStorageWarningDialog = false }
)
}
if (showTurnOffAndDeleteDialog) {
Dialogs.SimpleAlertDialog(
title = stringResource(id = R.string.BackupDialog_delete_backups),
@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.keyvalue.protos.LocalBackupCreationProgress
data class LocalBackupsSettingsState(
val backupsEnabled: Boolean = false,
val canTurnOn: Boolean = true,
val optimizeStorageEnabled: Boolean = false,
val lastBackupLabel: String? = null,
val folderDisplayName: String? = null,
val scheduleTimeLabel: String? = null,
@@ -103,7 +103,8 @@ class LocalBackupsViewModel : ViewModel(), BackupKeyCredentialManagerHandler {
internalSettingsState.update {
it.copy(
canTurnOn = canTurnOn,
scheduleTimeLabel = backupTime
scheduleTimeLabel = backupTime,
optimizeStorageEnabled = SignalStore.backup.optimizeStorage
)
}
}
@@ -118,6 +118,8 @@ class ManageStorageSettingsFragment : ComposeFragment() {
navController.navigate("paid-tier-pending")
} else if (state.onDeviceStorageOptimizationState == ManageStorageSettingsViewModel.OnDeviceStorageOptimizationState.REQUIRES_PAID_TIER) {
UpgradeToEnableOptimizedStorageSheet().show(parentFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
} else if (enabled && state.localBackupsEnabled) {
navController.navigate("confirm-optimize-with-local-backup")
} else {
viewModel.setOptimizeStorage(enabled)
}
@@ -238,6 +240,17 @@ class ManageStorageSettingsFragment : ComposeFragment() {
)
}
dialog("confirm-optimize-with-local-backup") {
Dialogs.SimpleAlertDialog(
title = stringResource(id = R.string.ManageStorageSettingsFragment__media_will_be_removed_from_your_on_device_backup),
body = stringResource(id = R.string.ManageStorageSettingsFragment__turning_on_optimize_signal_storage_will_offload),
confirm = stringResource(id = R.string.ManageStorageSettingsFragment__turn_on),
dismiss = stringResource(id = android.R.string.cancel),
onConfirm = { viewModel.setOptimizeStorage(true) },
onDismiss = { navController.popBackStack() }
)
}
dialog(
route = "paid-tier-pending"
) {
@@ -35,7 +35,8 @@ class ManageStorageSettingsViewModel : ViewModel() {
ManageStorageState(
keepMessagesDuration = SignalStore.settings.keepMessagesDuration,
lengthLimit = if (SignalStore.settings.isTrimByLengthEnabled) SignalStore.settings.threadTrimLength else ManageStorageState.NO_LIMIT,
syncTrimDeletes = SignalStore.settings.shouldSyncThreadTrimDeletes()
syncTrimDeletes = SignalStore.settings.shouldSyncThreadTrimDeletes(),
localBackupsEnabled = SignalStore.backup.newLocalBackupsEnabled
)
)
val state = store.asStateFlow()
@@ -179,7 +180,8 @@ class ManageStorageSettingsViewModel : ViewModel() {
val breakdown: MediaTable.StorageBreakdown? = null,
val onDeviceStorageOptimizationState: OnDeviceStorageOptimizationState = OnDeviceStorageOptimizationState.FEATURE_NOT_AVAILABLE,
val storageOptimizationStateChanged: Boolean = false,
val isPaidTierPending: Boolean = false
val isPaidTierPending: Boolean = false,
val localBackupsEnabled: Boolean = false
) {
companion object {
const val NO_LIMIT = 0