Merge branch 'prefs' into 'develop'

Modernize Activity launching to set custom cache location

See merge request ultrasonic/ultrasonic!1015
This commit is contained in:
birdbird 2023-05-18 10:32:17 +00:00
commit 0cfd8e8240
4 changed files with 76 additions and 71 deletions

View File

@ -1,14 +1,11 @@
package org.moire.ultrasonic.fragment
import android.app.Activity
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.DocumentsContract
import android.provider.SearchRecentSuggestions
import android.view.View
import androidx.annotation.StringRes
@ -38,6 +35,7 @@ import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.ErrorDialog
import org.moire.ultrasonic.util.FileUtil.ultrasonicDirectory
import org.moire.ultrasonic.util.InfoDialog
import org.moire.ultrasonic.util.SelectCacheActivityContract
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Settings.id3TagsEnabledOnline
import org.moire.ultrasonic.util.Settings.preferences
@ -100,64 +98,14 @@ class SettingsFragment :
updateCustomPreferences()
}
/**
* This function will be called when we return from the file picker
* with a new custom cache location
*
* TODO: This method has been deprecated in favor of using the Activity Result API
* which brings increased type safety via an ActivityResultContract and the prebuilt
* contracts for common intents available in
* androidx.activity.result.contract.ActivityResultContracts,
* provides hooks for testing, and allow receiving results in separate,
* testable classes independent from your fragment.
* Use registerForActivityResult(ActivityResultContract, ActivityResultCallback) with the
* appropriate ActivityResultContract and handling the result in the callback.
*/
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (
requestCode == SELECT_CACHE_ACTIVITY &&
resultCode == Activity.RESULT_OK &&
resultData != null
) {
val read = (resultData.flags and Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
val write = (resultData.flags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
val persist = (resultData.flags and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0
if (read && write && persist) {
if (resultData.data != null) {
// The result data contains a URI for the document or directory that
// the user selected.
val uri = resultData.data!!
val contentResolver = UApp.applicationContext().contentResolver
contentResolver.takePersistableUriPermission(uri, RW_FLAG)
setCacheLocation(uri.toString())
setupCacheLocationPreference()
return
}
}
ErrorDialog.Builder(requireContext())
.setMessage(R.string.settings_cache_location_error)
.show()
}
if (Settings.cacheLocationUri == "") {
Settings.customCacheLocation = false
customCacheLocation?.isChecked = false
setupCacheLocationPreference()
}
}
override fun onResume() {
super.onResume()
val preferences = preferences
preferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
super.onPause()
val prefs = preferences
prefs.unregisterOnSharedPreferenceChangeListener(this)
preferences.unregisterOnSharedPreferenceChangeListener(this)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
@ -249,19 +197,31 @@ class SettingsFragment :
}
private fun selectCacheLocation() {
// Choose a directory using the system's file picker.
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
if (Settings.cacheLocationUri != "" && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Settings.cacheLocationUri)
}
intent.addFlags(RW_FLAG)
intent.addFlags(PERSISTABLE_FLAG)
startActivityForResult(intent, SELECT_CACHE_ACTIVITY)
// Start the activity to pick a directory using the system's file picker.
selectCacheActivityContract.launch(Settings.cacheLocationUri)
}
// Custom activity result contract
private val selectCacheActivityContract =
registerForActivityResult(SelectCacheActivityContract()) { uri ->
// parseResult will return the chosen path as an Uri
if (uri != null) {
val contentResolver = UApp.applicationContext().contentResolver
contentResolver.takePersistableUriPermission(uri, RW_FLAG)
setCacheLocation(uri.toString())
setupCacheLocationPreference()
} else {
ErrorDialog.Builder(requireContext())
.setMessage(R.string.settings_cache_location_error)
.show()
if (Settings.cacheLocationUri == "") {
Settings.customCacheLocation = false
customCacheLocation?.isChecked = false
setupCacheLocationPreference()
}
}
}
private fun setupBluetoothDevicePreferences() {
val resumeSetting = Settings.resumeOnBluetoothDevice
val pauseSetting = Settings.pauseOnBluetoothDevice
@ -425,7 +385,6 @@ class SettingsFragment :
}
companion object {
const val SELECT_CACHE_ACTIVITY = 161161
const val RW_FLAG = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
const val PERSISTABLE_FLAG = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION

View File

@ -0,0 +1,49 @@
/*
* SelectCacheActivityContract.kt
* Copyright (C) 2009-2023 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.util
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.DocumentsContract
import androidx.activity.result.contract.ActivityResultContract
import org.moire.ultrasonic.fragment.SettingsFragment
class SelectCacheActivityContract : ActivityResultContract<String?, Uri?>() {
override fun createIntent(context: Context, input: String?): Intent {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
if (Settings.cacheLocationUri != "" && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, input)
}
intent.addFlags(SettingsFragment.RW_FLAG)
intent.addFlags(SettingsFragment.PERSISTABLE_FLAG)
return intent
}
override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
if (
resultCode == Activity.RESULT_OK &&
intent != null
) {
val read = (intent.flags and Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
val write = (intent.flags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
val persist = (intent.flags and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0
if (read && write && persist) {
if (intent.data != null) {
// The result data contains a URI for the document or directory that
// the user selected.
return intent.data!!
}
}
}
return null
}
}

View File

@ -48,7 +48,6 @@ object Settings {
@JvmStatic
val preloadCount: Int
get() {
val preferences = preferences
val preloadCount =
preferences.getString(getKey(R.string.setting_key_preload_count), "-1")!!
.toInt()
@ -60,7 +59,6 @@ object Settings {
@JvmStatic
val cacheSizeMB: Int
get() {
val preferences = preferences
val cacheSize = preferences.getString(
getKey(R.string.setting_key_cache_size),
"-1"
@ -209,7 +207,6 @@ object Settings {
@JvmStatic
val shareGreeting: String?
get() {
val preferences = preferences
val context = Util.appContext()
val defaultVal = String.format(
context.resources.getString(R.string.share_default_greeting),
@ -278,8 +275,7 @@ object Settings {
}
fun getAllKeys(): List<String> {
val prefs = PreferenceManager.getDefaultSharedPreferences(UApp.applicationContext())
return prefs.all.keys.toList()
return preferences.all.keys.toList()
}
private val appContext: Context

View File

@ -833,6 +833,7 @@ object Util {
Timber.d("Current user preferences")
Timber.d("========================")
val keys = Settings.preferences.all
keys.forEach {
Timber.d("${it.key}: ${it.value}")
}