Favourites container fixes

pull/421/head
Koitharu 3 years ago
parent ed672feebe
commit 7908eb1441
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -1,8 +1,11 @@
package org.koitharu.kotatsu.core.ui package org.koitharu.kotatsu.core.ui
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.AsyncListDiffer.ListListener import androidx.recyclerview.widget.AsyncListDiffer.ListListener
import com.hannesdorfmann.adapterdelegates4.AdapterDelegate import com.hannesdorfmann.adapterdelegates4.AdapterDelegate
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.FlowCollector
import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
@ -11,8 +14,12 @@ import kotlin.coroutines.suspendCoroutine
open class BaseListAdapter( open class BaseListAdapter(
vararg delegates: AdapterDelegate<List<ListModel>>, vararg delegates: AdapterDelegate<List<ListModel>>,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback, *delegates), ) : AsyncListDifferDelegationAdapter<ListModel>(
FlowCollector<List<ListModel>> { AsyncDifferConfig.Builder(ListModelDiffCallback)
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
.build(),
*delegates,
), FlowCollector<List<ListModel>> {
override suspend fun emit(value: List<ListModel>) = suspendCoroutine { cont -> override suspend fun emit(value: List<ListModel>) = suspendCoroutine { cont ->
setItems(value, ContinuationResumeRunnable(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 package org.koitharu.kotatsu.favourites.ui.container
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.AdapterListUpdateCallback
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.AsyncListDiffer import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.FlowCollector
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
class FavouritesContainerAdapter(fragment: Fragment) : FragmentStateAdapter( class FavouritesContainerAdapter(fragment: Fragment) :
fragment.childFragmentManager, FragmentStateAdapter(fragment.childFragmentManager, fragment.viewLifecycleOwner.lifecycle),
fragment.viewLifecycleOwner.lifecycle,
),
TabConfigurationStrategy, 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 override fun getItemCount(): Int = differ.currentList.size
@ -27,8 +33,13 @@ class FavouritesContainerAdapter(fragment: Fragment) : FragmentStateAdapter(
return differ.currentList[position].id 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 { 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) { override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
@ -37,18 +48,18 @@ class FavouritesContainerAdapter(fragment: Fragment) : FragmentStateAdapter(
tab.tag = item 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)) 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 return oldItem.id == newItem.id
} }
override fun areContentsTheSame(oldItem: FavouriteCategory, newItem: FavouriteCategory): Boolean { override fun areContentsTheSame(oldItem: FavouriteTabModel, newItem: FavouriteTabModel): Boolean {
return oldItem.title == newItem.title return oldItem == newItem
} }
} }
} }

@ -1,7 +1,13 @@
package org.koitharu.kotatsu.favourites.ui.container package org.koitharu.kotatsu.favourites.ui.container
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel 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.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.ext.mapItems
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import javax.inject.Inject import javax.inject.Inject
@ -11,4 +17,6 @@ class FavouritesContainerViewModel @Inject constructor(
) : BaseViewModel() { ) : BaseViewModel() {
val categories = favouritesRepository.observeCategories() 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 selectionController: ListSelectionController? = null
private var spanResolver: MangaListSpanResolver? = null private var spanResolver: MangaListSpanResolver? = null
private val spanSizeLookup = SpanSizeLookup() private val spanSizeLookup = SpanSizeLookup()
private val listCommitCallback = Runnable {
spanSizeLookup.invalidateCache()
}
open val isSwipeRefreshEnabled = true open val isSwipeRefreshEnabled = true
protected abstract val viewModel: MangaListViewModel protected abstract val viewModel: MangaListViewModel
@ -166,8 +163,9 @@ abstract class MangaListFragment :
viewModel.onRefresh() viewModel.onRefresh()
} }
private fun onListChanged(list: List<ListModel>) { private suspend fun onListChanged(list: List<ListModel>) {
listAdapter?.setItems(list, listCommitCallback) listAdapter?.emit(list)
spanSizeLookup.invalidateCache()
} }
private fun resolveException(e: Throwable) { private fun resolveException(e: Throwable) {
@ -341,8 +339,7 @@ abstract class MangaListFragment :
} }
override fun getSpanSize(position: Int): Int { override fun getSpanSize(position: Int): Int {
val total = val total = (viewBinding?.recyclerView?.layoutManager as? GridLayoutManager)?.spanCount ?: return 1
(requireViewBinding().recyclerView.layoutManager as? GridLayoutManager)?.spanCount ?: return 1
return when (listAdapter?.getItemViewType(position)) { return when (listAdapter?.getItemViewType(position)) {
ITEM_TYPE_MANGA_GRID -> 1 ITEM_TYPE_MANGA_GRID -> 1
else -> total else -> total

@ -1,17 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" 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"
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 <com.google.android.material.tabs.TabLayout
android:id="@+id/tabs" android:id="@+id/tabs"
@ -20,12 +13,9 @@
app:tabGravity="start" app:tabGravity="start"
app:tabMode="scrollable" /> app:tabMode="scrollable" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2 <androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager" android:id="@+id/pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent" />
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </LinearLayout>

Loading…
Cancel
Save