Use master-detals pattern for settings

This commit is contained in:
Koitharu
2022-04-02 09:09:01 +03:00
parent b916d4016e
commit 41fb351fe0
49 changed files with 578 additions and 688 deletions

View File

@@ -6,14 +6,18 @@ import androidx.annotation.CallSuper
import androidx.annotation.StringRes
import androidx.core.graphics.Insets
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceFragmentCompat
import androidx.recyclerview.widget.RecyclerView
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.settings.SettingsHeadersFragment
abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : PreferenceFragmentCompat(),
abstract class BasePreferenceFragment(@StringRes private val titleId: Int) :
PreferenceFragmentCompat(),
WindowInsetsDelegate.WindowInsetsListener,
RecyclerViewOwner {
@@ -39,16 +43,20 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : Pre
override fun onResume() {
super.onResume()
if (titleId != 0) {
activity?.setTitle(titleId)
setTitle(getString(titleId))
}
}
@CallSuper
override fun onWindowInsetsChanged(insets: Insets) {
listView.updatePadding(
left = insets.left,
right = insets.right,
bottom = insets.bottom
)
}
}
@Suppress("UsePropertyAccessSyntax")
protected fun setTitle(title: CharSequence) {
(parentFragment as? SettingsHeadersFragment)?.setTitle(title)
?: activity?.setTitle(title)
}
}

View File

@@ -253,11 +253,9 @@ class AppSettings(context: Context) {
const val KEY_APP_UPDATE = "app_update"
const val KEY_APP_UPDATE_AUTO = "app_update_auto"
const val KEY_APP_TRANSLATION = "about_app_translation"
const val KEY_APP_GRATITUDES = "about_gratitudes"
const val KEY_FEEDBACK_4PDA = "about_feedback_4pda"
const val KEY_FEEDBACK_DISCORD = "about_feedback_discord"
const val KEY_FEEDBACK_GITHUB = "about_feedback_github"
const val KEY_SUPPORT_DEVELOPER = "about_support_developer"
private const val NETWORK_NEVER = 0
private const val NETWORK_ALWAYS = 1

View File

@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.main.ui.AppBarOwner
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.settings.*
@Deprecated("")
class SimpleSettingsActivity : BaseActivity<ActivitySettingsSimpleBinding>(), AppBarOwner {
override val appBar: AppBarLayout
@@ -36,7 +37,7 @@ class SimpleSettingsActivity : BaseActivity<ActivitySettingsSimpleBinding>(), Ap
ACTION_SOURCE -> SourceSettingsFragment.newInstance(
intent.getSerializableExtra(EXTRA_SOURCE) as? MangaSource ?: MangaSource.LOCAL
)
else -> MainSettingsFragment()
else -> SettingsHeadersFragment()
}
)
}

View File

@@ -0,0 +1,100 @@
package org.koitharu.kotatsu.settings
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.TwoStatePreference
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.settings.protect.ProtectSetupActivity
import org.koitharu.kotatsu.settings.utils.SliderPreference
import org.koitharu.kotatsu.utils.ext.names
import org.koitharu.kotatsu.utils.ext.setDefaultValueCompat
import java.util.*
class AppearanceSettingsFragment :
BasePreferenceFragment(R.string.appearance),
SharedPreferences.OnSharedPreferenceChangeListener {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_appearance)
findPreference<SliderPreference>(AppSettings.KEY_GRID_SIZE)?.run {
summary = "%d%%".format(value)
setOnPreferenceChangeListener { preference, newValue ->
preference.summary = "%d%%".format(newValue)
true
}
}
preferenceScreen?.findPreference<ListPreference>(AppSettings.KEY_LIST_MODE)?.run {
entryValues = ListMode.values().names()
setDefaultValueCompat(ListMode.GRID.name)
}
findPreference<Preference>(AppSettings.KEY_DYNAMIC_THEME)?.isVisible = AppSettings.isDynamicColorAvailable
findPreference<ListPreference>(AppSettings.KEY_DATE_FORMAT)?.run {
entryValues = resources.getStringArray(R.array.date_formats)
val now = Date().time
entries = entryValues.map { value ->
val formattedDate = settings.getDateFormat(value.toString()).format(now)
if (value == "") {
"${context.getString(R.string.system_default)} ($formattedDate)"
} else {
formattedDate
}
}.toTypedArray()
setDefaultValueCompat("")
summary = "%s"
}
findPreference<TwoStatePreference>(AppSettings.KEY_PROTECT_APP)
?.isChecked = !settings.appPassword.isNullOrEmpty()
}
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_THEME -> {
AppCompatDelegate.setDefaultNightMode(settings.theme)
}
AppSettings.KEY_DYNAMIC_THEME -> {
findPreference<Preference>(key)?.setSummary(R.string.restart_required)
}
AppSettings.KEY_THEME_AMOLED -> {
findPreference<Preference>(key)?.setSummary(R.string.restart_required)
}
AppSettings.KEY_APP_PASSWORD -> {
findPreference<TwoStatePreference>(AppSettings.KEY_PROTECT_APP)
?.isChecked = !settings.appPassword.isNullOrEmpty()
}
}
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
return when (preference.key) {
AppSettings.KEY_PROTECT_APP -> {
val pref = (preference as? TwoStatePreference ?: return false)
if (pref.isChecked) {
pref.isChecked = false
startActivity(Intent(preference.context, ProtectSetupActivity::class.java))
} else {
settings.appPassword = null
}
true
}
else -> super.onPreferenceTreeClick(preference)
}
}
}

