Library views recycling
This commit is contained in:
parent
97454ca162
commit
dfb2487640
@ -27,7 +27,7 @@ abstract class FlexibleViewHolder(view: View,
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun toggleActivation() {
|
fun toggleActivation() {
|
||||||
itemView.isActivated = adapter.isSelected(adapterPosition)
|
itemView.isActivated = adapter.isSelected(adapterPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
import android.support.v4.app.Fragment
|
import android.view.View
|
||||||
import android.support.v4.app.FragmentManager
|
import android.view.ViewGroup
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.ui.base.adapter.SmartFragmentStatePagerAdapter
|
import eu.kanade.tachiyomi.util.inflate
|
||||||
|
import eu.kanade.tachiyomi.widget.RecyclerViewPagerAdapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This adapter stores the categories from the library, used with a ViewPager.
|
* This adapter stores the categories from the library, used with a ViewPager.
|
||||||
*
|
*
|
||||||
* @param fm the fragment manager.
|
|
||||||
* @constructor creates an instance of the adapter.
|
* @constructor creates an instance of the adapter.
|
||||||
*/
|
*/
|
||||||
class LibraryAdapter(fm: FragmentManager) : SmartFragmentStatePagerAdapter(fm) {
|
class LibraryAdapter(private val fragment: LibraryFragment) : RecyclerViewPagerAdapter() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The categories to bind in the adapter.
|
* The categories to bind in the adapter.
|
||||||
*/
|
*/
|
||||||
var categories: List<Category>? = null
|
var categories: List<Category> = emptyList()
|
||||||
// This setter helps to not refresh the adapter if the reference to the list doesn't change.
|
// This setter helps to not refresh the adapter if the reference to the list doesn't change.
|
||||||
set(value) {
|
set(value) {
|
||||||
if (field !== value) {
|
if (field !== value) {
|
||||||
@ -26,13 +27,34 @@ class LibraryAdapter(fm: FragmentManager) : SmartFragmentStatePagerAdapter(fm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new fragment for the given position when it's called.
|
* Creates a new view for this adapter.
|
||||||
*
|
*
|
||||||
* @param position the position to instantiate.
|
* @return a new view.
|
||||||
* @return a fragment for the given position.
|
|
||||||
*/
|
*/
|
||||||
override fun getItem(position: Int): Fragment {
|
override fun createView(container: ViewGroup): View {
|
||||||
return LibraryCategoryFragment.newInstance(position)
|
val view = container.inflate(R.layout.item_library_category) as LibraryCategoryFragment
|
||||||
|
view.onCreate(fragment)
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 LibraryCategoryFragment).onBind(categories[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 LibraryCategoryFragment).onRecycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +63,7 @@ class LibraryAdapter(fm: FragmentManager) : SmartFragmentStatePagerAdapter(fm) {
|
|||||||
* @return the number of categories or 0 if the list is null.
|
* @return the number of categories or 0 if the list is null.
|
||||||
*/
|
*/
|
||||||
override fun getCount(): Int {
|
override fun getCount(): Int {
|
||||||
return categories?.size ?: 0
|
return categories.size
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,28 +73,7 @@ class LibraryAdapter(fm: FragmentManager) : SmartFragmentStatePagerAdapter(fm) {
|
|||||||
* @return the title to display.
|
* @return the title to display.
|
||||||
*/
|
*/
|
||||||
override fun getPageTitle(position: Int): CharSequence {
|
override fun getPageTitle(position: Int): CharSequence {
|
||||||
return categories!![position].name
|
return categories[position].name
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to enable or disable the action mode (multiple selection) for all the instantiated
|
|
||||||
* fragments.
|
|
||||||
*
|
|
||||||
* @param mode the mode to set.
|
|
||||||
*/
|
|
||||||
fun setSelectionMode(mode: Int) {
|
|
||||||
for (fragment in getRegisteredFragments()) {
|
|
||||||
(fragment as LibraryCategoryFragment).setSelectionMode(mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies the adapters in all the registered fragments to refresh their content.
|
|
||||||
*/
|
|
||||||
fun refreshRegisteredAdapters() {
|
|
||||||
for (fragment in getRegisteredFragments()) {
|
|
||||||
(fragment as LibraryCategoryFragment).adapter.notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -84,7 +84,7 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryFragment) :
|
|||||||
* @return a new view holder for a manga.
|
* @return a new view holder for a manga.
|
||||||
*/
|
*/
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LibraryHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LibraryHolder {
|
||||||
//depending on preferences, display a list or display a grid
|
// Depending on preferences, display a list or display a grid
|
||||||
if (parent is AutofitRecyclerView) {
|
if (parent is AutofitRecyclerView) {
|
||||||
val view = parent.inflate(R.layout.item_catalogue_grid).apply {
|
val view = parent.inflate(R.layout.item_catalogue_grid).apply {
|
||||||
val coverHeight = parent.itemWidth / 3 * 4
|
val coverHeight = parent.itemWidth / 3 * 4
|
||||||
@ -96,7 +96,6 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryFragment) :
|
|||||||
val view = parent.inflate(R.layout.item_library_list)
|
val view = parent.inflate(R.layout.item_library_list)
|
||||||
return LibraryListHolder(view, this, fragment)
|
return LibraryListHolder(view, this, fragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,8 +108,17 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryFragment) :
|
|||||||
val manga = getItem(position)
|
val manga = getItem(position)
|
||||||
|
|
||||||
holder.onSetValues(manga)
|
holder.onSetValues(manga)
|
||||||
//When user scrolls this bind the correct selection status
|
// When user scrolls this bind the correct selection status
|
||||||
holder.itemView.isActivated = isSelected(position)
|
holder.itemView.isActivated = isSelected(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the position in the adapter for the given manga.
|
||||||
|
*
|
||||||
|
* @param manga the manga to find.
|
||||||
|
*/
|
||||||
|
fun indexOf(manga: Manga): Int {
|
||||||
|
return mangas.orEmpty().indexOfFirst { it.id == manga.id }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.content.Context
|
||||||
import android.support.v7.widget.LinearLayoutManager
|
import android.support.v7.widget.LinearLayoutManager
|
||||||
import android.support.v7.widget.RecyclerView
|
import android.support.v7.widget.RecyclerView
|
||||||
import android.view.LayoutInflater
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.widget.FrameLayout
|
||||||
import android.view.ViewGroup
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
|
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment
|
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaActivity
|
import eu.kanade.tachiyomi.ui.manga.MangaActivity
|
||||||
import eu.kanade.tachiyomi.util.inflate
|
import eu.kanade.tachiyomi.util.inflate
|
||||||
import eu.kanade.tachiyomi.util.toast
|
import eu.kanade.tachiyomi.util.toast
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
import kotlinx.android.synthetic.main.fragment_library_category.*
|
import kotlinx.android.synthetic.main.item_library_category.view.*
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
@ -26,23 +25,33 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
* Fragment containing the library manga for a certain category.
|
* Fragment containing the library manga for a certain category.
|
||||||
* Uses R.layout.fragment_library_category.
|
* Uses R.layout.fragment_library_category.
|
||||||
*/
|
*/
|
||||||
class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemClickListener {
|
class LibraryCategoryFragment @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
|
||||||
|
: FrameLayout(context, attrs), FlexibleViewHolder.OnListItemClickListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preferences.
|
* Preferences.
|
||||||
*/
|
*/
|
||||||
val preferences: PreferencesHelper by injectLazy()
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fragment containing this view.
|
||||||
|
*/
|
||||||
|
private lateinit var fragment: LibraryFragment
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Category for this view.
|
||||||
|
*/
|
||||||
|
private lateinit var category: Category
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recycler view of the list of manga.
|
||||||
|
*/
|
||||||
|
private lateinit var recycler: RecyclerView
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter to hold the manga in this category.
|
* Adapter to hold the manga in this category.
|
||||||
*/
|
*/
|
||||||
lateinit var adapter: LibraryCategoryAdapter
|
private lateinit var adapter: LibraryCategoryAdapter
|
||||||
private set
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Position in the adapter from [LibraryAdapter].
|
|
||||||
*/
|
|
||||||
private var position: Int = 0
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscription for the library manga.
|
* Subscription for the library manga.
|
||||||
@ -54,69 +63,30 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||||||
*/
|
*/
|
||||||
private var searchSubscription: Subscription? = null
|
private var searchSubscription: Subscription? = null
|
||||||
|
|
||||||
companion object {
|
/**
|
||||||
/**
|
* Subscription of the library selections.
|
||||||
* Key to save and restore [position] from a [Bundle].
|
*/
|
||||||
*/
|
private var selectionSubscription: Subscription? = null
|
||||||
const val POSITION_KEY = "position_key"
|
|
||||||
|
|
||||||
/**
|
fun onCreate(fragment: LibraryFragment) {
|
||||||
* Creates a new instance of this class.
|
this.fragment = fragment
|
||||||
*
|
|
||||||
* @param position the position in the adapter from [LibraryAdapter].
|
|
||||||
* @return a new instance of [LibraryCategoryFragment].
|
|
||||||
*/
|
|
||||||
fun newInstance(position: Int): LibraryCategoryFragment {
|
|
||||||
val fragment = LibraryCategoryFragment()
|
|
||||||
fragment.position = position
|
|
||||||
|
|
||||||
return fragment
|
recycler = if (preferences.libraryAsList().getOrDefault()) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?): View? {
|
|
||||||
return inflater.inflate(R.layout.fragment_library_category, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
adapter = LibraryCategoryAdapter(this)
|
|
||||||
|
|
||||||
val recycler = if (preferences.libraryAsList().getOrDefault()) {
|
|
||||||
(swipe_refresh.inflate(R.layout.library_list_recycler) as RecyclerView).apply {
|
(swipe_refresh.inflate(R.layout.library_list_recycler) as RecyclerView).apply {
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = LinearLayoutManager(context)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(swipe_refresh.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply {
|
(swipe_refresh.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply {
|
||||||
spanCount = libraryFragment.mangaPerRow
|
spanCount = fragment.mangaPerRow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This crashes when opening a manga after changing categories, but then viewholders aren't
|
adapter = LibraryCategoryAdapter(this)
|
||||||
// recycled between pages. It may be fixed if this fragment is replaced with a custom view.
|
|
||||||
//(recycler.layoutManager as LinearLayoutManager).recycleChildrenOnDetach = true
|
|
||||||
//recycler.recycledViewPool = libraryFragment.pool
|
|
||||||
recycler.setHasFixedSize(true)
|
recycler.setHasFixedSize(true)
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
swipe_refresh.addView(recycler)
|
swipe_refresh.addView(recycler)
|
||||||
|
|
||||||
if (libraryFragment.actionMode != null) {
|
|
||||||
setSelectionMode(FlexibleAdapter.MODE_MULTI)
|
|
||||||
}
|
|
||||||
|
|
||||||
searchSubscription = libraryPresenter.searchSubject.subscribe { text ->
|
|
||||||
adapter.searchText = text
|
|
||||||
adapter.updateDataSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (savedState != null) {
|
|
||||||
position = savedState.getInt(POSITION_KEY)
|
|
||||||
adapter.onRestoreInstanceState(savedState)
|
|
||||||
|
|
||||||
if (adapter.mode == FlexibleAdapter.MODE_SINGLE) {
|
|
||||||
adapter.clearSelection()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
override fun onScrollStateChanged(recycler: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recycler: RecyclerView, newState: Int) {
|
||||||
// Disable swipe refresh when view is not at the top
|
// Disable swipe refresh when view is not at the top
|
||||||
@ -130,36 +100,47 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||||||
swipe_refresh.setDistanceToTriggerSync((2 * 64 * resources.displayMetrics.density).toInt())
|
swipe_refresh.setDistanceToTriggerSync((2 * 64 * resources.displayMetrics.density).toInt())
|
||||||
swipe_refresh.setOnRefreshListener {
|
swipe_refresh.setOnRefreshListener {
|
||||||
if (!LibraryUpdateService.isRunning(context)) {
|
if (!LibraryUpdateService.isRunning(context)) {
|
||||||
libraryPresenter.categories.getOrNull(position)?.let {
|
LibraryUpdateService.start(context, true, category)
|
||||||
LibraryUpdateService.start(context, true, it)
|
context.toast(R.string.updating_category)
|
||||||
context.toast(R.string.updating_category)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// It can be a very long operation, so we disable swipe refresh and show a toast.
|
// It can be a very long operation, so we disable swipe refresh and show a toast.
|
||||||
swipe_refresh.isRefreshing = false
|
swipe_refresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
fun onBind(category: Category) {
|
||||||
searchSubscription?.unsubscribe()
|
this.category = category
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
val presenter = fragment.presenter
|
||||||
super.onResume()
|
|
||||||
libraryMangaSubscription = libraryPresenter.libraryMangaSubject
|
searchSubscription = presenter.searchSubject.subscribe { text ->
|
||||||
|
adapter.searchText = text
|
||||||
|
adapter.updateDataSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.mode = if (presenter.selectedMangas.isNotEmpty()) {
|
||||||
|
FlexibleAdapter.MODE_MULTI
|
||||||
|
} else {
|
||||||
|
FlexibleAdapter.MODE_SINGLE
|
||||||
|
}
|
||||||
|
|
||||||
|
libraryMangaSubscription = presenter.libraryMangaSubject
|
||||||
.subscribe { onNextLibraryManga(it) }
|
.subscribe { onNextLibraryManga(it) }
|
||||||
|
|
||||||
|
selectionSubscription = presenter.selectionSubject
|
||||||
|
.subscribe { onSelectionChanged(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
fun onRecycle() {
|
||||||
|
adapter.setItems(emptyList())
|
||||||
|
adapter.clearSelection()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
searchSubscription?.unsubscribe()
|
||||||
libraryMangaSubscription?.unsubscribe()
|
libraryMangaSubscription?.unsubscribe()
|
||||||
super.onPause()
|
selectionSubscription?.unsubscribe()
|
||||||
}
|
super.onDetachedFromWindow()
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
|
||||||
outState.putInt(POSITION_KEY, position)
|
|
||||||
adapter.onSaveInstanceState(outState)
|
|
||||||
super.onSaveInstanceState(outState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,17 +150,61 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||||||
* @param event the event received.
|
* @param event the event received.
|
||||||
*/
|
*/
|
||||||
fun onNextLibraryManga(event: LibraryMangaEvent) {
|
fun onNextLibraryManga(event: LibraryMangaEvent) {
|
||||||
// Get the categories from the parent fragment.
|
|
||||||
val categories = libraryFragment.adapter.categories ?: return
|
|
||||||
|
|
||||||
// When a category is deleted, the index can be greater than the number of categories.
|
|
||||||
if (position >= categories.size) return
|
|
||||||
|
|
||||||
// Get the manga list for this category.
|
// Get the manga list for this category.
|
||||||
val mangaForCategory = event.getMangaForCategory(categories[position]) ?: emptyList()
|
val mangaForCategory = event.getMangaForCategory(category).orEmpty()
|
||||||
|
|
||||||
// Update the category with its manga.
|
// Update the category with its manga.
|
||||||
adapter.setItems(mangaForCategory)
|
adapter.setItems(mangaForCategory)
|
||||||
|
|
||||||
|
if (adapter.mode == FlexibleAdapter.MODE_MULTI) {
|
||||||
|
fragment.presenter.selectedMangas.forEach { manga ->
|
||||||
|
val position = adapter.indexOf(manga)
|
||||||
|
if (position != -1 && !adapter.isSelected(position)) {
|
||||||
|
adapter.toggleSelection(position)
|
||||||
|
(recycler.findViewHolderForItemId(manga.id!!) as? LibraryHolder)?.toggleActivation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to [LibrarySelectionEvent]. When an event is received, it updates the selection
|
||||||
|
* depending on the type of event received.
|
||||||
|
*
|
||||||
|
* @param event the selection event received.
|
||||||
|
*/
|
||||||
|
private fun onSelectionChanged(event: LibrarySelectionEvent) {
|
||||||
|
when (event) {
|
||||||
|
is LibrarySelectionEvent.Selected -> {
|
||||||
|
if (adapter.mode != FlexibleAdapter.MODE_MULTI) {
|
||||||
|
adapter.mode = FlexibleAdapter.MODE_MULTI
|
||||||
|
}
|
||||||
|
findAndToggleSelection(event.manga)
|
||||||
|
}
|
||||||
|
is LibrarySelectionEvent.Unselected -> {
|
||||||
|
findAndToggleSelection(event.manga)
|
||||||
|
if (fragment.presenter.selectedMangas.isEmpty()) {
|
||||||
|
adapter.mode = FlexibleAdapter.MODE_SINGLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is LibrarySelectionEvent.Cleared -> {
|
||||||
|
adapter.mode = FlexibleAdapter.MODE_SINGLE
|
||||||
|
adapter.clearSelection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the selection for the given manga and updates the view if needed.
|
||||||
|
*
|
||||||
|
* @param manga the manga to toggle.
|
||||||
|
*/
|
||||||
|
private fun findAndToggleSelection(manga: Manga) {
|
||||||
|
val position = adapter.indexOf(manga)
|
||||||
|
if (position != -1) {
|
||||||
|
adapter.toggleSelection(position)
|
||||||
|
(recycler.findViewHolderForItemId(manga.id!!) as? LibraryHolder)?.toggleActivation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -191,7 +216,7 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||||||
override fun onListItemClick(position: Int): Boolean {
|
override fun onListItemClick(position: Int): Boolean {
|
||||||
// If the action mode is created and the position is valid, toggle the selection.
|
// If the action mode is created and the position is valid, toggle the selection.
|
||||||
val item = adapter.getItem(position) ?: return false
|
val item = adapter.getItem(position) ?: return false
|
||||||
if (libraryFragment.actionMode != null) {
|
if (adapter.mode == FlexibleAdapter.MODE_MULTI) {
|
||||||
toggleSelection(position)
|
toggleSelection(position)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
@ -206,7 +231,7 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||||||
* @param position the position of the element clicked.
|
* @param position the position of the element clicked.
|
||||||
*/
|
*/
|
||||||
override fun onListItemLongClick(position: Int) {
|
override fun onListItemLongClick(position: Int) {
|
||||||
libraryFragment.createActionModeIfNeeded()
|
fragment.createActionModeIfNeeded()
|
||||||
toggleSelection(position)
|
toggleSelection(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,63 +242,24 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||||||
*/
|
*/
|
||||||
private fun openManga(manga: Manga) {
|
private fun openManga(manga: Manga) {
|
||||||
// Notify the presenter a manga is being opened.
|
// Notify the presenter a manga is being opened.
|
||||||
libraryPresenter.onOpenManga()
|
fragment.presenter.onOpenManga()
|
||||||
|
|
||||||
// Create a new activity with the manga.
|
// Create a new activity with the manga.
|
||||||
val intent = MangaActivity.newIntent(context, manga)
|
val intent = MangaActivity.newIntent(context, manga)
|
||||||
startActivity(intent)
|
fragment.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the selection for a manga.
|
* Tells the presenter to toggle the selection for the given position.
|
||||||
*
|
*
|
||||||
* @param position the position to toggle.
|
* @param position the position to toggle.
|
||||||
*/
|
*/
|
||||||
private fun toggleSelection(position: Int) {
|
private fun toggleSelection(position: Int) {
|
||||||
val library = libraryFragment
|
val manga = adapter.getItem(position) ?: return
|
||||||
|
|
||||||
// Toggle the selection.
|
fragment.presenter.setSelection(manga, !adapter.isSelected(position))
|
||||||
adapter.toggleSelection(position, false)
|
fragment.invalidateActionMode()
|
||||||
|
|
||||||
// Notify the selection to the presenter.
|
|
||||||
library.presenter.setSelection(adapter.getItem(position), adapter.isSelected(position))
|
|
||||||
|
|
||||||
// Get the selected count.
|
|
||||||
val count = library.presenter.selectedMangas.size
|
|
||||||
if (count == 0) {
|
|
||||||
// Destroy action mode if there are no items selected.
|
|
||||||
library.destroyActionModeIfNeeded()
|
|
||||||
} else {
|
|
||||||
// Update action mode with the new selection.
|
|
||||||
library.setContextTitle(count)
|
|
||||||
library.setVisibilityOfCoverEdit(count)
|
|
||||||
library.invalidateActionMode()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the mode for the adapter.
|
|
||||||
*
|
|
||||||
* @param mode the mode to set. It should be MODE_SINGLE or MODE_MULTI.
|
|
||||||
*/
|
|
||||||
fun setSelectionMode(mode: Int) {
|
|
||||||
adapter.mode = mode
|
|
||||||
if (mode == FlexibleAdapter.MODE_SINGLE) {
|
|
||||||
adapter.clearSelection()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Property to get the library fragment.
|
|
||||||
*/
|
|
||||||
private val libraryFragment: LibraryFragment
|
|
||||||
get() = parentFragment as LibraryFragment
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Property to get the library presenter.
|
|
||||||
*/
|
|
||||||
private val libraryPresenter: LibraryPresenter
|
|
||||||
get() = libraryFragment.presenter
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import android.support.v7.widget.SearchView
|
|||||||
import android.view.*
|
import android.view.*
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.f2prateek.rx.preferences.Preference
|
import com.f2prateek.rx.preferences.Preference
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
@ -26,6 +25,7 @@ import kotlinx.android.synthetic.main.activity_main.*
|
|||||||
import kotlinx.android.synthetic.main.fragment_library.*
|
import kotlinx.android.synthetic.main.fragment_library.*
|
||||||
import nucleus.factory.RequiresPresenter
|
import nucleus.factory.RequiresPresenter
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@ -66,8 +66,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
/**
|
/**
|
||||||
* Action mode for manga selection.
|
* Action mode for manga selection.
|
||||||
*/
|
*/
|
||||||
var actionMode: ActionMode? = null
|
private var actionMode: ActionMode? = null
|
||||||
private set
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selected manga for editing its cover.
|
* Selected manga for editing its cover.
|
||||||
@ -91,14 +90,8 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pool to share view holders between all the registered categories (fragments).
|
* Subscription for the number of manga per row.
|
||||||
*/
|
*/
|
||||||
// TODO find out why this breaks sometimes
|
|
||||||
// var pool = RecyclerView.RecycledViewPool().apply { setMaxRecycledViews(0, 20) }
|
|
||||||
// private set(value) {
|
|
||||||
// field = value.apply { setMaxRecycledViews(0, 20) }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private var numColumnsSubscription: Subscription? = null
|
private var numColumnsSubscription: Subscription? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -141,7 +134,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
override fun onViewCreated(view: View, savedState: Bundle?) {
|
||||||
setToolbarTitle(getString(R.string.label_library))
|
setToolbarTitle(getString(R.string.label_library))
|
||||||
|
|
||||||
adapter = LibraryAdapter(childFragmentManager)
|
adapter = LibraryAdapter(this)
|
||||||
view_pager.adapter = adapter
|
view_pager.adapter = adapter
|
||||||
view_pager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
|
view_pager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
|
||||||
override fun onPageSelected(position: Int) {
|
override fun onPageSelected(position: Int) {
|
||||||
@ -154,6 +147,9 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
activeCategory = savedState.getInt(CATEGORY_KEY)
|
activeCategory = savedState.getInt(CATEGORY_KEY)
|
||||||
query = savedState.getString(QUERY_KEY)
|
query = savedState.getString(QUERY_KEY)
|
||||||
presenter.searchSubject.onNext(query)
|
presenter.searchSubject.onNext(query)
|
||||||
|
if (presenter.selectedMangas.isNotEmpty()) {
|
||||||
|
createActionModeIfNeeded()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
activeCategory = preferences.lastUsedCategory().getOrDefault()
|
activeCategory = preferences.lastUsedCategory().getOrDefault()
|
||||||
}
|
}
|
||||||
@ -261,8 +257,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
* Applies filter change
|
* Applies filter change
|
||||||
*/
|
*/
|
||||||
private fun onFilterCheckboxChanged() {
|
private fun onFilterCheckboxChanged() {
|
||||||
presenter.updateLibrary()
|
presenter.resubscribeLibrary()
|
||||||
adapter.refreshRegisteredAdapters()
|
|
||||||
activity.supportInvalidateOptionsMenu()
|
activity.supportInvalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,11 +273,11 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
* Reattaches the adapter to the view pager to recreate fragments
|
* Reattaches the adapter to the view pager to recreate fragments
|
||||||
*/
|
*/
|
||||||
private fun reattachAdapter() {
|
private fun reattachAdapter() {
|
||||||
// pool.clear()
|
|
||||||
// pool = RecyclerView.RecycledViewPool()
|
|
||||||
val position = view_pager.currentItem
|
val position = view_pager.currentItem
|
||||||
|
adapter.recycle = false
|
||||||
view_pager.adapter = adapter
|
view_pager.adapter = adapter
|
||||||
view_pager.currentItem = position
|
view_pager.currentItem = position
|
||||||
|
adapter.recycle = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -323,7 +318,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
R.string.information_empty_library, R.drawable.ic_book_black_128dp)
|
R.string.information_empty_library, R.drawable.ic_book_black_128dp)
|
||||||
|
|
||||||
// Get the current active category.
|
// Get the current active category.
|
||||||
val activeCat = if (adapter.categories != null) view_pager.currentItem else activeCategory
|
val activeCat = if (adapter.categories.isNotEmpty()) view_pager.currentItem else activeCategory
|
||||||
|
|
||||||
// Set the categories
|
// Set the categories
|
||||||
adapter.categories = categories
|
adapter.categories = categories
|
||||||
@ -339,31 +334,42 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the title of the action mode.
|
* Creates the action mode if it's not created already.
|
||||||
*
|
|
||||||
* @param count the number of items selected.
|
|
||||||
*/
|
*/
|
||||||
fun setContextTitle(count: Int) {
|
fun createActionModeIfNeeded() {
|
||||||
actionMode?.title = getString(R.string.label_selected, count)
|
if (actionMode == null) {
|
||||||
|
actionMode = activity.startSupportActionMode(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the visibility of the edit cover item.
|
* Destroys the action mode.
|
||||||
*
|
|
||||||
* @param count the number of items selected.
|
|
||||||
*/
|
*/
|
||||||
fun setVisibilityOfCoverEdit(count: Int) {
|
fun destroyActionModeIfNeeded() {
|
||||||
// If count = 1 display edit button
|
actionMode?.finish()
|
||||||
actionMode?.menu?.findItem(R.id.action_edit_cover)?.isVisible = count == 1
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the action mode, forcing it to refresh its content.
|
||||||
|
*/
|
||||||
|
fun invalidateActionMode() {
|
||||||
|
actionMode?.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||||
mode.menuInflater.inflate(R.menu.library_selection, menu)
|
mode.menuInflater.inflate(R.menu.library_selection, menu)
|
||||||
adapter.setSelectionMode(FlexibleAdapter.MODE_MULTI)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||||
|
val count = presenter.selectedMangas.size
|
||||||
|
if (count == 0) {
|
||||||
|
// Destroy action mode if there are no items selected.
|
||||||
|
destroyActionModeIfNeeded()
|
||||||
|
} else {
|
||||||
|
mode.title = getString(R.string.label_selected, count)
|
||||||
|
menu.findItem(R.id.action_edit_cover)?.isVisible = count == 1
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,18 +387,10 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyActionMode(mode: ActionMode) {
|
override fun onDestroyActionMode(mode: ActionMode) {
|
||||||
adapter.setSelectionMode(FlexibleAdapter.MODE_SINGLE)
|
presenter.clearSelections()
|
||||||
presenter.selectedMangas.clear()
|
|
||||||
actionMode = null
|
actionMode = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys the action mode.
|
|
||||||
*/
|
|
||||||
fun destroyActionModeIfNeeded() {
|
|
||||||
actionMode?.finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the cover for the selected manga.
|
* Changes the cover for the selected manga.
|
||||||
*
|
*
|
||||||
@ -422,14 +420,14 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
context.contentResolver.openInputStream(data.data).use {
|
context.contentResolver.openInputStream(data.data).use {
|
||||||
// Update cover to selected file, show error if something went wrong
|
// Update cover to selected file, show error if something went wrong
|
||||||
if (presenter.editCoverWithStream(it, manga)) {
|
if (presenter.editCoverWithStream(it, manga)) {
|
||||||
adapter.refreshRegisteredAdapters()
|
// TODO refresh cover
|
||||||
} else {
|
} else {
|
||||||
context.toast(R.string.notification_manga_update_failed)
|
context.toast(R.string.notification_manga_update_failed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (error: IOException) {
|
||||||
context.toast(R.string.notification_manga_update_failed)
|
context.toast(R.string.notification_manga_update_failed)
|
||||||
e.printStackTrace()
|
Timber.e(error, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,20 +474,4 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the action mode if it's not created already.
|
|
||||||
*/
|
|
||||||
fun createActionModeIfNeeded() {
|
|
||||||
if (actionMode == null) {
|
|
||||||
actionMode = activity.startSupportActionMode(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates the action mode, forcing it to refresh its content.
|
|
||||||
*/
|
|
||||||
fun invalidateActionMode() {
|
|
||||||
actionMode?.invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import rx.Observable
|
|||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import rx.subjects.BehaviorSubject
|
import rx.subjects.BehaviorSubject
|
||||||
|
import rx.subjects.PublishSubject
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -29,22 +30,27 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|||||||
/**
|
/**
|
||||||
* Categories of the library.
|
* Categories of the library.
|
||||||
*/
|
*/
|
||||||
lateinit var categories: List<Category>
|
var categories: List<Category> = emptyList()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currently selected manga.
|
* Currently selected manga.
|
||||||
*/
|
*/
|
||||||
var selectedMangas = mutableListOf<Manga>()
|
val selectedMangas = mutableListOf<Manga>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search query of the library.
|
* Search query of the library.
|
||||||
*/
|
*/
|
||||||
val searchSubject: BehaviorSubject<String> = BehaviorSubject.create<String>()
|
val searchSubject: BehaviorSubject<String> = BehaviorSubject.create()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subject to notify the library's viewpager for updates.
|
* Subject to notify the library's viewpager for updates.
|
||||||
*/
|
*/
|
||||||
val libraryMangaSubject: BehaviorSubject<LibraryMangaEvent> = BehaviorSubject.create<LibraryMangaEvent>()
|
val libraryMangaSubject: BehaviorSubject<LibraryMangaEvent> = BehaviorSubject.create()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject to notify the UI of selection updates.
|
||||||
|
*/
|
||||||
|
val selectionSubject: PublishSubject<LibrarySelectionEvent> = PublishSubject.create()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database.
|
* Database.
|
||||||
@ -149,7 +155,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|||||||
/**
|
/**
|
||||||
* Resubscribes to library.
|
* Resubscribes to library.
|
||||||
*/
|
*/
|
||||||
fun updateLibrary() {
|
fun resubscribeLibrary() {
|
||||||
start(GET_LIBRARY)
|
start(GET_LIBRARY)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,11 +225,21 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|||||||
fun setSelection(manga: Manga, selected: Boolean) {
|
fun setSelection(manga: Manga, selected: Boolean) {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selectedMangas.add(manga)
|
selectedMangas.add(manga)
|
||||||
|
selectionSubject.onNext(LibrarySelectionEvent.Selected(manga))
|
||||||
} else {
|
} else {
|
||||||
selectedMangas.remove(manga)
|
selectedMangas.remove(manga)
|
||||||
|
selectionSubject.onNext(LibrarySelectionEvent.Unselected(manga))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all the manga selections and notifies the UI.
|
||||||
|
*/
|
||||||
|
fun clearSelections() {
|
||||||
|
selectedMangas.clear()
|
||||||
|
selectionSubject.onNext(LibrarySelectionEvent.Cleared())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the common categories for the given list of manga.
|
* Returns the common categories for the given list of manga.
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
|
||||||
|
sealed class LibrarySelectionEvent {
|
||||||
|
|
||||||
|
class Selected(val manga: Manga) : LibrarySelectionEvent()
|
||||||
|
class Unselected(val manga: Manga) : LibrarySelectionEvent()
|
||||||
|
class Cleared() : LibrarySelectionEvent()
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package eu.kanade.tachiyomi.widget
|
||||||
|
|
||||||
|
import android.support.v4.view.PagerAdapter
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
abstract class RecyclerViewPagerAdapter : PagerAdapter() {
|
||||||
|
|
||||||
|
private val pool = Stack<View>()
|
||||||
|
|
||||||
|
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 instantiateItem(container: ViewGroup, position: Int): Any {
|
||||||
|
val view = if (pool.isNotEmpty()) pool.pop() else createView(container)
|
||||||
|
bindView(view, position)
|
||||||
|
container.addView(view)
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun destroyItem(container: ViewGroup, position: Int, obj: Any) {
|
||||||
|
val view = obj as View
|
||||||
|
recycleView(view, position)
|
||||||
|
container.removeView(view)
|
||||||
|
if (recycle) pool.push(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isViewFromObject(view: View, obj: Any): Boolean {
|
||||||
|
return view === obj
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
app/src/main/res/layout/item_library_category.xml
Normal file
14
app/src/main/res/layout/item_library_category.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<eu.kanade.tachiyomi.ui.library.LibraryCategoryFragment
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<android.support.v4.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/swipe_refresh"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
</android.support.v4.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
</eu.kanade.tachiyomi.ui.library.LibraryCategoryFragment>
|
Loading…
Reference in New Issue
Block a user