From b6d519b19a7b77d65809097b8d06645add83bb95 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 10 Dec 2024 16:51:27 -0300 Subject: [PATCH] Allow changing backup location when flash drive isn't plugged in --- .../seedvault/settings/SettingsFragment.kt | 21 ++++++----- .../seedvault/settings/SettingsViewModel.kt | 35 ++++++++++++++----- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt index 073236d6a..597c275fe 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt @@ -27,6 +27,7 @@ import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.restore.RestoreActivity +import com.stevesoltys.seedvault.settings.BackupPermission.BackupAllowed import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import com.stevesoltys.seedvault.ui.toRelativeTime import org.calyxos.seedvault.core.backends.BackendProperties @@ -83,8 +84,8 @@ class SettingsFragment : PreferenceFragmentCompat() { trySetBackupEnabled(false) dialog.dismiss() } - .setNegativeButton(R.string.settings_backup_apk_dialog_cancel) { dialog, - _ -> dialog.dismiss() + .setNegativeButton(R.string.settings_backup_apk_dialog_cancel) { d, _ -> + d.dismiss() } .show() return@OnPreferenceChangeListener false @@ -143,12 +144,16 @@ class SettingsFragment : PreferenceFragmentCompat() { } } - viewModel.backupPossible.observe(viewLifecycleOwner) { possible -> - toolbar.menu.findItem(R.id.action_backup)?.isEnabled = possible - toolbar.menu.findItem(R.id.action_restore)?.isEnabled = possible - backupLocation.isEnabled = possible - backupAppCheck.isEnabled = possible - backupFileCheck.isEnabled = possible + viewModel.backupPossible.observe(viewLifecycleOwner) { permission -> + val allowed = permission == BackupAllowed + toolbar.menu.findItem(R.id.action_backup)?.isEnabled = allowed + toolbar.menu.findItem(R.id.action_restore)?.isEnabled = allowed + // backup location can be changed when backup isn't allowed, + // because flash-drive isn't plugged in + backupLocation.isEnabled = allowed || + (permission as? BackupPermission.BackupRestricted)?.unavailableUsb == true + backupAppCheck.isEnabled = allowed + backupFileCheck.isEnabled = allowed } viewModel.lastBackupTime.observe(viewLifecycleOwner) { time -> diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt index eac8aee2c..8fb9f40e6 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt @@ -39,6 +39,8 @@ import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.crypto.KeyManager import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.repo.Checker +import com.stevesoltys.seedvault.settings.BackupPermission.BackupAllowed +import com.stevesoltys.seedvault.settings.BackupPermission.BackupRestricted import com.stevesoltys.seedvault.storage.StorageBackupJobService import com.stevesoltys.seedvault.ui.LiveEvent import com.stevesoltys.seedvault.ui.MutableLiveEvent @@ -64,6 +66,11 @@ import java.util.concurrent.TimeUnit.HOURS private const val TAG = "SettingsViewModel" private const val USER_FULL_DATA_BACKUP_AWARE = "user_full_data_backup_aware" +sealed class BackupPermission { + object BackupAllowed : BackupPermission() + class BackupRestricted(val unavailableUsb: Boolean = false) : BackupPermission() +} + internal class SettingsViewModel( app: Application, settingsManager: SettingsManager, @@ -86,8 +93,8 @@ internal class SettingsViewModel( private val isBackupRunning: StateFlow private val isCheckOrPruneRunning: StateFlow - private val mBackupPossible = MutableLiveData(false) - val backupPossible: LiveData = mBackupPossible + private val mBackupPossible = MutableLiveData(BackupRestricted()) + val backupPossible: LiveData = mBackupPossible private val mBackupSize = MutableLiveData() val backupSize: LiveData = mBackupSize @@ -183,12 +190,24 @@ internal class SettingsViewModel( onStoragePropertiesChanged() } - private fun onBackupRunningStateChanged() { + private suspend fun onBackupRunningStateChanged() = withContext(Dispatchers.IO) { val backupAllowed = !isBackupRunning.value && !isCheckOrPruneRunning.value - if (backupAllowed) viewModelScope.launch(Dispatchers.IO) { - val canDo = !backendManager.isOnUnavailableUsb() - mBackupPossible.postValue(canDo) - } else mBackupPossible.postValue(false) + if (backupAllowed) { + if (backendManager.isOnUnavailableUsb()) { + updateBackupPossible(BackupRestricted(unavailableUsb = true)) + } else { + updateBackupPossible(BackupAllowed) + } + } else updateBackupPossible(BackupRestricted()) + } + + /** + * Updates [mBackupPossible] on the UiThread to avoid race conditions. + */ + private suspend fun updateBackupPossible(newValue: BackupPermission) { + withContext(Dispatchers.Main) { + mBackupPossible.value = newValue + } } private fun onStoragePropertiesChanged() { @@ -221,7 +240,7 @@ internal class SettingsViewModel( networkCallback.registered = true } // update whether we can do backups right now or not - onBackupRunningStateChanged() + viewModelScope.launch { onBackupRunningStateChanged() } } override fun onCleared() {