Favourites container fixes
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
package org.koitharu.kotatsu.core.ui
|
||||
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.AsyncListDiffer.ListListener
|
||||
import com.hannesdorfmann.adapterdelegates4.AdapterDelegate
|
||||
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.asExecutor
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||
@@ -11,8 +14,12 @@ import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
open class BaseListAdapter(
|
||||
vararg delegates: AdapterDelegate<List<ListModel>>,
|
||||
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback, *delegates),
|
||||
FlowCollector<List<ListModel>> {
|
||||
) : AsyncListDifferDelegationAdapter<ListModel>(
|
||||
AsyncDifferConfig.Builder(ListModelDiffCallback)
|
||||
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
|
||||
.build(),
|
||||
*delegates,
|
||||
), FlowCollector<List<ListModel>> {
|
||||
|
||||
override suspend fun emit(value: List<ListModel>) = suspendCoroutine { cont ->
|
||||
setItems(value, ContinuationResumeRunnable(cont))
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.container
|
||||
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
class FavouriteTabModel(
|
||||
val id: Long,
|
||||
val title: String,
|
||||
) : ListModel {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is FavouriteTabModel && other.id == id
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as FavouriteTabModel
|
||||
|
||||
if (id != other.id) return false
|
||||
return title == other.title
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + title.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,31 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.container
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.AdapterListUpdateCallback
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
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.TabConfigurationStrategy
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.asExecutor
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable
|
||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class FavouritesContainerAdapter(fragment: Fragment) : FragmentStateAdapter(
|
||||
fragment.childFragmentManager,
|
||||
fragment.viewLifecycleOwner.lifecycle,
|
||||
),
|
||||
class FavouritesContainerAdapter(fragment: Fragment) :
|
||||
FragmentStateAdapter(fragment.childFragmentManager, fragment.viewLifecycleOwner.lifecycle),
|
||||
TabConfigurationStrategy,
|
||||
FlowCollector<List<FavouriteCategory>> {
|
||||
FlowCollector<List<FavouriteTabModel>> {
|
||||
|
||||
private val differ = AsyncListDiffer(this, DiffCallback())
|
||||
private val differ = AsyncListDiffer(
|
||||
AdapterListUpdateCallback(this),
|
||||
AsyncDifferConfig.Builder(DiffCallback())
|
||||
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
|
||||
.build(),
|
||||
)
|
||||
|
||||
override fun getItemCount(): Int = differ.currentList.size
|
||||
|
||||
@@ -27,8 +33,13 @@ class FavouritesContainerAdapter(fragment: Fragment) : FragmentStateAdapter(
|
||||
return differ.currentList[position].id
|
||||
}
|
||||
|
||||
override fun containsItem(itemId: Long): Boolean {
|
||||
return differ.currentList.any { x -> x.id == itemId }
|
||||
}
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return FavouritesListFragment.newInstance(getItemId(position))
|
||||
val item = differ.currentList[position]
|
||||
return FavouritesListFragment.newInstance(item.id)
|
||||
}
|
||||
|
||||
override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
|
||||
@@ -37,18 +48,18 @@ class FavouritesContainerAdapter(fragment: Fragment) : FragmentStateAdapter(
|
||||
tab.tag = item
|
||||
}
|
||||
|
||||
override suspend fun emit(value: List<FavouriteCategory>) = suspendCoroutine { cont ->
|
||||
override suspend fun emit(value: List<FavouriteTabModel>) = suspendCoroutine { cont ->
|
||||
differ.submitList(value, ContinuationResumeRunnable(cont))
|
||||
}
|
||||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<FavouriteCategory>() {
|
||||
private class DiffCallback : DiffUtil.ItemCallback<FavouriteTabModel>() {
|
||||
|
||||
override fun areItemsTheSame(oldItem: FavouriteCategory, newItem: FavouriteCategory): Boolean {
|
||||
override fun areItemsTheSame(oldItem: FavouriteTabModel, newItem: FavouriteTabModel): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: FavouriteCategory, newItem: FavouriteCategory): Boolean {
|
||||
return oldItem.title == newItem.title
|
||||
override fun areContentsTheSame(oldItem: FavouriteTabModel, newItem: FavouriteTabModel): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.container
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.util.ext.mapItems
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -11,4 +17,6 @@ class FavouritesContainerViewModel @Inject constructor(
|
||||
) : BaseViewModel() {
|
||||
|
||||
val categories = favouritesRepository.observeCategories()
|
||||
.mapItems { FavouriteTabModel(it.id, it.title) }
|
||||
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList())
|
||||
}
|
||||
|
||||
@@ -76,9 +76,6 @@ abstract class MangaListFragment :
|
||||
private var selectionController: ListSelectionController? = null
|
||||
private var spanResolver: MangaListSpanResolver? = null
|
||||
private val spanSizeLookup = SpanSizeLookup()
|
||||
private val listCommitCallback = Runnable {
|
||||
spanSizeLookup.invalidateCache()
|
||||
}
|
||||
open val isSwipeRefreshEnabled = true
|
||||
|
||||
protected abstract val viewModel: MangaListViewModel
|
||||
@@ -166,8 +163,9 @@ abstract class MangaListFragment :
|
||||
viewModel.onRefresh()
|
||||
}
|
||||
|
||||
private fun onListChanged(list: List<ListModel>) {
|
||||
listAdapter?.setItems(list, listCommitCallback)
|
||||
private suspend fun onListChanged(list: List<ListModel>) {
|
||||
listAdapter?.emit(list)
|
||||
spanSizeLookup.invalidateCache()
|
||||
}
|
||||
|
||||
private fun resolveException(e: Throwable) {
|
||||
@@ -341,8 +339,7 @@ abstract class MangaListFragment :
|
||||
}
|
||||
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
val total =
|
||||
(requireViewBinding().recyclerView.layoutManager as? GridLayoutManager)?.spanCount ?: return 1
|
||||
val total = (viewBinding?.recyclerView?.layoutManager as? GridLayoutManager)?.spanCount ?: return 1
|
||||
return when (listAdapter?.getItemViewType(position)) {
|
||||
ITEM_TYPE_MANGA_GRID -> 1
|
||||
else -> total
|
||||
|
||||
@@ -1,31 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="0dp"
|
||||
app:elevation="0dp"
|
||||
app:liftOnScroll="false">
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabGravity="start"
|
||||
app:tabMode="scrollable" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
app:tabGravity="start"
|
||||
app:tabMode="scrollable" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</LinearLayout>
|
||||
|
||||
Reference in New Issue
Block a user