Prepare backup destination UI refactoring

Mostly renaming for clarity.
This commit is contained in:
Torsten Grote 2024-04-09 17:22:46 -03:00
parent ec8190755e
commit 6788d0d25a
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
10 changed files with 74 additions and 40 deletions

View file

@ -1,4 +1,9 @@
package com.stevesoltys.seedvault.ui.storage
/*
* SPDX-FileCopyrightText: 2024 The Calyx Institute
* SPDX-License-Identifier: Apache-2.0
*/
package com.stevesoltys.seedvault.plugins.saf
import android.content.Context
import android.content.Intent
@ -9,8 +14,13 @@ import android.provider.DocumentsContract
import android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME
import android.provider.DocumentsContract.Document.COLUMN_DOCUMENT_ID
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.plugins.saf.StorageRootResolver.getIcon
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_DAVX5
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_NEXTCLOUD
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_ROUND_SYNC
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_STORAGE
import com.stevesoltys.seedvault.ui.storage.StorageOption
import com.stevesoltys.seedvault.ui.storage.StorageOption.SafOption
import com.stevesoltys.seedvault.ui.storage.StorageRootResolver.getIcon
private const val DAVX5_PACKAGE = "at.bitfire.davdroid"
private const val DAVX5_ACTIVITY = "at.bitfire.davdroid.ui.webdav.WebdavMountsActivity"
@ -29,15 +39,15 @@ internal class SafStorageOptions(
private val packageManager = context.packageManager
internal fun checkOrAddExtraRoots(roots: ArrayList<SafOption>) {
internal fun checkOrAddExtraRoots(roots: ArrayList<StorageOption>) {
checkOrAddUsbRoot(roots)
checkOrAddDavX5Root(roots)
checkOrAddNextCloudRoot(roots)
checkOrAddRoundSyncRoots(roots)
}
private fun checkOrAddUsbRoot(roots: ArrayList<SafOption>) {
if (doNotInclude(AUTHORITY_STORAGE, roots) { it.isUsb }) return
private fun checkOrAddUsbRoot(roots: ArrayList<StorageOption>) {
if (doNotInclude(AUTHORITY_STORAGE, roots) { it is SafOption && it.isUsb }) return
val root = SafOption(
authority = AUTHORITY_STORAGE,
@ -57,11 +67,11 @@ internal class SafStorageOptions(
/**
* Add a storage root for each child directory at the RoundSync root, if it exists.
*/
private fun checkOrAddRoundSyncRoots(roots: ArrayList<SafOption>) {
private fun checkOrAddRoundSyncRoots(roots: ArrayList<StorageOption>) {
val roundSyncRoot = roots.firstOrNull {
it.authority == AUTHORITY_ROUND_SYNC
} ?: return
it is SafOption && it.authority == AUTHORITY_ROUND_SYNC
} as? SafOption ?: return
roots.remove(roundSyncRoot)
@ -105,7 +115,7 @@ internal class SafStorageOptions(
*
* If it *is* installed and this is restore, the user can set up a new account by clicking.
*/
private fun checkOrAddDavX5Root(roots: ArrayList<SafOption>) {
private fun checkOrAddDavX5Root(roots: ArrayList<StorageOption>) {
if (doNotInclude(AUTHORITY_DAVX5, roots)) return
val intent = Intent().apply {
@ -155,7 +165,7 @@ internal class SafStorageOptions(
* because we don't know if there's just no account or an activated passcode
* (which hides existing accounts).
*/
private fun checkOrAddNextCloudRoot(roots: ArrayList<SafOption>) {
private fun checkOrAddNextCloudRoot(roots: ArrayList<StorageOption>) {
if (doNotInclude(AUTHORITY_NEXTCLOUD, roots)) return
val intent = Intent().apply {
@ -202,11 +212,12 @@ internal class SafStorageOptions(
private fun doNotInclude(
authority: String,
roots: ArrayList<SafOption>,
doNotIncludeIfTrue: ((SafOption) -> Boolean)? = null,
roots: ArrayList<StorageOption>,
doNotIncludeIfTrue: ((StorageOption) -> Boolean)? = null,
): Boolean {
if (!isAuthoritySupported(authority)) return true
for (root in roots) {
if (root !is SafOption) continue
if (root.authority == authority && doNotIncludeIfTrue?.invoke(root) != false) {
return true
}

View file

@ -1,4 +1,9 @@
package com.stevesoltys.seedvault.ui.storage
/*
* SPDX-FileCopyrightText: 2024 The Calyx Institute
* SPDX-License-Identifier: Apache-2.0
*/
package com.stevesoltys.seedvault.plugins.saf
import android.Manifest.permission.MANAGE_DOCUMENTS
import android.content.Context
@ -19,8 +24,16 @@ import android.provider.DocumentsContract.Root.FLAG_REMOVABLE_USB
import android.provider.DocumentsContract.Root.FLAG_SUPPORTS_CREATE
import android.provider.DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD
import android.util.Log
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.getStorageContext
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_DAVX5
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_DOWNLOADS
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_NEXTCLOUD
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_ROUND_SYNC
import com.stevesoltys.seedvault.ui.storage.AUTHORITY_STORAGE
import com.stevesoltys.seedvault.ui.storage.ROOT_ID_DEVICE
import com.stevesoltys.seedvault.ui.storage.ROOT_ID_HOME
import com.stevesoltys.seedvault.ui.storage.StorageOption.SafOption
internal object StorageRootResolver {
@ -126,23 +139,23 @@ internal object StorageRootResolver {
fun getIcon(context: Context, authority: String, rootId: String, icon: Int): Drawable? {
return getPackageIcon(context, authority, icon) ?: when {
authority == AUTHORITY_STORAGE && rootId == ROOT_ID_DEVICE -> {
context.getDrawable(R.drawable.ic_phone_android)
getDrawable(context, R.drawable.ic_phone_android)
}
authority == AUTHORITY_STORAGE && rootId != ROOT_ID_HOME -> {
context.getDrawable(R.drawable.ic_usb)
getDrawable(context, R.drawable.ic_usb)
}
authority == AUTHORITY_NEXTCLOUD -> {
context.getDrawable(R.drawable.nextcloud)
getDrawable(context, R.drawable.nextcloud)
}
authority == AUTHORITY_DAVX5 -> {
context.getDrawable(R.drawable.davx5)
getDrawable(context, R.drawable.davx5)
}
authority == AUTHORITY_ROUND_SYNC -> {
context.getDrawable(R.drawable.round_sync)
getDrawable(context, R.drawable.round_sync)
}
else -> null

View file

@ -31,7 +31,7 @@ internal class BackupStorageViewModel(
override val isRestoreOperation = false
override fun onLocationSet(uri: Uri) {
override fun onSafUriSet(uri: Uri) {
val isUsb = saveStorage(uri)
if (isUsb) {
// disable storage backup if new storage is on USB

View file

@ -22,7 +22,7 @@ internal class RestoreStorageViewModel(
override val isRestoreOperation = true
override fun onLocationSet(uri: Uri) {
override fun onSafUriSet(uri: Uri) {
viewModelScope.launch(Dispatchers.IO) {
val storage = createStorage(uri)
val hasBackup = try {

View file

@ -9,11 +9,11 @@ import android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.activity.result.contract.ActivityResultContracts.OpenDocumentTree
import androidx.annotation.CallSuper
import androidx.appcompat.app.AlertDialog
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.plugins.saf.StorageRootResolver
import com.stevesoltys.seedvault.ui.BackupActivity
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_RESTORE
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_SETUP_WIZARD
@ -82,14 +82,6 @@ class StorageActivity : BackupActivity() {
}
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 0) {
Log.d(TAG, "Blocking back button.")
} else {
super.onBackPressed()
}
}
private fun onInvalidLocation(errorMsg: String) {
if (viewModel.isRestoreOperation) {
val dialog = AlertDialog.Builder(this)

View file

@ -1,6 +1,7 @@
package com.stevesoltys.seedvault.ui.storage
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
@ -10,6 +11,7 @@ import android.view.ViewGroup
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.activity.addCallback
import androidx.fragment.app.Fragment
import com.stevesoltys.seedvault.R
@ -34,6 +36,14 @@ class StorageCheckFragment : Fragment() {
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requireActivity().onBackPressedDispatcher.addCallback(this) {
Log.i("StorageCheckFragment", "Not navigating back!")
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,

View file

@ -13,9 +13,11 @@ import android.provider.DocumentsContract.PROVIDER_INTERFACE
import android.provider.DocumentsContract.buildRootsUri
import android.util.Log
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.plugins.saf.SafStorageOptions
import com.stevesoltys.seedvault.plugins.saf.StorageRootResolver
import com.stevesoltys.seedvault.ui.storage.StorageOption.SafOption
private val TAG = StorageRootFetcher::class.java.simpleName
private val TAG = StorageOptionFetcher::class.java.simpleName
const val AUTHORITY_STORAGE = "com.android.externalstorage.documents"
const val ROOT_ID_DEVICE = "primary"
@ -30,7 +32,7 @@ internal interface RemovableStorageListener {
fun onStorageChanged()
}
internal class StorageRootFetcher(private val context: Context, private val isRestore: Boolean) {
internal class StorageOptionFetcher(private val context: Context, private val isRestore: Boolean) {
private val packageManager = context.packageManager
private val contentResolver = context.contentResolver
@ -60,7 +62,9 @@ internal class StorageRootFetcher(private val context: Context, private val isRe
internal fun getRemovableStorageListener() = listener
internal fun getStorageOptions(): List<StorageOption> {
val roots = ArrayList<SafOption>()
val roots = ArrayList<StorageOption>().apply {
add(WebDavOption(context))
}
val intent = Intent(PROVIDER_INTERFACE)
val providers = packageManager.queryIntentContentProviders(intent, 0)
for (info in providers) {

View file

@ -55,7 +55,7 @@ internal class StorageOptionsFragment : Fragment(), StorageOptionClickedListener
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
val v: View = inflater.inflate(R.layout.fragment_storage_root, container, false)
val v: View = inflater.inflate(R.layout.fragment_storage_options, container, false)
titleView = v.requireViewById(R.id.titleView)
warningIcon = v.requireViewById(R.id.warningIcon)

View file

@ -1,5 +1,6 @@
package com.stevesoltys.seedvault.ui.storage
import android.annotation.UiThread
import android.app.Application
import android.content.Context
import android.content.Context.USB_SERVICE
@ -11,6 +12,7 @@ import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.isMassStorage
import com.stevesoltys.seedvault.permitDiskReads
@ -21,6 +23,8 @@ import com.stevesoltys.seedvault.settings.Storage
import com.stevesoltys.seedvault.ui.LiveEvent
import com.stevesoltys.seedvault.ui.MutableLiveEvent
import com.stevesoltys.seedvault.ui.storage.StorageOption.SafOption
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
private val TAG = StorageViewModel::class.java.simpleName
@ -38,7 +42,7 @@ internal abstract class StorageViewModel(
protected val mLocationChecked = MutableLiveEvent<LocationResult>()
internal val locationChecked: LiveEvent<LocationResult> get() = mLocationChecked
private val storageRootFetcher by lazy { StorageRootFetcher(app, isRestoreOperation) }
private val storageOptionFetcher by lazy { StorageOptionFetcher(app, isRestoreOperation) }
private var safOption: SafOption? = null
internal var isSetupWizard: Boolean = false
@ -60,11 +64,11 @@ internal abstract class StorageViewModel(
}
internal fun loadStorageRoots() {
if (storageRootFetcher.getRemovableStorageListener() == null) {
storageRootFetcher.setRemovableStorageListener(this)
if (storageOptionFetcher.getRemovableStorageListener() == null) {
storageOptionFetcher.setRemovableStorageListener(this)
}
Thread {
mStorageOptions.postValue(storageRootFetcher.getStorageOptions())
mStorageOptions.postValue(storageOptionFetcher.getStorageOptions())
}.start()
}
@ -88,7 +92,7 @@ internal abstract class StorageViewModel(
val takeFlags = FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
app.contentResolver.takePersistableUriPermission(uri, takeFlags)
onLocationSet(uri)
onSafUriSet(uri)
}
/**
@ -144,10 +148,10 @@ internal abstract class StorageViewModel(
return false
}
abstract fun onLocationSet(uri: Uri)
abstract fun onSafUriSet(uri: Uri)
override fun onCleared() {
storageRootFetcher.setRemovableStorageListener(null)
storageOptionFetcher.setRemovableStorageListener(null)
super.onCleared()
}