Ask on first run if user wants restore
This commit is contained in:
parent
cff5d20342
commit
22b3ace3aa
7 changed files with 79 additions and 28 deletions
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 The Calyx Institute
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.stevesoltys.seedvault.settings
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.stevesoltys.seedvault.R
|
||||
import com.stevesoltys.seedvault.restore.RestoreActivity
|
||||
|
||||
class FirstRunFragment : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
isCancelable = false // is what really works, specifying it for the dialog only doesn't
|
||||
return MaterialAlertDialogBuilder(requireContext())
|
||||
.setMessage(R.string.first_start_text)
|
||||
.setPositiveButton(R.string.setup_button) { dialog, _ ->
|
||||
parentFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment, SettingsFragment(), null)
|
||||
.commit()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNeutralButton(R.string.restore_backup_button) { dialog, _ ->
|
||||
val i = Intent(requireContext(), RestoreActivity::class.java)
|
||||
startActivity(i)
|
||||
dialog.dismiss()
|
||||
requireActivity().finish()
|
||||
}
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
}
|
||||
}
|
|
@ -6,17 +6,14 @@
|
|||
package com.stevesoltys.seedvault.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
|
||||
import com.stevesoltys.seedvault.R
|
||||
import com.stevesoltys.seedvault.ui.RequireProvisioningActivity
|
||||
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
|
||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||
import com.stevesoltys.seedvault.ui.recoverycode.ARG_FOR_NEW_CODE
|
||||
import com.stevesoltys.seedvault.ui.storage.StorageCheckFragment
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
internal const val ACTION_APP_STATUS_LIST = "com.stevesoltys.seedvault.APP_STATUS_LIST"
|
||||
|
@ -25,7 +22,6 @@ private const val PREF_BACKUP_RECOVERY_CODE = "backup_recovery_code"
|
|||
class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmentCallback {
|
||||
|
||||
private val viewModel: SettingsViewModel by viewModel()
|
||||
private val notificationManager: BackupNotificationManager by inject()
|
||||
|
||||
override fun getViewModel(): RequireProvisioningViewModel = viewModel
|
||||
|
||||
|
@ -37,8 +33,13 @@ class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmen
|
|||
setSupportActionBar(requireViewById(R.id.toolbar))
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
// always start with settings fragment as a base (when fresh start)
|
||||
if (savedInstanceState == null) showFragment(SettingsFragment())
|
||||
if (savedInstanceState == null && viewModel.isFirstStart) {
|
||||
// let user choose whether to restore on first start
|
||||
FirstRunFragment().show(supportFragmentManager, null)
|
||||
} else if (savedInstanceState == null) {
|
||||
// always start with settings fragment as a base (when fresh start)
|
||||
showFragment(SettingsFragment())
|
||||
}
|
||||
// add app status fragment on the stack, if started via intent
|
||||
if (intent?.action == ACTION_APP_STATUS_LIST) {
|
||||
showFragment(AppStatusFragment(), true)
|
||||
|
@ -58,24 +59,6 @@ class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmen
|
|||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// Activity results from the parent will get delivered before and might tell us to finish.
|
||||
// Don't start any new activities when that happens.
|
||||
// Note: onStart() can get called *before* results get delivered, so we use onResume() here
|
||||
if (isFinishing) return
|
||||
|
||||
// check that backup is provisioned
|
||||
if (!viewModel.recoveryCodeIsSet()) {
|
||||
showRecoveryCodeActivity()
|
||||
} else if (!viewModel.validLocationIsSet()) {
|
||||
showStorageActivity()
|
||||
// remove potential error notifications
|
||||
notificationManager.onBackupErrorSeen()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreferenceStartFragment(
|
||||
caller: PreferenceFragmentCompat,
|
||||
pref: Preference,
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.stevesoltys.seedvault.permitDiskReads
|
|||
import com.stevesoltys.seedvault.plugins.StoragePluginManager
|
||||
import com.stevesoltys.seedvault.plugins.StorageProperties
|
||||
import com.stevesoltys.seedvault.restore.RestoreActivity
|
||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||
import com.stevesoltys.seedvault.ui.toRelativeTime
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
|
@ -42,6 +43,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
private val viewModel: SettingsViewModel by sharedViewModel()
|
||||
private val storagePluginManager: StoragePluginManager by inject()
|
||||
private val backupManager: IBackupManager by inject()
|
||||
private val notificationManager: BackupNotificationManager by inject()
|
||||
|
||||
private lateinit var backup: TwoStatePreference
|
||||
private lateinit var autoRestore: TwoStatePreference
|
||||
|
@ -184,6 +186,24 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
setAppBackupSchedulingSummary(viewModel.appBackupWorkInfo.value)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// Activity results from the parent will get delivered before and might tell us to finish.
|
||||
// Don't start any new activities when that happens.
|
||||
// Note: onStart() can get called *before* results get delivered, so we use onResume() here
|
||||
if (requireActivity().isFinishing) return
|
||||
|
||||
// check that backup is provisioned
|
||||
val activity = requireActivity() as SettingsActivity
|
||||
if (!viewModel.recoveryCodeIsSet()) {
|
||||
activity.showRecoveryCodeActivity()
|
||||
} else if (!viewModel.validLocationIsSet()) {
|
||||
activity.showStorageActivity()
|
||||
// remove potential error notifications
|
||||
notificationManager.onBackupErrorSeen()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.settings_menu, menu)
|
||||
|
|
|
@ -247,6 +247,14 @@ class SettingsManager(private val context: Context) {
|
|||
.putBoolean(PREF_KEY_D2D_BACKUPS, enabled)
|
||||
.apply()
|
||||
}
|
||||
|
||||
/**
|
||||
* This assumes that if there's no storage plugin set, it is the first start.
|
||||
* We enforce a storage plugin and don't allow unsetting one,
|
||||
* so this should be a safe assumption.
|
||||
*/
|
||||
val isFirstStart get() = prefs.getString(PREF_KEY_STORAGE_PLUGIN, null) == null
|
||||
|
||||
}
|
||||
|
||||
data class FlashDrive(
|
||||
|
|
|
@ -85,6 +85,7 @@ internal class SettingsViewModel(
|
|||
private val workManager = WorkManager.getInstance(app)
|
||||
|
||||
override val isRestoreOperation = false
|
||||
val isFirstStart get() = settingsManager.isFirstStart
|
||||
|
||||
val isBackupRunning: StateFlow<Boolean>
|
||||
private val mBackupPossible = MutableLiveData(false)
|
||||
|
|
|
@ -56,12 +56,12 @@ abstract class RequireProvisioningActivity : BackupActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
getViewModel().chooseBackupLocation.observeEvent(this, { show ->
|
||||
getViewModel().chooseBackupLocation.observeEvent(this) { show ->
|
||||
if (show) showStorageActivity()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
protected fun showStorageActivity() {
|
||||
fun showStorageActivity() {
|
||||
val intent = Intent(this, StorageActivity::class.java).apply {
|
||||
putExtra(INTENT_EXTRA_IS_RESTORE, getViewModel().isRestoreOperation)
|
||||
putExtra(INTENT_EXTRA_IS_SETUP_WIZARD, isSetupWizard)
|
||||
|
@ -69,7 +69,7 @@ abstract class RequireProvisioningActivity : BackupActivity() {
|
|||
requestLocation.launch(intent)
|
||||
}
|
||||
|
||||
protected fun showRecoveryCodeActivity() {
|
||||
fun showRecoveryCodeActivity() {
|
||||
val intent = Intent(this, RecoveryCodeActivity::class.java).apply {
|
||||
putExtra(INTENT_EXTRA_IS_RESTORE, getViewModel().isRestoreOperation)
|
||||
putExtra(INTENT_EXTRA_IS_SETUP_WIZARD, isSetupWizard)
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
<string name="data_management_label">Seedvault Backup</string>
|
||||
<string name="current_destination_string">Backup status and settings</string>
|
||||
|
||||
<string name="first_start_text">Do you want to restore your device from an existing backup or start a new backup?</string>
|
||||
<string name="restore_backup_button">Restore backup</string>
|
||||
<string name="setup_button">Start new</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="settings_category_apps">App backup</string>
|
||||
|
|
Loading…
Reference in a new issue