Move favourites order from menu to header

This commit is contained in:
Koitharu
2022-07-12 14:34:08 +03:00
parent 2654de96ba
commit b293fee742
12 changed files with 58 additions and 115 deletions

View File

@@ -1,19 +1,20 @@
package org.koitharu.kotatsu.favourites.ui.list package org.koitharu.kotatsu.favourites.ui.list
import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.PopupMenu
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf import org.koin.core.parameter.parametersOf
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.titleRes
import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesActivity
import org.koitharu.kotatsu.list.ui.MangaListFragment import org.koitharu.kotatsu.list.ui.MangaListFragment
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.ext.addMenuProvider
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
class FavouritesListFragment : MangaListFragment() { class FavouritesListFragment : MangaListFragment(), PopupMenu.OnMenuItemClickListener {
override val viewModel by viewModel<FavouritesListViewModel> { override val viewModel by viewModel<FavouritesListViewModel> {
parametersOf(categoryId) parametersOf(categoryId)
@@ -24,16 +25,22 @@ class FavouritesListFragment : MangaListFragment() {
override val isSwipeRefreshEnabled = false override val isSwipeRefreshEnabled = false
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onScrolledToEnd() = Unit
super.onViewCreated(view, savedInstanceState)
viewModel.sortOrder.observe(viewLifecycleOwner) { activity?.invalidateOptionsMenu() }
if (categoryId != NO_ID) { override fun onFilterClick(view: View?) {
addMenuProvider(FavouritesListMenuProvider(viewModel)) val menu = PopupMenu(view?.context ?: return, view)
menu.setOnMenuItemClickListener(this)
for ((i, item) in FavouriteCategoriesActivity.SORT_ORDERS.withIndex()) {
menu.menu.add(Menu.NONE, Menu.NONE, i, item.titleRes)
} }
menu.show()
} }
override fun onScrolledToEnd() = Unit override fun onMenuItemClick(item: MenuItem): Boolean {
val order = FavouriteCategoriesActivity.SORT_ORDERS.getOrNull(item.order) ?: return false
viewModel.setSortOrder(order)
return true
}
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.mode_favourites, menu) mode.menuInflater.inflate(R.menu.mode_favourites, menu)

View File

@@ -1,48 +0,0 @@
package org.koitharu.kotatsu.favourites.ui.list
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.core.view.MenuProvider
import androidx.core.view.iterator
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.titleRes
import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesActivity
class FavouritesListMenuProvider(
private val viewModel: FavouritesListViewModel,
) : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.opt_favourites_list, menu)
menu.findItem(R.id.action_order)?.subMenu?.let { submenu ->
for ((i, item) in FavouriteCategoriesActivity.SORT_ORDERS.withIndex()) {
val menuItem = submenu.add(R.id.group_order, Menu.NONE, i, item.titleRes)
menuItem.isCheckable = true
}
submenu.setGroupCheckable(R.id.group_order, true, true)
}
}
override fun onPrepareMenu(menu: Menu) {
menu.findItem(R.id.action_order)?.subMenu?.let { submenu ->
val selectedOrder = viewModel.sortOrder.value
for (item in submenu) {
val order = FavouriteCategoriesActivity.SORT_ORDERS.getOrNull(item.order)
item.isChecked = order == selectedOrder
}
}
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return when {
menuItem.itemId == R.id.action_order -> false
menuItem.groupId == R.id.group_order -> {
val order = FavouriteCategoriesActivity.SORT_ORDERS.getOrNull(menuItem.order) ?: return false
viewModel.setSortOrder(order)
true
}
else -> false
}
}
}

View File

@@ -1,12 +1,9 @@
package org.koitharu.kotatsu.favourites.ui.list package org.koitharu.kotatsu.favourites.ui.list
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.plus
import kotlinx.coroutines.flow.map
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
@@ -15,10 +12,7 @@ import org.koitharu.kotatsu.history.domain.HistoryRepository
import org.koitharu.kotatsu.history.domain.PROGRESS_NONE import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.domain.ListExtraProvider
import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.MangaListViewModel
import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.*
import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.list.ui.model.toErrorState
import org.koitharu.kotatsu.list.ui.model.toUi
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.tracker.domain.TrackingRepository import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
@@ -31,12 +25,12 @@ class FavouritesListViewModel(
private val settings: AppSettings, private val settings: AppSettings,
) : MangaListViewModel(settings), ListExtraProvider { ) : MangaListViewModel(settings), ListExtraProvider {
var sortOrder: LiveData<SortOrder?> = if (categoryId == NO_ID) { private val sortOrder: StateFlow<SortOrder?> = if (categoryId == NO_ID) {
MutableLiveData(null) MutableStateFlow(null)
} else { } else {
repository.observeCategory(categoryId) repository.observeCategory(categoryId)
.map { it?.order } .map { it?.order }
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null)
} }
override val content = combine( override val content = combine(
@@ -45,8 +39,9 @@ class FavouritesListViewModel(
} else { } else {
repository.observeAll(categoryId) repository.observeAll(categoryId)
}, },
sortOrder,
createListModeFlow() createListModeFlow()
) { list, mode -> ) { list, order, mode ->
when { when {
list.isEmpty() -> listOf( list.isEmpty() -> listOf(
EmptyState( EmptyState(
@@ -60,7 +55,12 @@ class FavouritesListViewModel(
actionStringRes = 0, actionStringRes = 0,
) )
) )
else -> list.toUi(mode, this) else -> buildList<ListModel>(list.size + 1) {
if (order != null) {
add(ListHeader2(emptyList(), order, false))
}
list.toUi(this, mode, this@FavouritesListViewModel)
}
} }
}.catch { }.catch {
emit(listOf(it.toErrorState(canRetry = false))) emit(listOf(it.toErrorState(canRetry = false)))

View File

@@ -197,7 +197,7 @@ abstract class MangaListFragment :
} }
} }
override fun onFilterClick() = Unit override fun onFilterClick(view: View?) = Unit
override fun onEmptyActionClick() = Unit override fun onEmptyActionClick() = Unit