View File

@@ -0,0 +1,96 @@
package org.koitharu.kotatsu.settings
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.preference.Preference
import java.io.File
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
import org.koitharu.kotatsu.base.ui.dialog.StorageSelectDialog
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.ext.getStorageName
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
class ContentSettingsFragment :
BasePreferenceFragment(R.string.content),
SharedPreferences.OnSharedPreferenceChangeListener,
StorageSelectDialog.OnStorageSelectListener {
private val storageManager by inject<LocalStorageManager>()
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_content)
findPreference<Preference>(AppSettings.KEY_SUGGESTIONS)?.setSummary(
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled
)
bindRemoteSourcesSummary()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
findPreference<Preference>(AppSettings.KEY_LOCAL_STORAGE)?.bindStorageName()
settings.subscribe(this)
}
override fun onDestroyView() {
settings.unsubscribe(this)
super.onDestroyView()
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences?, key: String?) {
when (key) {
AppSettings.KEY_LOCAL_STORAGE -> {
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()
}
}
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
return when (preference.key) {
AppSettings.KEY_LOCAL_STORAGE -> {
val ctx = context ?: return false
StorageSelectDialog.Builder(ctx, storageManager, this)
.setTitle(preference.title ?: "")
.setNegativeButton(android.R.string.cancel)
.create()
.show()
true
}
else -> super.onPreferenceTreeClick(preference)
}
}
override fun onStorageSelected(file: File) {
settings.mangaStorageDir = file
}
private fun Preference.bindStorageName() {
viewLifecycleScope.launch {
val storage = storageManager.getDefaultWriteableDir()
summary = storage?.getStorageName(context) ?: getString(R.string.not_available)
}
}
private fun bindRemoteSourcesSummary() {
findPreference<Preference>(AppSettings.KEY_REMOTE_SOURCES)?.run {
val total = MangaSource.values().size - 1
summary = getString(
R.string.enabled_d_of_d, total - settings.hiddenSources.size, total
)
}
}
}

View File

