Reorganize settings

This commit is contained in:
Koitharu
2023-06-05 12:53:12 +03:00
parent e794f84c6f
commit bc3a7fc211
23 changed files with 333 additions and 252 deletions

View File

@@ -9,10 +9,10 @@ import androidx.core.view.updatePadding
import androidx.preference.PreferenceFragmentCompat
import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.core.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.settings.SettingsActivity
import javax.inject.Inject
@Suppress("LeakingThis")
@@ -44,9 +44,7 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) :
override fun onResume() {
super.onResume()
if (titleId != 0) {
setTitle(getString(titleId))
}
setTitle(if (titleId != 0) getString(titleId) else null)
}
@CallSuper
@@ -56,11 +54,7 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) :
)
}
protected fun setTitle(title: CharSequence) {
activity?.let {
if (!it.resources.getBoolean(R.bool.is_tablet)) {
it.title = title
}
}
protected fun setTitle(title: CharSequence?) {
(activity as? SettingsActivity)?.setSectionTitle(title)
}
}

View File

@@ -12,7 +12,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.AlertDialogFragment
import org.koitharu.kotatsu.databinding.DialogImportBinding
import org.koitharu.kotatsu.settings.backup.BackupDialogFragment
import org.koitharu.kotatsu.settings.backup.RestoreDialogFragment
class ImportDialogFragment : AlertDialogFragment<DialogImportBinding>(), View.OnClickListener {
@@ -64,9 +63,10 @@ class ImportDialogFragment : AlertDialogFragment<DialogImportBinding>(), View.On
}
private fun restoreBackup(uri: Uri?) {
RestoreDialogFragment.newInstance(uri ?: return)
.show(parentFragmentManager, BackupDialogFragment.TAG)
dismiss()
if (uri != null) {
RestoreDialogFragment.show(parentFragmentManager, uri)
dismiss()
}
}
companion object {

View File

@@ -3,67 +3,42 @@ package org.koitharu.kotatsu.settings
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.preference.ListPreference
import androidx.preference.Preference
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.cache.ContentCache
import org.koitharu.kotatsu.core.network.DoHProvider
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.ui.dialog.StorageSelectDialog
import org.koitharu.kotatsu.core.util.ext.getStorageName
import org.koitharu.kotatsu.core.util.ext.setDefaultValueCompat
import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.parsers.util.names
import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import java.io.File
import java.net.Proxy
import javax.inject.Inject
@AndroidEntryPoint
class ContentSettingsFragment :
BasePreferenceFragment(R.string.content),
class DownloadsSettingsFragment :
BasePreferenceFragment(R.string.downloads),
SharedPreferences.OnSharedPreferenceChangeListener,
StorageSelectDialog.OnStorageSelectListener {
@Inject
lateinit var storageManager: LocalStorageManager
@Inject
lateinit var contentCache: ContentCache
@Inject
lateinit var downloadsScheduler: DownloadWorker.Scheduler
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_content)
findPreference<Preference>(AppSettings.KEY_PREFETCH_CONTENT)?.isVisible = contentCache.isCachingEnabled
findPreference<ListPreference>(AppSettings.KEY_DOH)?.run {
entryValues = arrayOf(
DoHProvider.NONE,
DoHProvider.GOOGLE,
DoHProvider.CLOUDFLARE,
DoHProvider.ADGUARD,
).names()
setDefaultValueCompat(DoHProvider.NONE.name)
}
addPreferencesFromResource(R.xml.pref_downloads)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
findPreference<Preference>(AppSettings.KEY_LOCAL_STORAGE)?.bindStorageName()
findPreference<Preference>(AppSettings.KEY_SUGGESTIONS)?.setSummary(
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled,
)
bindRemoteSourcesSummary()
bindProxySummary()
settings.subscribe(this)
}
@@ -78,29 +53,9 @@ class ContentSettingsFragment :
findPreference<Preference>(key)?.bindStorageName()
}
AppSettings.KEY_SUGGESTIONS -> {
findPreference<Preference>(AppSettings.KEY_SUGGESTIONS)?.setSummary(
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled,
)
}
AppSettings.KEY_SOURCES_HIDDEN -> {
bindRemoteSourcesSummary()
}
AppSettings.KEY_DOWNLOADS_WIFI -> {
updateDownloadsConstraints()
}
AppSettings.KEY_SSL_BYPASS -> {
Snackbar.make(listView, R.string.settings_apply_restart_required, Snackbar.LENGTH_INDEFINITE).show()
}
AppSettings.KEY_PROXY_TYPE,
AppSettings.KEY_PROXY_ADDRESS,
AppSettings.KEY_PROXY_PORT -> {
bindProxySummary()
}
}
}
@@ -131,26 +86,6 @@ class ContentSettingsFragment :
}
}
private fun bindRemoteSourcesSummary() {
findPreference<Preference>(AppSettings.KEY_REMOTE_SOURCES)?.run {
val total = settings.remoteMangaSources.size
summary = getString(R.string.enabled_d_of_d, total - settings.hiddenSources.size, total)
}
}
private fun bindProxySummary() {
findPreference<Preference>(AppSettings.KEY_PROXY)?.run {
val type = settings.proxyType
val address = settings.proxyAddress
val port = settings.proxyPort
summary = if (type == Proxy.Type.DIRECT || address.isNullOrEmpty() || port == 0) {
context.getString(R.string.disabled)
} else {
"$address:$port"
}
}
}
private fun updateDownloadsConstraints() {
val preference = findPreference<Preference>(AppSettings.KEY_DOWNLOADS_WIFI)
viewLifecycleScope.launch {

View File

@@ -0,0 +1,79 @@
package org.koitharu.kotatsu.settings
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.preference.ListPreference
import androidx.preference.Preference
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.cache.ContentCache
import org.koitharu.kotatsu.core.network.DoHProvider
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.util.ext.setDefaultValueCompat
import org.koitharu.kotatsu.parsers.util.names
import java.net.Proxy
import javax.inject.Inject
@AndroidEntryPoint
class NetworkSettingsFragment :
BasePreferenceFragment(R.string.network),
SharedPreferences.OnSharedPreferenceChangeListener {
@Inject
lateinit var contentCache: ContentCache
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_network)
findPreference<Preference>(AppSettings.KEY_PREFETCH_CONTENT)?.isVisible = contentCache.isCachingEnabled
findPreference<ListPreference>(AppSettings.KEY_DOH)?.run {
entryValues = arrayOf(
DoHProvider.NONE,
DoHProvider.GOOGLE,
DoHProvider.CLOUDFLARE,
DoHProvider.ADGUARD,
).names()
setDefaultValueCompat(DoHProvider.NONE.name)
}
bindProxySummary()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
settings.subscribe(this)
}
override fun onDestroyView() {
settings.unsubscribe(this)
super.onDestroyView()
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences?, key: String?) {
when (key) {
AppSettings.KEY_SSL_BYPASS -> {
Snackbar.make(listView, R.string.settings_apply_restart_required, Snackbar.LENGTH_INDEFINITE).show()
}
AppSettings.KEY_PROXY_TYPE,
AppSettings.KEY_PROXY_ADDRESS,
AppSettings.KEY_PROXY_PORT -> {
bindProxySummary()
}
}
}
private fun bindProxySummary() {
findPreference<Preference>(AppSettings.KEY_PROXY)?.run {
val type = settings.proxyType
val address = settings.proxyAddress
val port = settings.proxyPort
summary = if (type == Proxy.Type.DIRECT || address.isNullOrEmpty() || port == 0) {
context.getString(R.string.disabled)
} else {
"$address:$port"
}
}
}
}

