diff --git a/app/src/main/java/org/koitharu/kotatsu/list/domain/AvailableFilters.kt b/app/src/main/java/org/koitharu/kotatsu/list/domain/AvailableFilters.kt new file mode 100644 index 000000000..414a219db --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/list/domain/AvailableFilters.kt @@ -0,0 +1,30 @@ +package org.koitharu.kotatsu.list.domain + +import org.koitharu.kotatsu.core.model.MangaTag +import org.koitharu.kotatsu.core.model.SortOrder + +class AvailableFilters( + val sortOrders: Set, + val tags: Set, +) { + + val size: Int + get() = sortOrders.size + tags.size + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as AvailableFilters + if (sortOrders != other.sortOrders) return false + if (tags != other.tags) return false + return true + } + + override fun hashCode(): Int { + var result = sortOrders.hashCode() + result = 31 * result + tags.hashCode() + return result + } + + fun isEmpty(): Boolean = sortOrders.isEmpty() && tags.isEmpty() +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaFilterConfig.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaFilterConfig.kt deleted file mode 100644 index e2147aa97..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaFilterConfig.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.koitharu.kotatsu.list.ui - -import org.koitharu.kotatsu.core.model.MangaFilter -import org.koitharu.kotatsu.core.model.MangaTag -import org.koitharu.kotatsu.core.model.SortOrder - -data class MangaFilterConfig( - val sortOrders: List, - val tags: List, - val currentFilter: MangaFilter? -) \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt index 1fa44344c..11b29eaa4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt @@ -22,19 +22,17 @@ import org.koitharu.kotatsu.base.ui.BaseFragment import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.list.PaginationScrollListener import org.koitharu.kotatsu.base.ui.list.decor.ItemTypeDividerDecoration -import org.koitharu.kotatsu.base.ui.list.decor.SectionItemDecoration import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.browser.cloudflare.CloudFlareDialog import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.resolve.ResolvableException import org.koitharu.kotatsu.core.model.Manga -import org.koitharu.kotatsu.core.model.MangaFilter import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter -import org.koitharu.kotatsu.list.ui.filter.FilterAdapter -import org.koitharu.kotatsu.list.ui.filter.OnFilterChangedListener +import org.koitharu.kotatsu.list.ui.filter.FilterAdapter2 +import org.koitharu.kotatsu.list.ui.filter.FilterItem import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.main.ui.AppBarOwner import org.koitharu.kotatsu.main.ui.MainActivity @@ -42,10 +40,11 @@ import org.koitharu.kotatsu.utils.RecycledViewPoolHolder import org.koitharu.kotatsu.utils.ext.* abstract class MangaListFragment : BaseFragment(), - PaginationScrollListener.Callback, OnListItemClickListener, OnFilterChangedListener, - SectionItemDecoration.Callback, SwipeRefreshLayout.OnRefreshListener { + PaginationScrollListener.Callback, OnListItemClickListener, + SwipeRefreshLayout.OnRefreshListener { private var listAdapter: MangaListAdapter? = null + private var filterAdapter: FilterAdapter2? = null private var paginationListener: PaginationScrollListener? = null private val spanResolver = MangaListSpanResolver() private val spanSizeLookup = SpanSizeLookup() @@ -78,6 +77,7 @@ abstract class MangaListFragment : BaseFragment(), onRetryClick = ::resolveException, onTagRemoveClick = viewModel::onRemoveFilterTag ) + filterAdapter = FilterAdapter2(viewModel) paginationListener = PaginationScrollListener(4, this) with(binding.recyclerView) { setHasFixedSize(true) @@ -94,8 +94,7 @@ abstract class MangaListFragment : BaseFragment(), } with(binding.recyclerViewFilter) { setHasFixedSize(true) - addItemDecoration(ItemTypeDividerDecoration(view.context)) - addItemDecoration(SectionItemDecoration(false, this@MangaListFragment)) + adapter = filterAdapter } (parentFragment as? RecycledViewPoolHolder)?.let { @@ -113,6 +112,7 @@ abstract class MangaListFragment : BaseFragment(), override fun onDestroyView() { drawer = null listAdapter = null + filterAdapter = null paginationListener = null spanSizeLookup.invalidateCache() super.onDestroyView() @@ -203,28 +203,21 @@ abstract class MangaListFragment : BaseFragment(), } } - protected fun onInitFilter(config: MangaFilterConfig) { - binding.recyclerViewFilter.adapter = FilterAdapter( - sortOrders = config.sortOrders, - tags = config.tags, - state = config.currentFilter, - listener = this - ) + protected fun onInitFilter(filter: List) { + filterAdapter?.items = filter drawer?.setDrawerLockMode( - if (config.sortOrders.isEmpty() && config.tags.isEmpty()) { + if (filter.isEmpty()) { DrawerLayout.LOCK_MODE_LOCKED_CLOSED } else { DrawerLayout.LOCK_MODE_UNLOCKED } ) ?: binding.dividerFilter?.let { - it.isGone = config.sortOrders.isEmpty() && config.tags.isEmpty() + it.isGone = filter.isEmpty() binding.recyclerViewFilter.isVisible = it.isVisible } activity?.invalidateOptionsMenu() } - override fun onFilterChanged(filter: MangaFilter) = Unit - override fun onWindowInsetsChanged(insets: Insets) { val headerHeight = (activity as? AppBarOwner)?.appBar?.measureHeight() ?: insets.top binding.recyclerViewFilter.updatePadding( @@ -284,20 +277,6 @@ abstract class MangaListFragment : BaseFragment(), } } - final override fun isSection(position: Int): Boolean { - return position == 0 || binding.recyclerViewFilter.adapter?.run { - getItemViewType(position) != getItemViewType(position - 1) - } ?: false - } - - final override fun getSectionTitle(position: Int): CharSequence? { - return when (binding.recyclerViewFilter.adapter?.getItemViewType(position)) { - FilterAdapter.VIEW_TYPE_SORT -> getString(R.string.sort_order) - FilterAdapter.VIEW_TYPE_TAG -> getString(R.string.genres) - else -> null - } - } - protected open fun onCreatePopupMenu(inflater: MenuInflater, menu: Menu, data: Manga) = Unit protected open fun onPopupMenuItemSelected(item: MenuItem, data: Manga) = false diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt index 3d94d1b65..e2a463f4e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt @@ -1,23 +1,32 @@ package org.koitharu.kotatsu.list.ui +import androidx.annotation.CallSuper import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.ensureActive import kotlinx.coroutines.flow.* +import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseViewModel +import org.koitharu.kotatsu.core.model.MangaFilter import org.koitharu.kotatsu.core.model.MangaTag import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode +import org.koitharu.kotatsu.list.domain.AvailableFilters +import org.koitharu.kotatsu.list.ui.filter.FilterItem +import org.koitharu.kotatsu.list.ui.filter.OnFilterChangedListener import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct abstract class MangaListViewModel( - private val settings: AppSettings -) : BaseViewModel() { + private val settings: AppSettings, +) : BaseViewModel(), OnFilterChangedListener { abstract val content: LiveData> - val filter = MutableLiveData() + val filter = MutableLiveData>() val listMode = MutableLiveData() val gridScale = settings.observe() .filter { it == AppSettings.KEY_GRID_SIZE } @@ -37,7 +46,62 @@ abstract class MangaListViewModel( } } - open fun onRemoveFilterTag(tag: MangaTag) = Unit + protected var currentFilter: MangaFilter = MangaFilter(null, emptySet()) + private set(value) { + field = value + onFilterChanged() + } + protected var availableFilters: AvailableFilters? = null + private var filterJob: Job? = null + + final override fun onSortItemClick(item: FilterItem.Sort) { + currentFilter = currentFilter.copy(sortOrder = item.order) + } + + final override fun onTagItemClick(item: FilterItem.Tag) { + val tags = if (item.isChecked) { + currentFilter.tags - item.tag + } else { + currentFilter.tags + item.tag + } + currentFilter = currentFilter.copy(tags = tags) + } + + fun onRemoveFilterTag(tag: MangaTag) { + val tags = currentFilter.tags + if (tag !in tags) { + return + } + currentFilter = currentFilter.copy(tags = tags - tag) + } + + @CallSuper + open fun onFilterChanged() { + val previousJob = filterJob + filterJob = launchJob(Dispatchers.Default) { + previousJob?.cancelAndJoin() + filter.postValue( + availableFilters?.run { + val list = ArrayList(size + 2) + if (sortOrders.isNotEmpty()) { + val selectedSort = currentFilter.sortOrder ?: sortOrders.first() + list += FilterItem.Header(R.string.sort_order) + sortOrders.sortedBy { it.ordinal }.mapTo(list) { + FilterItem.Sort(it, isSelected = it == selectedSort) + } + } + if (tags.isNotEmpty()) { + list += FilterItem.Header(R.string.genres) + tags.sortedBy { it.title }.mapTo(list) { + FilterItem.Tag(it, isChecked = it in currentFilter.tags) + } + } + ensureActive() + list + }.orEmpty() + ) + } + } abstract fun onRefresh() diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapter.kt deleted file mode 100644 index 983fdf0f1..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapter.kt +++ /dev/null @@ -1,94 +0,0 @@ -package org.koitharu.kotatsu.list.ui.filter - -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import org.koitharu.kotatsu.base.ui.list.BaseViewHolder -import org.koitharu.kotatsu.core.model.MangaFilter -import org.koitharu.kotatsu.core.model.MangaTag -import org.koitharu.kotatsu.core.model.SortOrder - -class FilterAdapter( - private val sortOrders: List = emptyList(), - private val tags: List = emptyList(), - state: MangaFilter?, - private val listener: OnFilterChangedListener -) : RecyclerView.Adapter>() { - - private var currentState = state ?: MangaFilter(sortOrders.firstOrNull(), emptySet()) - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) { - VIEW_TYPE_SORT -> FilterSortHolder(parent).apply { - itemView.setOnClickListener { - setCheckedSort(requireData()) - } - } - VIEW_TYPE_TAG -> FilterTagHolder(parent).apply { - itemView.setOnClickListener { - setCheckedTag(boundData ?: return@setOnClickListener, !isChecked) - } - } - else -> throw IllegalArgumentException("Unknown viewType $viewType") - } - - override fun getItemCount() = sortOrders.size + tags.size - - override fun onBindViewHolder(holder: BaseViewHolder<*, Boolean, *>, position: Int) { - when (holder) { - is FilterSortHolder -> { - val item = sortOrders[position] - holder.bind(item, item == currentState.sortOrder) - } - is FilterTagHolder -> { - val item = tags[position - sortOrders.size] - holder.bind(item, item in currentState.tags) - } - } - } - - override fun getItemViewType(position: Int) = when (position) { - in sortOrders.indices -> VIEW_TYPE_SORT - else -> VIEW_TYPE_TAG - } - - fun setCheckedTag(tag: MangaTag, isChecked: Boolean) { - currentState = if (tag in currentState.tags) { - if (!isChecked) { - currentState.copy(tags = currentState.tags - tag) - } else { - return - } - } else { - if (isChecked) { - currentState.copy(tags = currentState.tags + tag) - } else { - return - } - } - val index = tags.indexOf(tag) - if (index in tags.indices) { - notifyItemChanged(sortOrders.size + index) - } - listener.onFilterChanged(currentState) - } - - fun setCheckedSort(sort: SortOrder) { - if (sort != currentState.sortOrder) { - val oldItemPos = sortOrders.indexOf(currentState.sortOrder) - val newItemPos = sortOrders.indexOf(sort) - currentState = currentState.copy(sortOrder = sort) - if (oldItemPos in sortOrders.indices) { - notifyItemChanged(oldItemPos) - } - if (newItemPos in sortOrders.indices) { - notifyItemChanged(newItemPos) - } - listener.onFilterChanged(currentState) - } - } - - companion object { - - const val VIEW_TYPE_SORT = 0 - const val VIEW_TYPE_TAG = 1 - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapter2.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapter2.kt new file mode 100644 index 000000000..67b4d3585 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapter2.kt @@ -0,0 +1,12 @@ +package org.koitharu.kotatsu.list.ui.filter + +import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter + +class FilterAdapter2( + listener: OnFilterChangedListener, +) : AsyncListDifferDelegationAdapter( + FilterDiffCallback(), + filterSortDelegate(listener), + filterTagDelegate(listener), + filterHeaderDelegate(), +) \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapterDelegates.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapterDelegates.kt new file mode 100644 index 000000000..8b926d768 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterAdapterDelegates.kt @@ -0,0 +1,47 @@ +package org.koitharu.kotatsu.list.ui.filter + +import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding +import org.koitharu.kotatsu.databinding.ItemCheckableMultipleBinding +import org.koitharu.kotatsu.databinding.ItemCheckableSingleBinding +import org.koitharu.kotatsu.databinding.ItemFilterHeaderBinding + +fun filterSortDelegate( + listener: OnFilterChangedListener, +) = adapterDelegateViewBinding( + { layoutInflater, parent -> ItemCheckableSingleBinding.inflate(layoutInflater, parent, false) } +) { + + itemView.setOnClickListener { + listener.onSortItemClick(item) + } + + bind { + binding.root.setText(item.order.titleRes) + binding.root.isChecked = item.isSelected + } +} + +fun filterTagDelegate( + listener: OnFilterChangedListener, +) = adapterDelegateViewBinding( + { layoutInflater, parent -> ItemCheckableMultipleBinding.inflate(layoutInflater, parent, false) } +) { + + itemView.setOnClickListener { + listener.onTagItemClick(item) + } + + bind { + binding.root.text = item.tag.title + binding.root.isChecked = item.isChecked + } +} + +fun filterHeaderDelegate() = adapterDelegateViewBinding( + { layoutInflater, parent -> ItemFilterHeaderBinding.inflate(layoutInflater, parent, false) } +) { + + bind { + binding.root.setText(item.titleResId) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterDiffCallback.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterDiffCallback.kt new file mode 100644 index 000000000..1ccd4e813 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterDiffCallback.kt @@ -0,0 +1,48 @@ +package org.koitharu.kotatsu.list.ui.filter + +import androidx.recyclerview.widget.DiffUtil + +class FilterDiffCallback : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: FilterItem, newItem: FilterItem): Boolean { + return when { + oldItem.javaClass != newItem.javaClass -> false + oldItem is FilterItem.Header && newItem is FilterItem.Header -> { + oldItem.titleResId == newItem.titleResId + } + oldItem is FilterItem.Tag && newItem is FilterItem.Tag -> { + oldItem.tag == newItem.tag + } + oldItem is FilterItem.Sort && newItem is FilterItem.Sort -> { + oldItem.order == newItem.order + } + else -> false + } + } + + override fun areContentsTheSame(oldItem: FilterItem, newItem: FilterItem): Boolean { + return when { + oldItem is FilterItem.Header && newItem is FilterItem.Header -> true + oldItem is FilterItem.Tag && newItem is FilterItem.Tag -> { + oldItem.isChecked == newItem.isChecked + } + oldItem is FilterItem.Sort && newItem is FilterItem.Sort -> { + oldItem.isSelected == newItem.isSelected + } + else -> false + } + } + + override fun getChangePayload(oldItem: FilterItem, newItem: FilterItem): Any? { + val isCheckedChanged = when { + oldItem is FilterItem.Tag && newItem is FilterItem.Tag -> { + oldItem.isChecked != newItem.isChecked + } + oldItem is FilterItem.Sort && newItem is FilterItem.Sort -> { + oldItem.isSelected != newItem.isSelected + } + else -> false + } + return if (isCheckedChanged) Unit else super.getChangePayload(oldItem, newItem) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterItem.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterItem.kt new file mode 100644 index 000000000..a74d93b1d --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterItem.kt @@ -0,0 +1,22 @@ +package org.koitharu.kotatsu.list.ui.filter + +import androidx.annotation.StringRes +import org.koitharu.kotatsu.core.model.MangaTag +import org.koitharu.kotatsu.core.model.SortOrder + +sealed interface FilterItem { + + class Header( + @StringRes val titleResId: Int, + ) : FilterItem + + class Sort( + val order: SortOrder, + val isSelected: Boolean, + ) : FilterItem + + class Tag( + val tag: MangaTag, + val isChecked: Boolean, + ) : FilterItem +} diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterSortHolder.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterSortHolder.kt deleted file mode 100644 index 9275ae831..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterSortHolder.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.koitharu.kotatsu.list.ui.filter - -import android.view.LayoutInflater -import android.view.ViewGroup -import org.koitharu.kotatsu.base.ui.list.BaseViewHolder -import org.koitharu.kotatsu.core.model.SortOrder -import org.koitharu.kotatsu.databinding.ItemCheckableSingleBinding - -class FilterSortHolder(parent: ViewGroup) : - BaseViewHolder( - ItemCheckableSingleBinding.inflate(LayoutInflater.from(parent.context), parent, false) - ) { - - override fun onBind(data: SortOrder, extra: Boolean) { - binding.root.setText(data.titleRes) - binding.root.isChecked = extra - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterTagHolder.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterTagHolder.kt deleted file mode 100644 index 2054d4cb9..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterTagHolder.kt +++ /dev/null @@ -1,21 +0,0 @@ -package org.koitharu.kotatsu.list.ui.filter - -import android.view.LayoutInflater -import android.view.ViewGroup -import org.koitharu.kotatsu.base.ui.list.BaseViewHolder -import org.koitharu.kotatsu.core.model.MangaTag -import org.koitharu.kotatsu.databinding.ItemCheckableMultipleBinding - -class FilterTagHolder(parent: ViewGroup) : - BaseViewHolder( - ItemCheckableMultipleBinding.inflate(LayoutInflater.from(parent.context), parent, false) - ) { - - val isChecked: Boolean - get() = binding.root.isChecked - - override fun onBind(data: MangaTag, extra: Boolean) { - binding.root.text = data.title - binding.root.isChecked = extra - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/OnFilterChangedListener.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/OnFilterChangedListener.kt index 93a1b7db5..a28596c9f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/OnFilterChangedListener.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/OnFilterChangedListener.kt @@ -1,8 +1,8 @@ package org.koitharu.kotatsu.list.ui.filter -import org.koitharu.kotatsu.core.model.MangaFilter +interface OnFilterChangedListener { -fun interface OnFilterChangedListener { + fun onSortItemClick(item: FilterItem.Sort) - fun onFilterChanged(filter: MangaFilter) + fun onTagItemClick(item: FilterItem.Tag) } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt index d3e593838..5ae3a92da 100644 --- a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt @@ -6,7 +6,6 @@ import android.view.MenuItem import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.model.MangaFilter import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.list.ui.MangaListFragment import org.koitharu.kotatsu.reader.ui.SimpleSettingsActivity @@ -29,10 +28,6 @@ class RemoteListFragment : MangaListFragment() { return source.title } - override fun onFilterChanged(filter: MangaFilter) { - viewModel.applyFilter(filter) - } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) inflater.inflate(R.menu.opt_list_remote, menu) diff --git a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt index d8df693a3..b9b1f3d3e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt @@ -9,12 +9,10 @@ import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.widgets.ChipsView import org.koitharu.kotatsu.core.model.Manga -import org.koitharu.kotatsu.core.model.MangaFilter -import org.koitharu.kotatsu.core.model.MangaTag import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.list.ui.MangaFilterConfig +import org.koitharu.kotatsu.list.domain.AvailableFilters import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.* import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct @@ -27,7 +25,6 @@ class RemoteListViewModel( private val mangaList = MutableStateFlow?>(null) private val hasNextPage = MutableStateFlow(false) private val listError = MutableStateFlow(null) - private var appliedFilter: MangaFilter? = null private var loadingJob: Job? = null private val headerModel = ListHeader((repository as RemoteMangaRepository).title, 0) @@ -68,16 +65,6 @@ class RemoteListViewModel( loadList(append = !mangaList.value.isNullOrEmpty()) } - override fun onRemoveFilterTag(tag: MangaTag) { - val filter = appliedFilter ?: return - if (tag !in filter.tags) { - return - } - applyFilter( - filter.copy(tags = filter.tags - tag) - ) - } - fun loadNextPage() { if (hasNextPage.value && listError.value == null) { loadList(append = true) @@ -93,8 +80,8 @@ class RemoteListViewModel( listError.value = null val list = repository.getList2( offset = if (append) mangaList.value?.size ?: 0 else 0, - sortOrder = appliedFilter?.sortOrder, - tags = appliedFilter?.tags, + sortOrder = currentFilter.sortOrder, + tags = currentFilter.tags, ) if (!append) { mangaList.value = list @@ -111,26 +98,29 @@ class RemoteListViewModel( } } - fun applyFilter(newFilter: MangaFilter) { - appliedFilter = newFilter + override fun onFilterChanged() { + super.onFilterChanged() mangaList.value = null hasNextPage.value = false loadList(false) - filter.value?.run { - filter.value = copy(currentFilter = newFilter) - } } - private fun createFilterModel() = appliedFilter?.run { - CurrentFilterModel(tags.map { ChipsView.ChipModel(0, it.title, it) }) + private fun createFilterModel(): CurrentFilterModel? { + val tags = currentFilter.tags + return if (tags.isEmpty()) { + null + } else { + CurrentFilterModel(tags.map { ChipsView.ChipModel(0, it.title, it) }) + } } private fun loadFilter() { launchJob(Dispatchers.Default) { try { - val sorts = repository.sortOrders.sortedBy { it.ordinal } - val tags = repository.getTags().sortedBy { it.title } - filter.postValue(MangaFilterConfig(sorts, tags, appliedFilter)) + val sorts = repository.sortOrders + val tags = repository.getTags() + availableFilters = AvailableFilters(sorts, tags) + onFilterChanged() } catch (e: Exception) { if (BuildConfig.DEBUG) { e.printStackTrace()