@@ -1,182 +0,0 @@
package org.koitharu.kotatsu.settings
import android.content.ComponentName
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceScreen
import androidx.preference.TwoStatePreference
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
import org.koitharu.kotatsu.base.ui.dialog.StorageSelectDialog
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.settings.protect.ProtectSetupActivity
import org.koitharu.kotatsu.settings.utils.SliderPreference
import org.koitharu.kotatsu.utils.ext.getStorageName
import org.koitharu.kotatsu.utils.ext.names
import org.koitharu.kotatsu.utils.ext.setDefaultValueCompat
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import java.io.File
import java.util.*
class MainSettingsFragment : BasePreferenceFragment(R.string.settings),
SharedPreferences.OnSharedPreferenceChangeListener,
StorageSelectDialog.OnStorageSelectListener {
private val storageManager by inject<LocalStorageManager>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_main)
findPreference<SliderPreference>(AppSettings.KEY_GRID_SIZE)?.run {
summary = "%d%%".format(value)
setOnPreferenceChangeListener { preference, newValue ->
preference.summary = "%d%%".format(newValue)
true
}
}
preferenceScreen?.findPreference<ListPreference>(AppSettings.KEY_LIST_MODE)?.run {
entryValues = ListMode.values().names()
setDefaultValueCompat(ListMode.GRID.name)
}
findPreference<Preference>(AppSettings.KEY_DYNAMIC_THEME)?.isVisible =
AppSettings.isDynamicColorAvailable
findPreference<ListPreference>(AppSettings.KEY_DATE_FORMAT)?.run {
entryValues = resources.getStringArray(R.array.date_formats)
val now = Date().time
entries = entryValues.map { value ->
val formattedDate = settings.getDateFormat(value.toString()).format(now)
if (value == "") {
"${context.getString(R.string.system_default)} ($formattedDate)"
} else {
formattedDate
}
}.toTypedArray()
setDefaultValueCompat("")
summary = "%s"
}
findPreference<Preference>(AppSettings.KEY_SUGGESTIONS)?.setSummary(
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled
)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
findPreference<Preference>(AppSettings.KEY_LOCAL_STORAGE)?.bindStorageName()
findPreference<TwoStatePreference>(AppSettings.KEY_PROTECT_APP)?.isChecked =
!settings.appPassword.isNullOrEmpty()
settings.subscribe(this)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.opt_settings, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_leaks -> {
val intent = Intent()
intent.component = ComponentName(requireContext(), "leakcanary.internal.activity.LeakActivity")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(intent)
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onDestroyView() {
settings.unsubscribe(this)
super.onDestroyView()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
when (key) {
AppSettings.KEY_THEME -> {
AppCompatDelegate.setDefaultNightMode(settings.theme)
}
AppSettings.KEY_DYNAMIC_THEME -> {
findPreference<Preference>(key)?.setSummary(R.string.restart_required)
}
AppSettings.KEY_THEME_AMOLED -> {
findPreference<Preference>(key)?.setSummary(R.string.restart_required)
}
AppSettings.KEY_LOCAL_STORAGE -> {
findPreference<Preference>(key)?.bindStorageName()
}
AppSettings.KEY_APP_PASSWORD -> {
findPreference<TwoStatePreference>(AppSettings.KEY_PROTECT_APP)
?.isChecked = !settings.appPassword.isNullOrEmpty()
}
AppSettings.KEY_SUGGESTIONS -> {
findPreference<Preference>(AppSettings.KEY_SUGGESTIONS)?.setSummary(
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled
)
}
}
}
override fun onResume() {
super.onResume()
findPreference<PreferenceScreen>(AppSettings.KEY_REMOTE_SOURCES)?.run {
val total = MangaSource.values().size - 1
summary = getString(
R.string.enabled_d_of_d, total - settings.hiddenSources.size, total
)
}
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
return when (preference.key) {
AppSettings.KEY_LOCAL_STORAGE -> {
val ctx = context ?: return false
StorageSelectDialog.Builder(ctx, storageManager, this)
.setTitle(preference.title ?: "")
.setNegativeButton(android.R.string.cancel)
.create()
.show()
true
}
AppSettings.KEY_PROTECT_APP -> {
val pref = (preference as? TwoStatePreference ?: return false)
if (pref.isChecked) {
pref.isChecked = false
startActivity(Intent(preference.context, ProtectSetupActivity::class.java))
} else {
settings.appPassword = null
}
true
}
else -> super.onPreferenceTreeClick(preference)
}
}
override fun onStorageSelected(file: File) {
settings.mangaStorageDir = file
}
private fun Preference.bindStorageName() {
viewLifecycleScope.launch {
val storage = storageManager.getDefaultWriteableDir()
summary = storage?.getStorageName(context) ?: getString(R.string.not_available)
}
}
}

View File

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

View File