View File

@@ -4,7 +4,7 @@ import android.os.Bundle
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
class RootSettingsFragment : BasePreferenceFragment(R.string.settings) {
class RootSettingsFragment : BasePreferenceFragment(0) {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_root)

View File

@@ -3,8 +3,10 @@ package org.koitharu.kotatsu.settings
import android.accounts.AccountManager
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.preference.Preference
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
@@ -27,7 +29,8 @@ import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import javax.inject.Inject
@AndroidEntryPoint
class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) {
class ServicesSettingsFragment : BasePreferenceFragment(R.string.services),
SharedPreferences.OnSharedPreferenceChangeListener {
@Inject
lateinit var shikimoriRepository: ShikimoriRepository
@@ -43,6 +46,17 @@ class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_services)
bindSuggestionsSummary()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
settings.subscribe(this)
}
override fun onDestroyView() {
settings.unsubscribe(this)
super.onDestroyView()
}
override fun onResume() {
@@ -53,6 +67,13 @@ class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) {
bindSyncSummary()
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences?, key: String?) {
when (key) {
AppSettings.KEY_SUGGESTIONS -> bindSuggestionsSummary()
}
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
return when (preference.key) {
AppSettings.KEY_SHIKIMORI -> {
@@ -156,4 +177,10 @@ class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) {
findPreference<Preference>(AppSettings.KEY_SYNC_SETTINGS)?.isEnabled = account != null
}
}
private fun bindSuggestionsSummary() {
findPreference<Preference>(AppSettings.KEY_SUGGESTIONS)?.setSummary(
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled,
)
}
}

View File