View File

@@ -16,7 +16,7 @@ fun listHeader2AD(
var ignoreChecking = false var ignoreChecking = false
binding.textViewFilter.setOnClickListener { binding.textViewFilter.setOnClickListener {
listener.onFilterClick() listener.onFilterClick(it)
} }
binding.chipsTags.setOnCheckedStateChangeListener { _, _ -> binding.chipsTags.setOnCheckedStateChangeListener { _, _ ->
if (!ignoreChecking) { if (!ignoreChecking) {

View File

@@ -32,7 +32,7 @@ fun listHeaderWithFilterAD(
) { ) {
binding.textViewFilter.setOnClickListener { binding.textViewFilter.setOnClickListener {
listener.onFilterClick() listener.onFilterClick(it)
} }
bind { bind {

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.list.ui.adapter package org.koitharu.kotatsu.list.ui.adapter
import android.view.View
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
@@ -8,5 +9,5 @@ interface MangaListListener : OnListItemClickListener<Manga>, ListStateHolderLis
fun onUpdateFilter(tags: Set<MangaTag>) fun onUpdateFilter(tags: Set<MangaTag>)
fun onFilterClick() fun onFilterClick(view: View?)
} }

View File

@@ -44,27 +44,13 @@ fun Manga.toGridModel(counter: Int, progress: Float) = MangaGridModel(
suspend fun List<Manga>.toUi( suspend fun List<Manga>.toUi(
mode: ListMode, mode: ListMode,
extraProvider: ListExtraProvider, extraProvider: ListExtraProvider,
): List<MangaItemModel> = when (mode) { ): List<MangaItemModel> = toUi(ArrayList(size), mode, extraProvider)
ListMode.LIST -> map {
it.toListModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
}
ListMode.DETAILED_LIST -> map {
it.toListDetailedModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
}
ListMode.GRID -> map {
it.toGridModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
}
}
fun List<Manga>.toUi( fun List<Manga>.toUi(
mode: ListMode, mode: ListMode,
): List<MangaItemModel> = when (mode) { ): List<MangaItemModel> = toUi(ArrayList(size), mode)
ListMode.LIST -> map { it.toListModel(0, PROGRESS_NONE) }
ListMode.DETAILED_LIST -> map { it.toListDetailedModel(0, PROGRESS_NONE) }
ListMode.GRID -> map { it.toGridModel(0, PROGRESS_NONE) }
}
fun <C : MutableCollection<ListModel>> List<Manga>.toUi( fun <C : MutableCollection<in MangaItemModel>> List<Manga>.toUi(
destination: C, destination: C,
mode: ListMode, mode: ListMode,
): C = when (mode) { ): C = when (mode) {
@@ -73,6 +59,22 @@ fun <C : MutableCollection<ListModel>> List<Manga>.toUi(
ListMode.GRID -> mapTo(destination) { it.toGridModel(0, PROGRESS_NONE) } ListMode.GRID -> mapTo(destination) { it.toGridModel(0, PROGRESS_NONE) }
} }
suspend fun <C : MutableCollection<in MangaItemModel>> List<Manga>.toUi(
destination: C,
mode: ListMode,
extraProvider: ListExtraProvider,
): C = when (mode) {
ListMode.LIST -> mapTo(destination) {
it.toListModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
}
ListMode.DETAILED_LIST -> mapTo(destination) {
it.toListDetailedModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
}
ListMode.GRID -> mapTo(destination) {
it.toGridModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
}
}
fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState( fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState(
exception = this, exception = this,
icon = getErrorIcon(this), icon = getErrorIcon(this),

View File

@@ -42,7 +42,7 @@ class RemoteListFragment : MangaListFragment() {
return super.onCreateActionMode(mode, menu) return super.onCreateActionMode(mode, menu)
} }
override fun onFilterClick() { override fun onFilterClick(view: View?) {
FilterBottomSheet.show(childFragmentManager) FilterBottomSheet.show(childFragmentManager)
} }
@@ -69,7 +69,7 @@ class RemoteListFragment : MangaListFragment() {
true true
} }
R.id.action_filter -> { R.id.action_filter -> {
onFilterClick() onFilterClick(null)
true true
} }
else -> false else -> false

View File

@@ -105,7 +105,7 @@ class MultiSearchActivity : BaseActivity<ActivitySearchMultiBinding>(), MangaLis
override fun onUpdateFilter(tags: Set<MangaTag>) = Unit override fun onUpdateFilter(tags: Set<MangaTag>) = Unit
override fun onFilterClick() = Unit override fun onFilterClick(view: View?) = Unit
override fun onEmptyActionClick() = Unit override fun onEmptyActionClick() = Unit

View File

@@ -89,7 +89,7 @@ class FeedFragment :
override fun onUpdateFilter(tags: Set<MangaTag>) = Unit override fun onUpdateFilter(tags: Set<MangaTag>) = Unit
override fun onFilterClick() = Unit override fun onFilterClick(view: View?) = Unit
override fun onEmptyActionClick() = Unit override fun onEmptyActionClick() = Unit

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_order"
android:orderInCategory="30"
android:title="@string/sort_order">
<menu>
<group
android:id="@+id/group_order"
android:checkableBehavior="single" />
</menu>
</item>
</menu>