@@ -1,9 +1,13 @@
package org.koitharu.kotatsu.settings
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.core.graphics.Insets
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
@@ -16,7 +20,6 @@ import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.databinding.ActivitySettingsBinding
import org.koitharu.kotatsu.main.ui.AppBarOwner
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.ext.isScrolledToTop
class SettingsActivity :
@@ -35,7 +38,7 @@ class SettingsActivity :
if (supportFragmentManager.findFragmentById(R.id.container) == null) {
supportFragmentManager.commit {
replace(R.id.container, MainSettingsFragment())
replace(R.id.container, SettingsHeadersFragment())
}
}
}
@@ -55,6 +58,22 @@ class SettingsActivity :
super.onStop()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.opt_settings, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
R.id.action_leaks -> {
val intent = Intent()
intent.component = ComponentName(this, "leakcanary.internal.activity.LeakActivity")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(intent)
true
}
else -> super.onOptionsItemSelected(item)
}
override fun onBackStackChanged() {
val fragment = supportFragmentManager.findFragmentById(R.id.container) as? RecyclerViewOwner ?: return
val recyclerView = fragment.recyclerView
@@ -70,30 +89,31 @@ class SettingsActivity :
val fm = supportFragmentManager
val fragment = fm.fragmentFactory.instantiate(classLoader, pref.fragment ?: return false)
fragment.arguments = pref.extras
fragment.setTargetFragment(caller, 0)
// fragment.setTargetFragment(caller, 0)
openFragment(fragment)
return true
}
fun openMangaSourceSettings(mangaSource: MangaSource) {
openFragment(SourceSettingsFragment.newInstance(mangaSource))
override fun onWindowInsetsChanged(insets: Insets) {
binding.appbar.updatePadding(
left = insets.left,
right = insets.right,
)
binding.container.updatePadding(
left = insets.left,
right = insets.right,
)
}
fun openNotificationSettingsLegacy() {
openFragment(NotificationSettingsLegacyFragment())
}
private fun openFragment(fragment: Fragment) {
fun openFragment(fragment: Fragment) {
supportFragmentManager.commit {
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
replace(R.id.container, fragment)
setReorderingAllowed(true)
replace(R.id.container, fragment)
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
addToBackStack(null)
}
}
override fun onWindowInsetsChanged(insets: Insets) = Unit
companion object {
fun newIntent(context: Context) = Intent(context, SettingsActivity::class.java)

View File

@@ -0,0 +1,49 @@
package org.koitharu.kotatsu.settings
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.commit
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceHeaderFragmentCompat
import androidx.slidingpanelayout.widget.SlidingPaneLayout
import org.koitharu.kotatsu.R
class SettingsHeadersFragment : PreferenceHeaderFragmentCompat(), SlidingPaneLayout.PanelSlideListener {
private var currentTitle: CharSequence? = null
override fun onCreatePreferenceHeader(): PreferenceFragmentCompat = RootSettingsFragment()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
slidingPaneLayout.addPanelSlideListener(this)
}
override fun onPanelSlide(panel: View, slideOffset: Float) = Unit
override fun onPanelOpened(panel: View) {
activity?.title = currentTitle ?: getString(R.string.settings)
}
override fun onPanelClosed(panel: View) {
activity?.setTitle(R.string.settings)
}
fun setTitle(title: CharSequence?) {
currentTitle = title
if (slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen) {
activity?.title = title
}
}
fun openFragment(fragment: Fragment) {
childFragmentManager.commit {
setReorderingAllowed(true)
replace(androidx.preference.R.id.preferences_detail, fragment)
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
addToBackStack(null)
}
}
}

View File

@@ -25,7 +25,7 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
override fun onResume() {
super.onResume()
activity?.title = source.title
setTitle(source.title)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

View File

@@ -31,7 +31,6 @@ class TrackerSettingsFragment : BasePreferenceFragment(R.string.check_for_new_ch
append(getString(R.string.read_more))
}
}
warningPreference
}
}
@@ -43,10 +42,10 @@ class TrackerSettingsFragment : BasePreferenceFragment(R.string.check_for_new_ch
.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
.putExtra(Settings.EXTRA_CHANNEL_ID, TrackWorker.CHANNEL_ID)
startActivity(intent)
true
} else {
(activity as? SettingsActivity)?.openNotificationSettingsLegacy()
super.onPreferenceTreeClick(preference)
}
true
}
else -> super.onPreferenceTreeClick(preference)
}

View File

