Move favourites order from menu to header
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)))
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ fun listHeaderWithFilterAD(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
binding.textViewFilter.setOnClickListener {
|
binding.textViewFilter.setOnClickListener {
|
||||||
listener.onFilterClick()
|
listener.onFilterClick(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
bind {
|
bind {
|
||||||
|
|||||||
@@ -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?)
|
||||||
}
|
}
|
||||||
@@ -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),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
|
||||||
Reference in New Issue
Block a user