Fix favourites categories
This commit is contained in:
@@ -4,6 +4,7 @@ import androidx.collection.ArraySet
|
||||
import androidx.room.withTransaction
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
@@ -61,13 +62,13 @@ class FavouritesRepository(private val db: MangaDatabase) {
|
||||
fun observeCategories(): Flow<List<FavouriteCategory>> {
|
||||
return db.favouriteCategoriesDao.observeAll().mapItems {
|
||||
it.toFavouriteCategory()
|
||||
}
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
fun observeCategories(mangaId: Long): Flow<List<FavouriteCategory>> {
|
||||
return db.favouritesDao.observe(mangaId).map { entity ->
|
||||
entity?.categories?.map { it.toFavouriteCategory() }.orEmpty()
|
||||
}
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
fun observeCategoriesIds(mangaId: Long): Flow<List<Long>> {
|
||||
|
||||
@@ -26,6 +26,7 @@ class FavouritesContainerFragment : BaseFragment<FragmentFavouritesBinding>(),
|
||||
private val editDelegate by lazy(LazyThreadSafetyMode.NONE) {
|
||||
CategoriesEditDelegate(requireContext(), this)
|
||||
}
|
||||
private var pagerAdapter: FavouritesPagerAdapter? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -40,13 +41,22 @@ class FavouritesContainerFragment : BaseFragment<FragmentFavouritesBinding>(),
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val adapter = FavouritesPagerAdapter(this, this)
|
||||
viewModel.categories.value?.let {
|
||||
adapter.replaceData(wrapCategories(it))
|
||||
}
|
||||
binding.pager.adapter = adapter
|
||||
pagerAdapter = adapter
|
||||
TabLayoutMediator(binding.tabs, binding.pager, adapter).attach()
|
||||
|
||||
viewModel.categories.observe(viewLifecycleOwner, ::onCategoriesChanged)
|
||||
viewModel.onError.observe(viewLifecycleOwner, ::onError)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
pagerAdapter = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) {
|
||||
binding.tabs.updatePadding(
|
||||
left = insets.left,
|
||||
@@ -55,10 +65,7 @@ class FavouritesContainerFragment : BaseFragment<FragmentFavouritesBinding>(),
|
||||
}
|
||||
|
||||
private fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
val data = ArrayList<FavouriteCategory>(categories.size + 1)
|
||||
data += FavouriteCategory(0L, getString(R.string.all_favourites), -1, Date())
|
||||
data += categories
|
||||
(binding.pager.adapter as? FavouritesPagerAdapter)?.replaceData(data)
|
||||
pagerAdapter?.replaceData(wrapCategories(categories))
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
@@ -109,6 +116,13 @@ class FavouritesContainerFragment : BaseFragment<FragmentFavouritesBinding>(),
|
||||
viewModel.createCategory(name)
|
||||
}
|
||||
|
||||
private fun wrapCategories(categories: List<FavouriteCategory>): List<FavouriteCategory> {
|
||||
val data = ArrayList<FavouriteCategory>(categories.size + 1)
|
||||
data += FavouriteCategory(0L, getString(R.string.all_favourites), -1, Date())
|
||||
data += categories
|
||||
return data
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance() = FavouritesContainerFragment()
|
||||
|
||||
@@ -2,44 +2,55 @@ package org.koitharu.kotatsu.favourites.ui
|
||||
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.AsyncListDiffer
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import org.koitharu.kotatsu.base.ui.list.AdapterUpdater
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment
|
||||
import org.koitharu.kotatsu.utils.ext.replaceWith
|
||||
|
||||
class FavouritesPagerAdapter(
|
||||
fragment: Fragment,
|
||||
private val longClickListener: FavouritesTabLongClickListener
|
||||
) : FragmentStateAdapter(fragment),
|
||||
) : FragmentStateAdapter(fragment.childFragmentManager, fragment.viewLifecycleOwner.lifecycle),
|
||||
TabLayoutMediator.TabConfigurationStrategy, View.OnLongClickListener {
|
||||
|
||||
private val dataSet = ArrayList<FavouriteCategory>()
|
||||
private val differ = AsyncListDiffer(this, DiffCallback())
|
||||
|
||||
override fun getItemCount() = dataSet.size
|
||||
override fun getItemCount() = differ.currentList.size
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
val item = dataSet[position]
|
||||
val item = differ.currentList[position]
|
||||
return FavouritesListFragment.newInstance(item.id)
|
||||
}
|
||||
|
||||
override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
|
||||
val item = dataSet[position]
|
||||
val item = differ.currentList[position]
|
||||
tab.text = item.title
|
||||
tab.view.tag = item
|
||||
tab.view.setOnLongClickListener(this)
|
||||
}
|
||||
|
||||
fun replaceData(data: List<FavouriteCategory>) {
|
||||
val updater = AdapterUpdater(dataSet, data, FavouriteCategory::id)
|
||||
dataSet.replaceWith(data)
|
||||
updater(this)
|
||||
differ.submitList(data)
|
||||
}
|
||||
|
||||
override fun onLongClick(v: View): Boolean {
|
||||
val item = v.tag as? FavouriteCategory ?: return false
|
||||
return longClickListener.onTabLongClick(v, item)
|
||||
}
|
||||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<FavouriteCategory>() {
|
||||
|
||||
override fun areItemsTheSame(
|
||||
oldItem: FavouriteCategory,
|
||||
newItem: FavouriteCategory
|
||||
): Boolean = oldItem.id == newItem.id
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: FavouriteCategory,
|
||||
newItem: FavouriteCategory
|
||||
): Boolean = oldItem.id == newItem.id && oldItem.title == newItem.title
|
||||
}
|
||||
}
|
||||
@@ -93,8 +93,6 @@ class CategoriesActivity : BaseActivity<ActivityCategoriesBinding>(),
|
||||
}
|
||||
|
||||
private fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
// TODO check if not moved
|
||||
|
||||
adapter.items = categories
|
||||
binding.textViewHolder.isVisible = categories.isEmpty()
|
||||
}
|
||||
@@ -124,14 +122,22 @@ class CategoriesActivity : BaseActivity<ActivityCategoriesBinding>(),
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val oldPos = viewHolder.bindingAdapterPosition
|
||||
val newPos = target.bindingAdapterPosition
|
||||
viewModel.reorderCategories(oldPos, newPos)
|
||||
return true
|
||||
}
|
||||
): Boolean = true
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||
|
||||
override fun onMoved(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
fromPos: Int,
|
||||
target: RecyclerView.ViewHolder,
|
||||
toPos: Int,
|
||||
x: Int,
|
||||
y: Int
|
||||
) {
|
||||
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y)
|
||||
viewModel.reorderCategories(fromPos, toPos)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -4,7 +4,6 @@ import androidx.recyclerview.widget.DiffUtil
|
||||
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
|
||||
class CategoriesAdapter(
|
||||
onItemClickListener: OnListItemClickListener<FavouriteCategory>
|
||||
@@ -26,7 +25,7 @@ class CategoriesAdapter(
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: FavouriteCategory, newItem: FavouriteCategory): Boolean {
|
||||
return Intrinsics.areEqual(oldItem, newItem)
|
||||
return oldItem.id == newItem.id && oldItem.title == newItem.title
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import kotlinx.coroutines.Job
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class FavouritesCategoriesViewModel(
|
||||
private val repository: FavouritesRepository
|
||||
@@ -40,8 +42,7 @@ class FavouritesCategoriesViewModel(
|
||||
prevJob?.join()
|
||||
val items = categories.value ?: error("This should not happen")
|
||||
val ids = items.mapTo(ArrayList(items.size)) { it.id }
|
||||
val item = ids.removeAt(oldPos)
|
||||
ids.add(newPos, item)
|
||||
Collections.swap(ids, oldPos, newPos)
|
||||
repository.reorderCategories(ids)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ 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.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.onFirst
|
||||
|
||||
class FavouritesListViewModel(
|
||||
private val categoryId: Long,
|
||||
@@ -38,8 +37,6 @@ class FavouritesListViewModel(
|
||||
)
|
||||
else -> list.toUi(mode)
|
||||
}
|
||||
}.onFirst {
|
||||
isLoading.postValue(false)
|
||||
}.catch {
|
||||
emit(listOf(it.toErrorState(canRetry = false)))
|
||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState))
|
||||
|
||||
Reference in New Issue
Block a user