@@ -1,13 +1,13 @@
package org.koitharu.kotatsu.settings.about
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.core.net.toUri
import androidx.preference.Preference
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
import org.koitharu.kotatsu.browser.BrowserActivity
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.settings.AppUpdateChecker
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
@@ -16,20 +16,16 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_about)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val isUpdateSupported = AppUpdateChecker.isUpdateSupported(requireContext())
findPreference<Preference>(AppSettings.KEY_APP_UPDATE_AUTO)?.run {
isVisible = AppUpdateChecker.isUpdateSupported(context)
isVisible = isUpdateSupported
}
findPreference<Preference>(AppSettings.KEY_APP_VERSION)?.run {
title = getString(R.string.app_version, BuildConfig.VERSION_NAME)
isEnabled = AppUpdateChecker.isUpdateSupported(context)
isEnabled = isUpdateSupported
}
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
return when (preference.key) {
AppSettings.KEY_APP_VERSION -> {
@@ -37,39 +33,19 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
true
}
AppSettings.KEY_APP_TRANSLATION -> {
startActivity(context?.let { BrowserActivity.newIntent(it,
"https://hosted.weblate.org/engage/kotatsu",
resources.getString(R.string.about_app_translation)) })
openLink(getString(R.string.url_weblate), preference.title)
true
}
AppSettings.KEY_FEEDBACK_4PDA -> {
startActivity(context?.let { BrowserActivity.newIntent(it,
"https://4pda.to/forum/index.php?showtopic=697669",
resources.getString(R.string.about_feedback_4pda)) })
openLink(getString(R.string.url_forpda), preference.title)
true
}
AppSettings.KEY_FEEDBACK_DISCORD -> {
startActivity(context?.let { BrowserActivity.newIntent(it,
"https://discord.gg/NNJ5RgVBC5",
"Discord") })
openLink(getString(R.string.url_discord), preference.title)
true
}
AppSettings.KEY_FEEDBACK_GITHUB -> {
startActivity(context?.let { BrowserActivity.newIntent(it,
"https://github.com/nv95/Kotatsu/issues",
"GitHub") })
true
}
AppSettings.KEY_SUPPORT_DEVELOPER -> {
startActivity(context?.let { BrowserActivity.newIntent(it,
"https://yoomoney.ru/to/410012543938752",
resources.getString(R.string.about_support_developer)) })
true
}
AppSettings.KEY_APP_GRATITUDES -> {
startActivity(context?.let { BrowserActivity.newIntent(it,
"https://github.com/nv95/Kotatsu/graphs/contributors",
resources.getString(R.string.about_gratitudes)) })
openLink(getString(R.string.url_github_issues), preference.title)
true
}
else -> super.onPreferenceTreeClick(preference)
@@ -95,4 +71,16 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
}
}
}
}
private fun openLink(url: String, title: CharSequence?) {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = url.toUri()
startActivity(
if (title != null) {
Intent.createChooser(intent, title)
} else {
intent
}
)
}
}

View File

@@ -1,41 +0,0 @@
package org.koitharu.kotatsu.settings.about
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.Insets
import androidx.core.text.HtmlCompat
import androidx.core.text.parseAsHtml
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseFragment
import org.koitharu.kotatsu.databinding.FragmentCopyrightBinding
class LicenseFragment : BaseFragment<FragmentCopyrightBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.textView.apply {
text =
SpannableStringBuilder(resources.openRawResource(R.raw.copyright).bufferedReader()
.readText()
.parseAsHtml(HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_LIST))
movementMethod = LinkMovementMethod.getInstance()
}
}
override fun onInflateView(
inflater: LayoutInflater,
container: ViewGroup?
) = FragmentCopyrightBinding.inflate(inflater, container, false)
override fun onResume() {
super.onResume()
activity?.setTitle(R.string.about_license)
}
override fun onWindowInsetsChanged(insets: Insets) = Unit
}

View File

@@ -15,6 +15,8 @@ import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding
import org.koitharu.kotatsu.main.ui.AppBarOwner
import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.settings.SettingsHeadersFragment
import org.koitharu.kotatsu.settings.SourceSettingsFragment
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigAdapter
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
@@ -87,7 +89,9 @@ class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(),
}
override fun onItemSettingsClick(item: SourceConfigItem.SourceItem) {
(activity as? SettingsActivity)?.openMangaSourceSettings(item.source)
val fragment = SourceSettingsFragment.newInstance(item.source)
(parentFragment as? SettingsHeadersFragment)?.openFragment(fragment)
?: (activity as? SettingsActivity)?.openFragment(fragment)
}
override fun onItemEnabledChanged(item: SourceConfigItem.SourceItem, isEnabled: Boolean) {

View File

@@ -30,18 +30,22 @@ class SliderPreference @JvmOverloads constructor(
set(value) = setValueInternal(value, notifyChanged = true)
private val sliderListener = Slider.OnChangeListener { _, value, fromUser ->
if (fromUser) {
syncValueInternal(value.toInt())
}
if (fromUser) {
syncValueInternal(value.toInt())
}
}
init {
context.withStyledAttributes(attrs,
context.withStyledAttributes(
attrs,
R.styleable.SliderPreference,
defStyleAttr,
defStyleRes) {
valueFrom = getFloat(R.styleable.SliderPreference_android_valueFrom,
valueFrom.toFloat()).toInt()
defStyleRes
) {
valueFrom = getFloat(
R.styleable.SliderPreference_android_valueFrom,
valueFrom.toFloat()
).toInt()
valueTo =
getFloat(R.styleable.SliderPreference_android_valueTo, valueTo.toFloat()).toInt()
stepSize =