Improve favorite categories screen (fix #1047)
This commit is contained in:
@@ -71,5 +71,11 @@ open class ReorderableListAdapter<T : ListModel> : ListDelegationAdapter<List<T>
|
||||
val newItem = newList[newItemPosition]
|
||||
return newItem == oldItem
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
|
||||
val oldItem = oldList[oldItemPosition]
|
||||
val newItem = newList[newItemPosition]
|
||||
return newItem.getChangePayload(oldItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
@@ -100,6 +101,18 @@ class FavouriteCategoriesActivity :
|
||||
return item != null && selectionController.onItemLongClick(item.id)
|
||||
}
|
||||
|
||||
override fun onSupportActionModeStarted(mode: ActionMode) {
|
||||
super.onSupportActionModeStarted(mode)
|
||||
viewBinding.fabAdd.hide()
|
||||
viewModel.setActionsEnabled(false)
|
||||
}
|
||||
|
||||
override fun onSupportActionModeFinished(mode: ActionMode) {
|
||||
super.onSupportActionModeFinished(mode)
|
||||
viewBinding.fabAdd.show()
|
||||
viewModel.setActionsEnabled(true)
|
||||
}
|
||||
|
||||
override fun onShowAllClick(isChecked: Boolean) {
|
||||
viewModel.setAllCategoriesVisible(isChecked)
|
||||
}
|
||||
@@ -138,6 +151,14 @@ class FavouriteCategoriesActivity :
|
||||
0,
|
||||
) {
|
||||
|
||||
override fun getDragDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
|
||||
return if (actionModeDelegate.isActionModeStarted) {
|
||||
0
|
||||
} else {
|
||||
super.getDragDirs(recyclerView, viewHolder)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||
|
||||
override fun onMove(
|
||||
|
||||
@@ -7,6 +7,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
@@ -34,13 +35,15 @@ class FavouritesCategoriesViewModel @Inject constructor(
|
||||
) : BaseViewModel() {
|
||||
|
||||
private var commitJob: Job? = null
|
||||
private val isActionsEnabled = MutableStateFlow(true)
|
||||
|
||||
val content = combine(
|
||||
repository.observeCategoriesWithCovers(),
|
||||
observeAllCategories(),
|
||||
settings.observeAsFlow(AppSettings.KEY_ALL_FAVOURITES_VISIBLE) { isAllFavouritesVisible },
|
||||
) { cats, all, showAll ->
|
||||
cats.toUiList(all, showAll)
|
||||
isActionsEnabled,
|
||||
) { cats, all, showAll, hasActions ->
|
||||
cats.toUiList(all, showAll, hasActions)
|
||||
}.withErrorHandling()
|
||||
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
|
||||
|
||||
@@ -77,6 +80,10 @@ class FavouritesCategoriesViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun setActionsEnabled(value: Boolean) {
|
||||
isActionsEnabled.value = value
|
||||
}
|
||||
|
||||
fun getCategories(ids: LongSet): ArrayList<FavouriteCategory> {
|
||||
val items = content.requireValue()
|
||||
return items.mapNotNullTo(ArrayList(ids.size)) { item ->
|
||||
@@ -86,7 +93,8 @@ class FavouritesCategoriesViewModel @Inject constructor(
|
||||
|
||||
private fun Map<FavouriteCategory, List<Cover>>.toUiList(
|
||||
allFavorites: Pair<Int, List<Cover>>,
|
||||
showAll: Boolean
|
||||
showAll: Boolean,
|
||||
hasActions: Boolean,
|
||||
): List<ListModel> {
|
||||
if (isEmpty()) {
|
||||
return listOf(
|
||||
@@ -104,6 +112,7 @@ class FavouritesCategoriesViewModel @Inject constructor(
|
||||
mangaCount = allFavorites.first,
|
||||
covers = allFavorites.second,
|
||||
isVisible = showAll,
|
||||
isActionsEnabled = hasActions,
|
||||
),
|
||||
)
|
||||
mapTo(result) { (category, covers) ->
|
||||
@@ -111,6 +120,7 @@ class FavouritesCategoriesViewModel @Inject constructor(
|
||||
mangaCount = covers.size,
|
||||
covers = covers.take(3),
|
||||
category = category,
|
||||
isActionsEnabled = hasActions,
|
||||
isTrackerEnabled = settings.isTrackerEnabled && AppSettings.TRACK_FAVOURITES in settings.trackSources,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@ data class AllCategoriesListModel(
|
||||
val mangaCount: Int,
|
||||
val covers: List<Cover>,
|
||||
val isVisible: Boolean,
|
||||
val isActionsEnabled: Boolean,
|
||||
) : ListModel {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is AllCategoriesListModel
|
||||
}
|
||||
|
||||
override fun getChangePayload(previousState: ListModel): Any? {
|
||||
return if (previousState is AllCategoriesListModel && previousState.isVisible != isVisible) {
|
||||
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
|
||||
} else {
|
||||
super.getChangePayload(previousState)
|
||||
}
|
||||
override fun getChangePayload(previousState: ListModel): Any? = when {
|
||||
previousState !is AllCategoriesListModel -> super.getChangePayload(previousState)
|
||||
previousState.isVisible != isVisible -> ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
|
||||
previousState.isActionsEnabled != isActionsEnabled -> ListModelDiffCallback.PAYLOAD_ANYTHING_CHANGED
|
||||
else -> super.getChangePayload(previousState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ fun categoryAD(
|
||||
binding.imageViewHandle.setOnTouchListener(eventListener)
|
||||
|
||||
bind {
|
||||
binding.imageViewHandle.isVisible = item.isActionsEnabled
|
||||
binding.imageViewEdit.isVisible = item.isActionsEnabled
|
||||
binding.textViewTitle.text = item.category.title
|
||||
binding.textViewSubtitle.text = if (item.mangaCount == 0) {
|
||||
getString(R.string.empty)
|
||||
@@ -138,6 +140,7 @@ fun allCategoriesAD(
|
||||
item.mangaCount,
|
||||
)
|
||||
}
|
||||
binding.imageViewVisible.isVisible = item.isActionsEnabled
|
||||
binding.imageViewVisible.setImageResource(
|
||||
if (item.isVisible) {
|
||||
R.drawable.ic_eye
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.favourites.ui.categories.adapter
|
||||
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.favourites.domain.model.Cover
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
class CategoryListModel(
|
||||
@@ -9,12 +10,19 @@ class CategoryListModel(
|
||||
val covers: List<Cover>,
|
||||
val category: FavouriteCategory,
|
||||
val isTrackerEnabled: Boolean,
|
||||
val isActionsEnabled: Boolean,
|
||||
) : ListModel {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is CategoryListModel && other.category.id == category.id
|
||||
}
|
||||
|
||||
override fun getChangePayload(previousState: ListModel): Any? = when {
|
||||
previousState !is CategoryListModel -> super.getChangePayload(previousState)
|
||||
previousState.isActionsEnabled != isActionsEnabled -> ListModelDiffCallback.PAYLOAD_ANYTHING_CHANGED
|
||||
else -> super.getChangePayload(previousState)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
@@ -23,6 +31,7 @@ class CategoryListModel(
|
||||
|
||||
if (mangaCount != other.mangaCount) return false
|
||||
if (isTrackerEnabled != other.isTrackerEnabled) return false
|
||||
if (isActionsEnabled != other.isActionsEnabled) return false
|
||||
if (covers != other.covers) return false
|
||||
if (category.id != other.category.id) return false
|
||||
if (category.title != other.category.title) return false
|
||||
@@ -36,6 +45,7 @@ class CategoryListModel(
|
||||
override fun hashCode(): Int {
|
||||
var result = mangaCount
|
||||
result = 31 * result + isTrackerEnabled.hashCode()
|
||||
result = 31 * result + isActionsEnabled.hashCode()
|
||||
result = 31 * result + covers.hashCode()
|
||||
result = 31 * result + category.id.hashCode()
|
||||
result = 31 * result + category.title.hashCode()
|
||||
|
||||
@@ -179,6 +179,7 @@
|
||||
layout="@layout/layout_details_chips"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/screen_padding"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier_header" />
|
||||
|
||||
@@ -54,18 +54,17 @@
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
tools:listitem="@layout/item_category" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/add_new_category"
|
||||
android:text="@string/create_category"
|
||||
android:src="@drawable/ic_add"
|
||||
app:fabSize="normal"
|
||||
app:icon="@drawable/ic_add"
|
||||
app:layout_anchor="@id/recyclerView"
|
||||
app:layout_anchorGravity="bottom|end"
|
||||
app:layout_behavior="org.koitharu.kotatsu.core.ui.util.ShrinkOnScrollBehavior"
|
||||
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
|
||||
app:layout_dodgeInsetEdges="bottom" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
Reference in New Issue
Block a user