@@ -24,6 +24,7 @@ import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
import org.koitharu.kotatsu.core.util.ext.isScrolledToTop
import org.koitharu.kotatsu.core.util.ext.textAndVisible
import org.koitharu.kotatsu.databinding.ActivitySettingsBinding
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
import org.koitharu.kotatsu.parsers.model.MangaSource
@@ -121,6 +122,12 @@ class SettingsActivity :
}
}
fun setSectionTitle(title: CharSequence?) {
viewBinding.textViewHeader?.apply {
textAndVisible = title
} ?: setTitle(title ?: getString(R.string.settings))
}
fun openFragment(fragment: Fragment, isFromRoot: Boolean) {
val hasFragment = supportFragmentManager.findFragmentById(R.id.container) != null
val isMasterDetail = viewBinding.containerMaster != null
@@ -139,7 +146,7 @@ class SettingsActivity :
val fragment = when (intent?.action) {
ACTION_READER -> ReaderSettingsFragment()
ACTION_SUGGESTIONS -> SuggestionsSettingsFragment()
ACTION_HISTORY -> HistorySettingsFragment()
ACTION_HISTORY -> UserDataSettingsFragment()
ACTION_TRACKER -> TrackerSettingsFragment()
ACTION_SOURCE -> SourceSettingsFragment.newInstance(
intent.getSerializableExtraCompat(EXTRA_SOURCE) as? MangaSource ?: MangaSource.LOCAL,

View File

@@ -1,7 +1,11 @@
package org.koitharu.kotatsu.settings
import android.content.ActivityNotFoundException
import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.Lifecycle
import androidx.preference.Preference
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@@ -24,11 +28,14 @@ import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
import org.koitharu.kotatsu.local.data.CacheDir
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
import org.koitharu.kotatsu.settings.backup.BackupDialogFragment
import org.koitharu.kotatsu.settings.backup.RestoreDialogFragment
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import javax.inject.Inject
@AndroidEntryPoint
class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cache) {
class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privacy), ActivityResultCallback<Uri?> {
@Inject
lateinit var trackerRepo: TrackingRepository
@@ -48,8 +55,13 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
@Inject
lateinit var shortcutsUpdater: ShortcutsUpdater
private val backupSelectCall = registerForActivityResult(
ActivityResultContracts.OpenDocument(),
this,
)
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_history)
addPreferencesFromResource(R.xml.pref_user_data)
findPreference<Preference>(AppSettings.KEY_SHORTCUTS)?.isVisible =
shortcutsUpdater.isDynamicShortcutsAvailable()
}
@@ -116,10 +128,33 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
true
}
AppSettings.KEY_BACKUP -> {
BackupDialogFragment.show(childFragmentManager)
true
}
AppSettings.KEY_RESTORE -> {
try {
backupSelectCall.launch(arrayOf("*/*"))
} catch (e: ActivityNotFoundException) {
e.printStackTraceDebug()
Snackbar.make(
listView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT,
).show()
}
true
}
else -> super.onPreferenceTreeClick(preference)
}
}
override fun onActivityResult(result: Uri?) {
if (result != null) {
RestoreDialogFragment.show(childFragmentManager, result)
}
}
private fun clearCache(preference: Preference, cache: CacheDir) {
val ctx = preference.context.applicationContext
viewLifecycleScope.launch {

View File

@@ -7,6 +7,7 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.viewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
@@ -101,6 +102,10 @@ class BackupDialogFragment : AlertDialogFragment<DialogProgressBinding>() {
companion object {
const val TAG = "BackupDialogFragment"
private const val TAG = "BackupDialogFragment"
fun show(fm: FragmentManager) {
BackupDialogFragment().show(fm, TAG)
}
}
}

View File

@@ -1,55 +0,0 @@
package org.koitharu.kotatsu.settings.backup
import android.content.ActivityNotFoundException
import android.net.Uri
import android.os.Bundle
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.preference.Preference
import com.google.android.material.snackbar.Snackbar
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
import org.koitharu.kotatsu.util.ext.printStackTraceDebug
class BackupSettingsFragment :
BasePreferenceFragment(R.string.backup_restore),
ActivityResultCallback<Uri?> {
private val backupSelectCall = registerForActivityResult(
ActivityResultContracts.OpenDocument(),
this,
)
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_backup)
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
return when (preference.key) {
AppSettings.KEY_BACKUP -> {
BackupDialogFragment().show(childFragmentManager, BackupDialogFragment.TAG)
true
}
AppSettings.KEY_RESTORE -> {
try {
backupSelectCall.launch(arrayOf("*/*"))
} catch (e: ActivityNotFoundException) {
e.printStackTraceDebug()
Snackbar.make(
listView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT,
).show()
}
true
}
else -> super.onPreferenceTreeClick(preference)
}
}
override fun onActivityResult(result: Uri?) {
RestoreDialogFragment.newInstance(result ?: return)
.show(childFragmentManager, BackupDialogFragment.TAG)
}
}

View File

@@ -5,6 +5,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.viewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
@@ -87,10 +88,12 @@ class RestoreDialogFragment : AlertDialogFragment<DialogProgressBinding>() {
companion object {
const val ARG_FILE = "file"
const val TAG = "RestoreDialogFragment"
private const val TAG = "RestoreDialogFragment"
fun newInstance(uri: Uri) = RestoreDialogFragment().withArgs(1) {
putString(ARG_FILE, uri.toString())
fun show(fm: FragmentManager, uri: Uri) {
RestoreDialogFragment().withArgs(1) {
putString(ARG_FILE, uri.toString())
}.show(fm, TAG)
}
}
}