diff --git a/app/build.gradle b/app/build.gradle index 580140820c..0187c4676e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -143,7 +143,6 @@ dependencies { implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha04' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' - implementation "androidx.viewpager2:viewpager2:1.0.0" implementation 'androidx.webkit:webkit:1.3.0-rc01' final lifecycle_version = '2.3.0-alpha05' @@ -236,6 +235,7 @@ dependencies { implementation 'eu.davidea:flexible-adapter:5.1.0' implementation 'eu.davidea:flexible-adapter-ui:1.0.0' implementation 'com.nononsenseapps:filepicker:2.5.2' + implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0' implementation 'com.github.mthli:Slice:v1.3' implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.carlosesco:DirectionalViewPager:a844dbca0a' @@ -259,7 +259,7 @@ dependencies { implementation "io.github.reactivecircus.flowbinding:flowbinding-appcompat:$flowbinding_version" implementation "io.github.reactivecircus.flowbinding:flowbinding-recyclerview:$flowbinding_version" implementation "io.github.reactivecircus.flowbinding:flowbinding-swiperefreshlayout:$flowbinding_version" - implementation "io.github.reactivecircus.flowbinding:flowbinding-viewpager2:$flowbinding_version" + implementation "io.github.reactivecircus.flowbinding:flowbinding-viewpager:$flowbinding_version" // Licenses final aboutlibraries_version = '8.2.0' diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt index d13efe42e9..27bb231829 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt @@ -1,20 +1,18 @@ package eu.kanade.tachiyomi.ui.library -import android.content.Context -import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Category -import eu.kanade.tachiyomi.databinding.LibraryCategoryBinding +import eu.kanade.tachiyomi.util.view.inflate +import eu.kanade.tachiyomi.widget.RecyclerViewPagerAdapter /** * This adapter stores the categories from the library, used with a ViewPager. + * + * @constructor creates an instance of the adapter. */ -class LibraryAdapter( - private val context: Context, - private val controller: LibraryController -) : RecyclerView.Adapter() { +class LibraryAdapter(private val controller: LibraryController) : RecyclerViewPagerAdapter() { /** * The categories to bind in the adapter. @@ -30,25 +28,45 @@ class LibraryAdapter( private var boundViews = arrayListOf() - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val binding = LibraryCategoryBinding.inflate(LayoutInflater.from(context), parent, false) - binding.root.onCreate(controller) - return ViewHolder(binding) + /** + * Creates a new view for this adapter. + * + * @return a new view. + */ + override fun createView(container: ViewGroup): View { + val view = container.inflate(R.layout.library_category) as LibraryCategoryView + view.onCreate(controller) + return view } - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val view = (holder.itemView as LibraryCategoryView) - view.onBind(categories[position]) + /** + * Binds a view with a position. + * + * @param view the view to bind. + * @param position the position in the adapter. + */ + override fun bindView(view: View, position: Int) { + (view as LibraryCategoryView).onBind(categories[position]) boundViews.add(view) } - override fun onViewRecycled(holder: ViewHolder) { - val view = (holder.itemView as LibraryCategoryView) - view.onRecycle() + /** + * Recycles a view. + * + * @param view the view to recycle. + * @param position the position in the adapter. + */ + override fun recycleView(view: View, position: Int) { + (view as LibraryCategoryView).onRecycle() boundViews.remove(view) } - override fun getItemCount(): Int { + /** + * Returns the number of categories. + * + * @return the number of categories or 0 if the list is null. + */ + override fun getCount(): Int { return categories.size } @@ -58,10 +76,19 @@ class LibraryAdapter( * @param position the position of the element. * @return the title to display. */ - fun getPageTitle(position: Int): CharSequence { + override fun getPageTitle(position: Int): CharSequence { return categories[position].name } + /** + * Returns the position of the view. + */ + override fun getItemPosition(obj: Any): Int { + val view = obj as? LibraryCategoryView ?: return POSITION_NONE + val index = categories.indexOfFirst { it.id == view.category.id } + return if (index == -1) POSITION_NONE else index + } + /** * Called when the view of this adapter is being destroyed. */ @@ -72,6 +99,4 @@ class LibraryAdapter( } } } - - class ViewHolder(binding: LibraryCategoryBinding) : RecyclerView.ViewHolder(binding.root) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index d1b8004dc8..21315cad38 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -15,7 +15,6 @@ import androidx.core.graphics.drawable.DrawableCompat import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeType import com.google.android.material.tabs.TabLayout -import com.google.android.material.tabs.TabLayoutMediator import com.jakewharton.rxrelay.BehaviorRelay import com.jakewharton.rxrelay.PublishRelay import com.tfcporciuncula.flow.Preference @@ -46,7 +45,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.view.clicks import reactivecircus.flowbinding.appcompat.queryTextChanges -import reactivecircus.flowbinding.viewpager2.pageSelections +import reactivecircus.flowbinding.viewpager.pageSelections import rx.Subscription import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -165,8 +164,7 @@ class LibraryController( override fun onViewCreated(view: View) { super.onViewCreated(view) - adapter = LibraryAdapter(activity!!, this) - binding.libraryPager.offscreenPageLimit = 5 + adapter = LibraryAdapter(this) binding.libraryPager.adapter = adapter binding.libraryPager.pageSelections() .onEach { @@ -214,11 +212,7 @@ class LibraryController( override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) { super.onChangeStarted(handler, type) if (type.isEnter) { - activity?.tabs?.let { tabLayout -> - TabLayoutMediator(tabLayout, binding.libraryPager) { tab, position -> - tab.text = adapter?.getPageTitle(position) - }.attach() - } + activity?.tabs?.setupWithViewPager(binding.libraryPager) presenter.subscribeLibrary() } } @@ -339,8 +333,10 @@ class LibraryController( val position = binding.libraryPager.currentItem + adapter.recycle = false binding.libraryPager.adapter = adapter binding.libraryPager.currentItem = position + adapter.recycle = true } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/RecyclerViewPagerAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/RecyclerViewPagerAdapter.kt new file mode 100644 index 0000000000..2e1d51c2f5 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/RecyclerViewPagerAdapter.kt @@ -0,0 +1,34 @@ +package eu.kanade.tachiyomi.widget + +import android.view.View +import android.view.ViewGroup +import com.nightlynexus.viewstatepageradapter.ViewStatePagerAdapter +import java.util.Stack + +abstract class RecyclerViewPagerAdapter : ViewStatePagerAdapter() { + + private val pool = Stack() + + var recycle = true + set(value) { + if (!value) pool.clear() + field = value + } + + protected abstract fun createView(container: ViewGroup): View + + protected abstract fun bindView(view: View, position: Int) + + protected open fun recycleView(view: View, position: Int) {} + + override fun createView(container: ViewGroup, position: Int): View { + val view = if (pool.isNotEmpty()) pool.pop() else createView(container) + bindView(view, position) + return view + } + + override fun destroyView(container: ViewGroup, position: Int, view: View) { + recycleView(view, position) + if (recycle) pool.push(view) + } +} diff --git a/app/src/main/res/layout/library_controller.xml b/app/src/main/res/layout/library_controller.xml index a01e595ec4..75fdb112cb 100644 --- a/app/src/main/res/layout/library_controller.xml +++ b/app/src/main/res/layout/library_controller.xml @@ -39,7 +39,7 @@ tools:text="Search" tools:visibility="visible" /> -