Improve favorite categories screen (fix #1047)

This commit is contained in:
Koitharu
2024-08-20 15:17:29 +03:00
parent 05a64308ac
commit e4282a8e9d
8 changed files with 63 additions and 13 deletions

View File

@@ -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)
}
}
}

View File

@@ -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(

View File

@@ -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,
)
}

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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" />

View File

@@ -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>