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
|
package com.stevesoltys.seedvault.settings
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.annotation.CallSuper
|
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
|
import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.ui.RequireProvisioningActivity
|
import com.stevesoltys.seedvault.ui.RequireProvisioningActivity
|
||||||
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
|
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.recoverycode.ARG_FOR_NEW_CODE
|
||||||
import com.stevesoltys.seedvault.ui.storage.StorageCheckFragment
|
import com.stevesoltys.seedvault.ui.storage.StorageCheckFragment
|
||||||
import org.koin.android.ext.android.inject
|
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
internal const val ACTION_APP_STATUS_LIST = "com.stevesoltys.seedvault.APP_STATUS_LIST"
|
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 {
|
class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmentCallback {
|
||||||
|
|
||||||
private val viewModel: SettingsViewModel by viewModel()
|
private val viewModel: SettingsViewModel by viewModel()
|
||||||
private val notificationManager: BackupNotificationManager by inject()
|
|
||||||
|
|
||||||
override fun getViewModel(): RequireProvisioningViewModel = viewModel
|
override fun getViewModel(): RequireProvisioningViewModel = viewModel
|
||||||
|
|
||||||
|
@ -37,8 +33,13 @@ class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmen
|
||||||
setSupportActionBar(requireViewById(R.id.toolbar))
|
setSupportActionBar(requireViewById(R.id.toolbar))
|
||||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
|
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)
|
// always start with settings fragment as a base (when fresh start)
|
||||||
if (savedInstanceState == null) showFragment(SettingsFragment())
|
showFragment(SettingsFragment())
|
||||||
|
}
|
||||||
// add app status fragment on the stack, if started via intent
|
// add app status fragment on the stack, if started via intent
|
||||||
if (intent?.action == ACTION_APP_STATUS_LIST) {
|
if (intent?.action == ACTION_APP_STATUS_LIST) {
|
||||||
showFragment(AppStatusFragment(), true)
|
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(
|
override fun onPreferenceStartFragment(
|
||||||
caller: PreferenceFragmentCompat,
|
caller: PreferenceFragmentCompat,
|
||||||
pref: Preference,
|
pref: Preference,
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.stevesoltys.seedvault.permitDiskReads
|
||||||
import com.stevesoltys.seedvault.plugins.StoragePluginManager
|
import com.stevesoltys.seedvault.plugins.StoragePluginManager
|
||||||
import com.stevesoltys.seedvault.plugins.StorageProperties
|
import com.stevesoltys.seedvault.plugins.StorageProperties
|
||||||
import com.stevesoltys.seedvault.restore.RestoreActivity
|
import com.stevesoltys.seedvault.restore.RestoreActivity
|
||||||
|
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||||
import com.stevesoltys.seedvault.ui.toRelativeTime
|
import com.stevesoltys.seedvault.ui.toRelativeTime
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
@ -42,6 +43,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
private val viewModel: SettingsViewModel by sharedViewModel()
|
private val viewModel: SettingsViewModel by sharedViewModel()
|
||||||
private val storagePluginManager: StoragePluginManager by inject()
|
private val storagePluginManager: StoragePluginManager by inject()
|
||||||
private val backupManager: IBackupManager by inject()
|
private val backupManager: IBackupManager by inject()
|
||||||
|
private val notificationManager: BackupNotificationManager by inject()
|
||||||
|
|
||||||
private lateinit var backup: TwoStatePreference
|
private lateinit var backup: TwoStatePreference
|
||||||
private lateinit var autoRestore: TwoStatePreference
|
private lateinit var autoRestore: TwoStatePreference
|
||||||
|
@ -184,6 +186,24 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
setAppBackupSchedulingSummary(viewModel.appBackupWorkInfo.value)
|
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) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
inflater.inflate(R.menu.settings_menu, menu)
|
inflater.inflate(R.menu.settings_menu, menu)
|
||||||
|
|
|
@ -247,6 +247,14 @@ class SettingsManager(private val context: Context) {
|
||||||
.putBoolean(PREF_KEY_D2D_BACKUPS, enabled)
|
.putBoolean(PREF_KEY_D2D_BACKUPS, enabled)
|
||||||
.apply()
|
.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(
|
data class FlashDrive(
|
||||||
|
|
|
@ -85,6 +85,7 @@ internal class SettingsViewModel(
|
||||||
private val workManager = WorkManager.getInstance(app)
|
private val workManager = WorkManager.getInstance(app)
|
||||||
|
|
||||||
override val isRestoreOperation = false
|
override val isRestoreOperation = false
|
||||||
|
val isFirstStart get() = settingsManager.isFirstStart
|
||||||
|
|
||||||
val isBackupRunning: StateFlow<Boolean>
|
val isBackupRunning: StateFlow<Boolean>
|
||||||
private val mBackupPossible = MutableLiveData(false)
|
private val mBackupPossible = MutableLiveData(false)
|
||||||
|
|
|
@ -56,12 +56,12 @@ abstract class RequireProvisioningActivity : BackupActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
getViewModel().chooseBackupLocation.observeEvent(this, { show ->
|
getViewModel().chooseBackupLocation.observeEvent(this) { show ->
|
||||||
if (show) showStorageActivity()
|
if (show) showStorageActivity()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun showStorageActivity() {
|
fun showStorageActivity() {
|
||||||
val intent = Intent(this, StorageActivity::class.java).apply {
|
val intent = Intent(this, StorageActivity::class.java).apply {
|
||||||
putExtra(INTENT_EXTRA_IS_RESTORE, getViewModel().isRestoreOperation)
|
putExtra(INTENT_EXTRA_IS_RESTORE, getViewModel().isRestoreOperation)
|
||||||
putExtra(INTENT_EXTRA_IS_SETUP_WIZARD, isSetupWizard)
|
putExtra(INTENT_EXTRA_IS_SETUP_WIZARD, isSetupWizard)
|
||||||
|
@ -69,7 +69,7 @@ abstract class RequireProvisioningActivity : BackupActivity() {
|
||||||
requestLocation.launch(intent)
|
requestLocation.launch(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun showRecoveryCodeActivity() {
|
fun showRecoveryCodeActivity() {
|
||||||
val intent = Intent(this, RecoveryCodeActivity::class.java).apply {
|
val intent = Intent(this, RecoveryCodeActivity::class.java).apply {
|
||||||
putExtra(INTENT_EXTRA_IS_RESTORE, getViewModel().isRestoreOperation)
|
putExtra(INTENT_EXTRA_IS_RESTORE, getViewModel().isRestoreOperation)
|
||||||
putExtra(INTENT_EXTRA_IS_SETUP_WIZARD, isSetupWizard)
|
putExtra(INTENT_EXTRA_IS_SETUP_WIZARD, isSetupWizard)
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
<string name="data_management_label">Seedvault Backup</string>
|
<string name="data_management_label">Seedvault Backup</string>
|
||||||
<string name="current_destination_string">Backup status and settings</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="restore_backup_button">Restore backup</string>
|
||||||
|
<string name="setup_button">Start new</string>
|
||||||
|
|
||||||
<!-- Settings -->
|
<!-- Settings -->
|
||||||
<string name="settings_category_apps">App backup</string>
|
<string name="settings_category_apps">App backup</string>
|
||||||
|
|
Loading…
Reference in a new issue