From 71b14a3aa8ace4645e2c390cda2ce0ec61c34ad7 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 17 Jun 2023 16:05:08 +0300 Subject: [PATCH] Refactor FilterOwner --- .../kotatsu/filter/ui/FilterCoordinator.kt | 4 +-- .../kotatsu/filter/ui/FilterHeaderFragment.kt | 9 +++--- .../koitharu/kotatsu/filter/ui/FilterOwner.kt | 30 ++----------------- .../kotatsu/filter/ui/FilterSheetFragment.kt | 9 ++---- .../koitharu/kotatsu/filter/ui/MangaFilter.kt | 15 ++++++++++ .../kotatsu/local/ui/LocalListFragment.kt | 27 +++-------------- .../remotelist/ui/RemoteListFragment.kt | 27 +++-------------- .../remotelist/ui/RemoteListViewModel.kt | 6 ++-- .../kotatsu/search/ui/MangaListActivity.kt | 19 +++++++++--- 9 files changed, 52 insertions(+), 94 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/MangaFilter.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterCoordinator.kt b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterCoordinator.kt index bff70420b..9e000f6ec 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterCoordinator.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterCoordinator.kt @@ -22,6 +22,7 @@ import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.ui.widgets.ChipsView import org.koitharu.kotatsu.core.util.ext.lifecycleScope +import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel import org.koitharu.kotatsu.filter.ui.model.FilterItem @@ -35,7 +36,6 @@ import org.koitharu.kotatsu.parsers.util.SuspendLazy import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment import org.koitharu.kotatsu.search.domain.MangaSearchRepository -import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import java.text.Collator import java.util.LinkedList import java.util.Locale @@ -49,7 +49,7 @@ class FilterCoordinator @Inject constructor( dataRepository: MangaDataRepository, private val searchRepository: MangaSearchRepository, lifecycle: ViewModelLifecycle, -) : FilterOwner { +) : MangaFilter { private val coroutineScope = lifecycle.lifecycleScope private val repository = mangaRepositoryFactory.create(savedStateHandle.require(RemoteListFragment.ARG_SOURCE)) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterHeaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterHeaderFragment.kt index 4f50e9df5..a16c55c15 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterHeaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterHeaderFragment.kt @@ -19,9 +19,8 @@ import com.google.android.material.R as materialR class FilterHeaderFragment : BaseFragment(), ChipsView.OnChipClickListener { - private val owner by lazy(LazyThreadSafetyMode.NONE) { - FilterOwner.from(requireActivity()) - } + private val filter: MangaFilter + get() = (requireActivity() as FilterOwner).filter override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFilterHeaderBinding { return FragmentFilterHeaderBinding.inflate(inflater, container, false) @@ -30,7 +29,7 @@ class FilterHeaderFragment : BaseFragment(), ChipsV override fun onViewBindingCreated(binding: FragmentFilterHeaderBinding, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState) binding.chipsTags.onChipClickListener = this - owner.header.observe(viewLifecycleOwner, ::onDataChanged) + filter.header.observe(viewLifecycleOwner, ::onDataChanged) } override fun onWindowInsetsChanged(insets: Insets) = Unit @@ -40,7 +39,7 @@ class FilterHeaderFragment : BaseFragment(), ChipsV if (tag == null) { FilterSheetFragment.show(parentFragmentManager) } else { - owner.onTagItemClick(FilterItem.Tag(tag, !chip.isChecked)) + filter.onTagItemClick(FilterItem.Tag(tag, !chip.isChecked)) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterOwner.kt b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterOwner.kt index b302e7692..d75f81c4a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterOwner.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterOwner.kt @@ -1,32 +1,6 @@ package org.koitharu.kotatsu.filter.ui -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity -import kotlinx.coroutines.flow.StateFlow -import org.koitharu.kotatsu.core.util.ext.values -import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel -import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.parsers.model.MangaTag +interface FilterOwner { -interface FilterOwner : OnFilterChangedListener { - - val filterItems: StateFlow> - - val header: StateFlow - - fun applyFilter(tags: Set) - - companion object { - - fun from(activity: FragmentActivity): FilterOwner { - for (f in activity.supportFragmentManager.fragments) { - return find(f) ?: continue - } - error("Cannot find FilterOwner") - } - - fun find(fragment: Fragment): FilterOwner? { - return fragment.viewModelStore.values.firstNotNullOfOrNull { it as? FilterOwner } - } - } + val filter: MangaFilter } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterSheetFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterSheetFragment.kt index 7e9ef1405..1d31d888d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterSheetFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/FilterSheetFragment.kt @@ -21,20 +21,17 @@ class FilterSheetFragment : AdaptiveSheetCallback, AsyncListDiffer.ListListener { - private val owner by lazy(LazyThreadSafetyMode.NONE) { - FilterOwner.from(requireActivity()) - } - override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): SheetFilterBinding { return SheetFilterBinding.inflate(inflater, container, false) } override fun onViewBindingCreated(binding: SheetFilterBinding, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState) + val filter = (requireActivity() as FilterOwner).filter addSheetCallback(this) - val adapter = FilterAdapter(owner, this) + val adapter = FilterAdapter(filter, this) binding.recyclerView.adapter = adapter - owner.filterItems.observe(viewLifecycleOwner, adapter::setItems) + filter.filterItems.observe(viewLifecycleOwner, adapter::setItems) if (dialog == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { binding.recyclerView.scrollIndicators = 0 diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/MangaFilter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/MangaFilter.kt new file mode 100644 index 000000000..e3aa46686 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/filter/ui/MangaFilter.kt @@ -0,0 +1,15 @@ +package org.koitharu.kotatsu.filter.ui + +import kotlinx.coroutines.flow.StateFlow +import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel +import org.koitharu.kotatsu.list.ui.model.ListModel +import org.koitharu.kotatsu.parsers.model.MangaTag + +interface MangaFilter : OnFilterChangedListener { + + val filterItems: StateFlow> + + val header: StateFlow + + fun applyFilter(tags: Set) +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListFragment.kt index 965fa1db8..0b2d0ef5e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListFragment.kt @@ -10,7 +10,6 @@ import androidx.core.net.toUri import androidx.fragment.app.viewModels import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar -import kotlinx.coroutines.flow.StateFlow import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.util.ShareHelper @@ -20,18 +19,18 @@ import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.filter.ui.FilterOwner import org.koitharu.kotatsu.filter.ui.FilterSheetFragment -import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel -import org.koitharu.kotatsu.filter.ui.model.FilterItem +import org.koitharu.kotatsu.filter.ui.MangaFilter import org.koitharu.kotatsu.list.ui.MangaListFragment -import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.parsers.model.MangaSource -import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment class LocalListFragment : MangaListFragment(), FilterOwner { override val viewModel by viewModels() + override val filter: MangaFilter + get() = viewModel + override fun onViewBindingCreated(binding: FragmentListBinding, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState) addMenuProvider(LocalListMenuProvider(this::onEmptyActionClick)) @@ -71,24 +70,6 @@ class LocalListFragment : MangaListFragment(), FilterOwner { } } - override val filterItems: StateFlow> - get() = viewModel.filterItems - - override val header: StateFlow - get() = viewModel.header - - override fun applyFilter(tags: Set) { - viewModel.applyFilter(tags) - } - - override fun onSortItemClick(item: FilterItem.Sort) { - viewModel.onSortItemClick(item) - } - - override fun onTagItemClick(item: FilterItem.Tag) { - viewModel.onTagItemClick(item) - } - private fun showDeletionConfirm(ids: Set, mode: ActionMode) { MaterialAlertDialogBuilder(context ?: return) .setTitle(R.string.delete_manga) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt index 502afa0ee..0c87936b3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt @@ -10,7 +10,6 @@ import androidx.appcompat.widget.SearchView import androidx.core.view.MenuProvider import androidx.fragment.app.viewModels import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.flow.StateFlow import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.util.ext.addMenuProvider @@ -18,13 +17,10 @@ import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.filter.ui.FilterOwner import org.koitharu.kotatsu.filter.ui.FilterSheetFragment -import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel -import org.koitharu.kotatsu.filter.ui.model.FilterItem +import org.koitharu.kotatsu.filter.ui.MangaFilter import org.koitharu.kotatsu.list.ui.MangaListFragment -import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.parsers.model.MangaSource -import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.search.ui.SearchActivity import org.koitharu.kotatsu.settings.SettingsActivity @@ -33,6 +29,9 @@ class RemoteListFragment : MangaListFragment(), FilterOwner { override val viewModel by viewModels() + override val filter: MangaFilter + get() = viewModel + override fun onViewBindingCreated(binding: FragmentListBinding, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState) addMenuProvider(RemoteListMenuProvider()) @@ -55,24 +54,6 @@ class RemoteListFragment : MangaListFragment(), FilterOwner { viewModel.resetFilter() } - override val filterItems: StateFlow> - get() = viewModel.filterItems - - override val header: StateFlow - get() = viewModel.header - - override fun applyFilter(tags: Set) { - viewModel.applyFilter(tags) - } - - override fun onSortItemClick(item: FilterItem.Sort) { - viewModel.onSortItemClick(item) - } - - override fun onTagItemClick(item: FilterItem.Tag) { - viewModel.onTagItemClick(item) - } - private inner class RemoteListMenuProvider : MenuProvider, SearchView.OnQueryTextListener, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt index b89e4788c..ef37f77fb 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt @@ -20,10 +20,11 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.call +import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.filter.ui.FilterCoordinator -import org.koitharu.kotatsu.filter.ui.FilterOwner +import org.koitharu.kotatsu.filter.ui.MangaFilter import org.koitharu.kotatsu.filter.ui.model.FilterState import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel @@ -36,7 +37,6 @@ import org.koitharu.kotatsu.list.ui.model.toUi import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaTag -import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import javax.inject.Inject private const val FILTER_MIN_INTERVAL = 250L @@ -49,7 +49,7 @@ open class RemoteListViewModel @Inject constructor( settings: AppSettings, listExtraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, -) : MangaListViewModel(settings, downloadScheduler), FilterOwner by filter { +) : MangaListViewModel(settings, downloadScheduler), MangaFilter by filter { val source = savedStateHandle.require(RemoteListFragment.ARG_SOURCE) private val repository = mangaRepositoryFactory.create(source) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/MangaListActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/MangaListActivity.kt index 84514d437..e5c3320a7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/MangaListActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/MangaListActivity.kt @@ -26,6 +26,7 @@ import org.koitharu.kotatsu.databinding.ActivityMangaListBinding import org.koitharu.kotatsu.filter.ui.FilterHeaderFragment import org.koitharu.kotatsu.filter.ui.FilterOwner import org.koitharu.kotatsu.filter.ui.FilterSheetFragment +import org.koitharu.kotatsu.filter.ui.MangaFilter import org.koitharu.kotatsu.local.ui.LocalListFragment import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.parsers.model.MangaSource @@ -35,11 +36,16 @@ import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment @AndroidEntryPoint class MangaListActivity : BaseActivity(), - AppBarOwner, View.OnClickListener { + AppBarOwner, View.OnClickListener, FilterOwner { override val appBar: AppBarLayout get() = viewBinding.appbar + override val filter: MangaFilter + get() = checkNotNull(findFilterOwner()) { + "Cannot find FilterOwner fragment in ${supportFragmentManager.fragments}" + }.filter + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivityMangaListBinding.inflate(layoutInflater)) @@ -109,13 +115,14 @@ class MangaListActivity : } } } + val filter = filterOwner.filter val chipSort = viewBinding.chipSort if (chipSort != null) { - filterOwner.header.observe(this) { + filter.header.observe(this) { chipSort.setTextAndVisible(it.sortOrder?.titleRes ?: 0) } } else { - filterOwner.header.map { + filter.header.map { it.textSummary }.flowOn(Dispatchers.Default) .observe(this) { @@ -124,13 +131,17 @@ class MangaListActivity : } } + private fun findFilterOwner(): FilterOwner? { + return supportFragmentManager.findFragmentById(R.id.container) as? FilterOwner + } + private class ApplyFilterRunnable( private val filterOwner: FilterOwner, private val tags: Set, ) : Runnable { override fun run() { - filterOwner.applyFilter(tags) + filterOwner.filter.applyFilter(tags) } }