From b1ba70bf77a58dfca8ab3e7c3ed603741fda3ab0 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 10 Jun 2023 15:48:30 +0300 Subject: [PATCH] Fix settings issues --- .../kotatsu/core/ui/BasePreferenceFragment.kt | 1 - .../select/MangaCategoriesViewModel.kt | 3 +- .../colorfilter/ColorFilterConfigViewModel.kt | 7 +- .../ui/thumbnails/PagesThumbnailsViewModel.kt | 3 +- .../settings/AppearanceSettingsFragment.kt | 28 +--- .../kotatsu/settings/SettingsActivity.kt | 1 + .../settings/SourceSettingsFragment.kt | 133 ------------------ .../settings/UserDataSettingsFragment.kt | 38 ++++- .../{ => sources}/SourceSettingsExt.kt | 2 +- .../sources/SourceSettingsFragment.kt | 100 +++++++++++++ .../sources/SourceSettingsViewModel.kt | 47 +++++++ .../settings/sources/SourcesListFragment.kt | 1 - .../tracker/TrackerSettingsFragment.kt | 18 +-- 13 files changed, 203 insertions(+), 179 deletions(-) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt rename app/src/main/kotlin/org/koitharu/kotatsu/settings/{ => sources}/SourceSettingsExt.kt (98%) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsFragment.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsViewModel.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt index 75ee4312b..ce407ddca 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt @@ -16,7 +16,6 @@ import org.koitharu.kotatsu.core.util.ext.getThemeColor import org.koitharu.kotatsu.settings.SettingsActivity import javax.inject.Inject -@Suppress("LeakingThis") @AndroidEntryPoint abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : PreferenceFragmentCompat(), diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt index ef5707f75..5f6566ceb 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt @@ -12,6 +12,7 @@ import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.model.ids import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.ui.BaseViewModel +import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet.Companion.KEY_MANGA_LIST import org.koitharu.kotatsu.favourites.ui.categories.select.model.CategoriesHeaderItem @@ -25,7 +26,7 @@ class MangaCategoriesViewModel @Inject constructor( private val favouritesRepository: FavouritesRepository, ) : BaseViewModel() { - private val manga = requireNotNull(savedStateHandle.get>(KEY_MANGA_LIST)).map { it.manga } + private val manga = savedStateHandle.require>(KEY_MANGA_LIST).map { it.manga } private val header = CategoriesHeaderItem() val content: StateFlow> = combine( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt index 74e7d1044..dec42bd8d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt @@ -11,6 +11,7 @@ import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call +import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.reader.domain.ReaderColorFilter import org.koitharu.kotatsu.reader.ui.colorfilter.ColorFilterConfigActivity.Companion.EXTRA_MANGA @@ -23,7 +24,7 @@ class ColorFilterConfigViewModel @Inject constructor( private val mangaDataRepository: MangaDataRepository, ) : BaseViewModel() { - private val manga = checkNotNull(savedStateHandle.get(EXTRA_MANGA)?.manga) + private val manga = savedStateHandle.require(EXTRA_MANGA).manga private var initialColorFilter: ReaderColorFilter? = null val colorFilter = MutableStateFlow(null) @@ -34,9 +35,7 @@ class ColorFilterConfigViewModel @Inject constructor( get() = colorFilter.value != initialColorFilter init { - val page = checkNotNull( - savedStateHandle.get(ColorFilterConfigActivity.EXTRA_PAGES)?.pages?.firstOrNull(), - ) + val page = savedStateHandle.require(ColorFilterConfigActivity.EXTRA_PAGES).pages.first() launchLoadingJob { initialColorFilter = mangaDataRepository.getColorFilter(manga.id) colorFilter.value = initialColorFilter diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt index ef0463ba0..7fee3bf49 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.ui.BaseViewModel +import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.details.domain.DoubleMangaLoadUseCase import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListModel @@ -26,7 +27,7 @@ class PagesThumbnailsViewModel @Inject constructor( private val currentPageIndex: Int = savedStateHandle[PagesThumbnailsSheet.ARG_CURRENT_PAGE] ?: -1 private val initialChapterId: Long = savedStateHandle[PagesThumbnailsSheet.ARG_CHAPTER_ID] ?: 0L - val manga = requireNotNull(savedStateHandle.get(PagesThumbnailsSheet.ARG_MANGA)).manga + val manga = savedStateHandle.require(PagesThumbnailsSheet.ARG_MANGA).manga private val repository = mangaRepositoryFactory.create(manga.source) private val mangaDetails = SuspendLazy { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/AppearanceSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/AppearanceSettingsFragment.kt index 468ffb0fa..5905e7f17 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/AppearanceSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/AppearanceSettingsFragment.kt @@ -13,7 +13,6 @@ import androidx.core.app.LocaleManagerCompat import androidx.core.view.postDelayed import androidx.preference.ListPreference import androidx.preference.Preference -import androidx.preference.TwoStatePreference import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings @@ -26,7 +25,6 @@ import org.koitharu.kotatsu.core.util.ext.setDefaultValueCompat import org.koitharu.kotatsu.core.util.ext.toList import org.koitharu.kotatsu.parsers.util.names import org.koitharu.kotatsu.parsers.util.toTitleCase -import org.koitharu.kotatsu.settings.protect.ProtectSetupActivity import org.koitharu.kotatsu.settings.utils.ActivityListPreference import org.koitharu.kotatsu.settings.utils.SliderPreference import java.util.Locale @@ -50,12 +48,10 @@ class AppearanceSettingsFragment : true } } - preferenceScreen?.findPreference(AppSettings.KEY_LIST_MODE)?.run { + findPreference(AppSettings.KEY_LIST_MODE)?.run { entryValues = ListMode.values().names() setDefaultValueCompat(ListMode.GRID.name) } - findPreference(AppSettings.KEY_PROTECT_APP) - ?.isChecked = !settings.appPassword.isNullOrEmpty() findPreference(AppSettings.KEY_APP_LOCALE)?.run { initLocalePicker(this) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { @@ -93,34 +89,12 @@ class AppearanceSettingsFragment : postRestart() } - AppSettings.KEY_APP_PASSWORD -> { - findPreference(AppSettings.KEY_PROTECT_APP) - ?.isChecked = !settings.appPassword.isNullOrEmpty() - } - AppSettings.KEY_APP_LOCALE -> { AppCompatDelegate.setApplicationLocales(settings.appLocales) } } } - 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) - } - } - private fun postRestart() { view?.postDelayed(400) { activityRecreationHandle.recreateAll() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt index 9e7ed1538..7af612d70 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt @@ -29,6 +29,7 @@ import org.koitharu.kotatsu.databinding.ActivitySettingsBinding import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.settings.about.AboutSettingsFragment +import org.koitharu.kotatsu.settings.sources.SourceSettingsFragment import org.koitharu.kotatsu.settings.sources.SourcesListFragment import org.koitharu.kotatsu.settings.tracker.TrackerSettingsFragment diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt deleted file mode 100644 index 81a2c47b6..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt +++ /dev/null @@ -1,133 +0,0 @@ -package org.koitharu.kotatsu.settings - -import android.os.Bundle -import android.view.View -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope -import androidx.preference.Preference -import com.google.android.material.snackbar.Snackbar -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ensureActive -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.core.parser.RemoteMangaRepository -import org.koitharu.kotatsu.core.ui.BasePreferenceFragment -import org.koitharu.kotatsu.core.util.ext.awaitViewLifecycle -import org.koitharu.kotatsu.core.util.ext.getDisplayMessage -import org.koitharu.kotatsu.core.util.ext.requireSerializable -import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope -import org.koitharu.kotatsu.core.util.ext.withArgs -import org.koitharu.kotatsu.parsers.exception.AuthRequiredException -import org.koitharu.kotatsu.parsers.model.MangaSource -import org.koitharu.kotatsu.parsers.util.runCatchingCancellable -import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity -import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug -import javax.inject.Inject - -@AndroidEntryPoint -class SourceSettingsFragment : BasePreferenceFragment(0) { - - @Inject - lateinit var mangaRepositoryFactory: MangaRepository.Factory - - private lateinit var source: MangaSource - private var repository: RemoteMangaRepository? = null - private val exceptionResolver = ExceptionResolver(this) - - override fun onCreate(savedInstanceState: Bundle?) { - source = requireArguments().requireSerializable(EXTRA_SOURCE) - repository = mangaRepositoryFactory.create(source) as? RemoteMangaRepository - super.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - setTitle(source.title) - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - preferenceManager.sharedPreferencesName = source.name - val repo = repository ?: return - addPreferencesFromResource(R.xml.pref_source) - addPreferencesFromRepository(repo) - - findPreference(KEY_AUTH)?.run { - val authProvider = repo.getAuthProvider() - isVisible = authProvider != null - isEnabled = authProvider?.isAuthorized == false - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - findPreference(KEY_AUTH)?.run { - if (isVisible) { - loadUsername(viewLifecycleOwner, this) - } - } - } - - override fun onPreferenceTreeClick(preference: Preference): Boolean { - return when (preference.key) { - KEY_AUTH -> { - startActivity(SourceAuthActivity.newIntent(preference.context, source)) - true - } - - else -> super.onPreferenceTreeClick(preference) - } - } - - private fun loadUsername(owner: LifecycleOwner, preference: Preference) = owner.lifecycleScope.launch { - runCatchingCancellable { - preference.summary = null - withContext(Dispatchers.Default) { - requireNotNull(repository?.getAuthProvider()?.getUsername()) - } - }.onSuccess { username -> - preference.title = getString(R.string.logged_in_as, username) - }.onFailure { error -> - when { - error is AuthRequiredException -> Unit - ExceptionResolver.canResolve(error) -> { - ensureActive() - Snackbar.make( - listView ?: return@onFailure, - error.getDisplayMessage(preference.context.resources), - Snackbar.LENGTH_INDEFINITE, - ).setAction(ExceptionResolver.getResolveStringId(error)) { resolveError(error) } - .show() - } - - else -> preference.summary = error.getDisplayMessage(preference.context.resources) - } - error.printStackTraceDebug() - } - } - - private fun resolveError(error: Throwable) { - view ?: return - viewLifecycleScope.launch { - if (exceptionResolver.resolve(error)) { - val pref = findPreference(KEY_AUTH) ?: return@launch - val lifecycleOwner = awaitViewLifecycle() - loadUsername(lifecycleOwner, pref) - } - } - } - - companion object { - - private const val KEY_AUTH = "auth" - - private const val EXTRA_SOURCE = "source" - - fun newInstance(source: MangaSource) = SourceSettingsFragment().withArgs(1) { - putSerializable(EXTRA_SOURCE, source) - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt index c680ab2af..2972d126d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt @@ -1,6 +1,8 @@ package org.koitharu.kotatsu.settings import android.content.ActivityNotFoundException +import android.content.Intent +import android.content.SharedPreferences import android.net.Uri import android.os.Bundle import android.view.View @@ -8,6 +10,7 @@ import androidx.activity.result.ActivityResultCallback import androidx.activity.result.contract.ActivityResultContracts import androidx.lifecycle.Lifecycle import androidx.preference.Preference +import androidx.preference.TwoStatePreference import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint @@ -24,18 +27,21 @@ import org.koitharu.kotatsu.core.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.ext.awaitStateAtLeast import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug 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.settings.protect.ProtectSetupActivity import org.koitharu.kotatsu.tracker.domain.TrackingRepository -import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import javax.inject.Inject @AndroidEntryPoint -class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privacy), ActivityResultCallback { +class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privacy), + SharedPreferences.OnSharedPreferenceChangeListener, + ActivityResultCallback { @Inject lateinit var trackerRepo: TrackingRepository @@ -64,6 +70,8 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac addPreferencesFromResource(R.xml.pref_user_data) findPreference(AppSettings.KEY_SHORTCUTS)?.isVisible = shortcutsUpdater.isDynamicShortcutsAvailable() + findPreference(AppSettings.KEY_PROTECT_APP) + ?.isChecked = !settings.appPassword.isNullOrEmpty() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -85,6 +93,12 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac pref.summary = pref.context.resources.getQuantityString(R.plurals.items, items, items) } } + settings.subscribe(this) + } + + override fun onDestroyView() { + settings.unsubscribe(this) + super.onDestroyView() } override fun onPreferenceTreeClick(preference: Preference): Boolean { @@ -145,10 +159,30 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac 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 onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + when (key) { + AppSettings.KEY_APP_PASSWORD -> { + findPreference(AppSettings.KEY_PROTECT_APP) + ?.isChecked = !settings.appPassword.isNullOrEmpty() + } + } + } + override fun onActivityResult(result: Uri?) { if (result != null) { RestoreDialogFragment.show(childFragmentManager, result) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsExt.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsExt.kt similarity index 98% rename from app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsExt.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsExt.kt index d0123bee7..f0c239c23 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsExt.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsExt.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.settings +package org.koitharu.kotatsu.settings.sources import android.view.inputmethod.EditorInfo import androidx.preference.EditTextPreference diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsFragment.kt new file mode 100644 index 000000000..2fbae0771 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsFragment.kt @@ -0,0 +1,100 @@ +package org.koitharu.kotatsu.settings.sources + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.viewModels +import androidx.preference.Preference +import com.google.android.material.snackbar.Snackbar +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver +import org.koitharu.kotatsu.core.ui.BasePreferenceFragment +import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent +import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope +import org.koitharu.kotatsu.core.util.ext.withArgs +import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity + +@AndroidEntryPoint +class SourceSettingsFragment : BasePreferenceFragment(0) { + + private val viewModel: SourceSettingsViewModel by viewModels() + private val exceptionResolver = ExceptionResolver(this) + + override fun onResume() { + super.onResume() + setTitle(viewModel.source.title) + viewModel.onResume() + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + preferenceManager.sharedPreferencesName = viewModel.source.name + addPreferencesFromResource(R.xml.pref_source) + addPreferencesFromRepository(viewModel.repository) + + findPreference(KEY_AUTH)?.run { + val authProvider = viewModel.repository.getAuthProvider() + isVisible = authProvider != null + isEnabled = authProvider?.isAuthorized == false + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + viewModel.username.observe(viewLifecycleOwner) { username -> + findPreference(KEY_AUTH)?.summary = username?.let { + getString(R.string.logged_in_as, it) + } + } + viewModel.onError.observeEvent(viewLifecycleOwner, ::onError) + viewModel.isLoading.observe(viewLifecycleOwner) { isLoading -> + findPreference(KEY_AUTH)?.isEnabled = !isLoading + } + } + + override fun onPreferenceTreeClick(preference: Preference): Boolean { + return when (preference.key) { + KEY_AUTH -> { + startActivity(SourceAuthActivity.newIntent(preference.context, viewModel.source)) + true + } + + else -> super.onPreferenceTreeClick(preference) + } + } + + private fun onError(error: Throwable) { + val snackbar = Snackbar.make( + listView ?: return, + error.getDisplayMessage(resources), + Snackbar.LENGTH_INDEFINITE, + ) + if (ExceptionResolver.canResolve(error)) { + snackbar.setAction(ExceptionResolver.getResolveStringId(error)) { resolveError(error) } + } + snackbar.show() + } + + private fun resolveError(error: Throwable) { + view ?: return + viewLifecycleScope.launch { + if (exceptionResolver.resolve(error)) { + viewModel.onResume() + } + } + } + + companion object { + + private const val KEY_AUTH = "auth" + + const val EXTRA_SOURCE = "source" + + fun newInstance(source: MangaSource) = SourceSettingsFragment().withArgs(1) { + putSerializable(EXTRA_SOURCE, source) + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsViewModel.kt new file mode 100644 index 000000000..173c53b69 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsViewModel.kt @@ -0,0 +1,47 @@ +package org.koitharu.kotatsu.settings.sources + +import androidx.lifecycle.SavedStateHandle +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import org.koitharu.kotatsu.core.parser.MangaRepository +import org.koitharu.kotatsu.core.parser.RemoteMangaRepository +import org.koitharu.kotatsu.core.ui.BaseViewModel +import org.koitharu.kotatsu.core.util.ext.require +import org.koitharu.kotatsu.parsers.exception.AuthRequiredException +import org.koitharu.kotatsu.parsers.model.MangaSource +import javax.inject.Inject + +@HiltViewModel +class SourceSettingsViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + mangaRepositoryFactory: MangaRepository.Factory, +) : BaseViewModel() { + + val source = savedStateHandle.require(SourceSettingsFragment.EXTRA_SOURCE) + val repository = mangaRepositoryFactory.create(source) as RemoteMangaRepository + + val username = MutableStateFlow(null) + private var usernameLoadJob: Job? = null + + init { + loadUsername() + } + + fun onResume() { + if (usernameLoadJob?.isActive != true) { + loadUsername() + } + } + + private fun loadUsername() { + launchLoadingJob(Dispatchers.Default) { + try { + username.value = null + username.value = repository.getAuthProvider()?.getUsername() + } catch (_: AuthRequiredException) { + } + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt index 18d0f2d97..413bea9a2 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt @@ -26,7 +26,6 @@ import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.settings.SettingsActivity -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 diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsFragment.kt index 51cca1a26..fb369ee01 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsFragment.kt @@ -56,14 +56,13 @@ class TrackerSettingsFragment : } } } + updateDozePreference() updateCategoriesEnabled() } override fun onResume() { super.onResume() - findPreference(KEY_IGNORE_DOZE)?.run { - isVisible = isDozeIgnoreAvailable(context) - } + updateDozePreference() updateNotificationsSummary() } @@ -82,8 +81,7 @@ class TrackerSettingsFragment : when (key) { AppSettings.KEY_TRACKER_NOTIFICATIONS -> updateNotificationsSummary() AppSettings.KEY_TRACK_SOURCES, - AppSettings.KEY_TRACKER_ENABLED, - -> updateCategoriesEnabled() + AppSettings.KEY_TRACKER_ENABLED -> updateCategoriesEnabled() } } @@ -104,9 +102,7 @@ class TrackerSettingsFragment : true } - else -> { - super.onPreferenceTreeClick(preference) - } + else -> super.onPreferenceTreeClick(preference) } AppSettings.KEY_TRACK_CATEGORIES -> { @@ -123,6 +119,12 @@ class TrackerSettingsFragment : } } + private fun updateDozePreference() { + findPreference(KEY_IGNORE_DOZE)?.run { + isVisible = isDozeIgnoreAvailable(context) + } + } + private fun updateNotificationsSummary() { val pref = findPreference(AppSettings.KEY_NOTIFICATIONS_SETTINGS) ?: return pref.setSummary(