mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-28 09:15:12 +03:00
Dynamic recyclerview inflation for the library view and better swap handling
This commit is contained in:
parent
fbd2235a51
commit
e95fcf6172
9 changed files with 99 additions and 158 deletions
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.library
|
|||
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentManager
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.ui.base.adapter.SmartFragmentStatePagerAdapter
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import kotlinx.android.synthetic.main.fragment_library_category.*
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import kotlinx.android.synthetic.main.item_catalogue_grid.view.*
|
||||
import java.util.*
|
||||
|
||||
|
@ -85,15 +85,16 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryFragment) :
|
|||
*/
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LibraryHolder {
|
||||
//depending on preferences, display a list or display a grid
|
||||
if (parent.id == R.id.library_list) {
|
||||
val view = parent.inflate(R.layout.item_library_list)
|
||||
return LibraryListHolder(view, this, fragment)
|
||||
} else {
|
||||
if (parent is AutofitRecyclerView) {
|
||||
val view = parent.inflate(R.layout.item_catalogue_grid).apply {
|
||||
val coverHeight = parent.itemWidth / 3 * 4
|
||||
card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
|
||||
gradient.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM)
|
||||
}
|
||||
return LibraryGridHolder(view, this, fragment)
|
||||
} else {
|
||||
val view = parent.inflate(R.layout.item_library_list)
|
||||
return LibraryListHolder(view, this, fragment)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -112,10 +113,4 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryFragment) :
|
|||
holder.itemView.isActivated = isSelected(position)
|
||||
}
|
||||
|
||||
/**
|
||||
* Property to return the height for the covers based on the width to keep an aspect ratio.
|
||||
*/
|
||||
val coverHeight: Int
|
||||
get() = fragment.recycler.itemWidth / 3 * 4
|
||||
|
||||
}
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.support.v7.widget.GridLayoutManager
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AnimationUtils
|
||||
import com.f2prateek.rx.preferences.Preference
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
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.util.inflate
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import kotlinx.android.synthetic.main.fragment_library_category.*
|
||||
import rx.Subscription
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
@ -50,26 +49,11 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||
*/
|
||||
private var libraryMangaSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Subscription of the number of manga per row.
|
||||
*/
|
||||
private var numColumnsSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* subscription to view toggle
|
||||
*/
|
||||
private var toggleViewSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Subscription of the library search.
|
||||
*/
|
||||
private var searchSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* display mode
|
||||
*/
|
||||
private var displayAsList: Boolean = false
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Key to save and restore [position] from a [Bundle].
|
||||
|
@ -97,45 +81,31 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
||||
adapter = LibraryCategoryAdapter(this)
|
||||
|
||||
//set up grid
|
||||
recycler.setHasFixedSize(true)
|
||||
(recycler.layoutManager as GridLayoutManager).recycleChildrenOnDetach = true
|
||||
recycler.recycledViewPool = libraryFragment.pool
|
||||
recycler.adapter = adapter
|
||||
val recycler = if (preferences.libraryAsList().getOrDefault()) {
|
||||
(swipe_refresh.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply {
|
||||
spanCount = libraryFragment.mangaPerRow
|
||||
}
|
||||
} else {
|
||||
(swipe_refresh.inflate(R.layout.library_list_recycler) as RecyclerView).apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
}
|
||||
|
||||
//set up list
|
||||
library_list.setHasFixedSize(true)
|
||||
library_list.layoutManager = LinearLayoutManager(activity)
|
||||
library_list.recycledViewPool = libraryFragment.pool
|
||||
(library_list.layoutManager as LinearLayoutManager).recycleChildrenOnDetach = true
|
||||
library_list.adapter = adapter
|
||||
(recycler.layoutManager as LinearLayoutManager).recycleChildrenOnDetach = true
|
||||
recycler.recycledViewPool = libraryFragment.pool
|
||||
recycler.setHasFixedSize(true)
|
||||
recycler.adapter = adapter
|
||||
swipe_refresh.addView(recycler)
|
||||
|
||||
if (libraryFragment.actionMode != null) {
|
||||
setSelectionMode(FlexibleAdapter.MODE_MULTI)
|
||||
}
|
||||
|
||||
numColumnsSubscription = getColumnsPreferenceForCurrentOrientation().asObservable()
|
||||
.doOnNext { recycler.spanCount = it }
|
||||
.skip(1)
|
||||
// Set again the adapter to recalculate the covers height
|
||||
.subscribe { recycler.adapter = adapter }
|
||||
|
||||
searchSubscription = libraryPresenter.searchSubject.subscribe { text ->
|
||||
adapter.searchText = text
|
||||
adapter.updateDataSet()
|
||||
}
|
||||
|
||||
toggleViewSubscription = preferences.libraryAsList().asObservable()
|
||||
.subscribe { onViewModeChange(it) }
|
||||
|
||||
if (libraryPresenter.displayAsList != displayAsList) {
|
||||
library_switcher.showNext()
|
||||
displayAsList = libraryPresenter.displayAsList
|
||||
}
|
||||
|
||||
library_switcher.inAnimation = AnimationUtils.loadAnimation(activity, android.R.anim.fade_in)
|
||||
library_switcher.outAnimation = AnimationUtils.loadAnimation(activity, android.R.anim.fade_out)
|
||||
|
||||
if (savedState != null) {
|
||||
position = savedState.getInt(POSITION_KEY)
|
||||
adapter.onRestoreInstanceState(savedState)
|
||||
|
@ -157,9 +127,9 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||
// Double the distance required to trigger sync
|
||||
swipe_refresh.setDistanceToTriggerSync((2 * 64 * resources.displayMetrics.density).toInt())
|
||||
swipe_refresh.setOnRefreshListener {
|
||||
if (!LibraryUpdateService.isRunning(activity)) {
|
||||
if (!LibraryUpdateService.isRunning(context)) {
|
||||
libraryPresenter.categories.getOrNull(position)?.let {
|
||||
LibraryUpdateService.start(activity, true, it)
|
||||
LibraryUpdateService.start(context, true, it)
|
||||
context.toast(R.string.updating_category)
|
||||
}
|
||||
}
|
||||
|
@ -169,9 +139,7 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
numColumnsSubscription?.unsubscribe()
|
||||
searchSubscription?.unsubscribe()
|
||||
toggleViewSubscription?.unsubscribe()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
|
@ -250,7 +218,7 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||
libraryPresenter.onOpenManga()
|
||||
|
||||
// Create a new activity with the manga.
|
||||
val intent = MangaActivity.newIntent(activity, manga)
|
||||
val intent = MangaActivity.newIntent(context, manga)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
|
@ -282,18 +250,6 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a preference for the number of manga per row based on the current orientation.
|
||||
*
|
||||
* @return the preference.
|
||||
*/
|
||||
fun getColumnsPreferenceForCurrentOrientation(): Preference<Int> {
|
||||
return if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT)
|
||||
libraryPresenter.preferences.portraitColumns()
|
||||
else
|
||||
libraryPresenter.preferences.landscapeColumns()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mode for the adapter.
|
||||
*
|
||||
|
@ -306,15 +262,6 @@ class LibraryCategoryFragment : BaseFragment(), FlexibleViewHolder.OnListItemCli
|
|||
}
|
||||
}
|
||||
|
||||
fun onViewModeChange(isList: Boolean) {
|
||||
//do nothing if the display does not need to change
|
||||
if (isList == displayAsList) return
|
||||
|
||||
//else change view and display mode
|
||||
library_switcher.showNext()
|
||||
displayAsList = isList
|
||||
}
|
||||
|
||||
/**
|
||||
* Property to get the library fragment.
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.library
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.TabLayout
|
||||
import android.support.v4.view.ViewPager
|
||||
|
@ -10,6 +11,7 @@ import android.support.v7.widget.RecyclerView
|
|||
import android.support.v7.widget.SearchView
|
||||
import android.view.*
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.f2prateek.rx.preferences.Preference
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
|
@ -24,6 +26,7 @@ import eu.kanade.tachiyomi.util.toast
|
|||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.fragment_library.*
|
||||
import nucleus.factory.RequiresPresenter
|
||||
import rx.Subscription
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
|
||||
|
@ -61,11 +64,6 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||
*/
|
||||
private var query: String? = null
|
||||
|
||||
/**
|
||||
* Display mode of the library (list or grid mode).
|
||||
*/
|
||||
private var displayMode: MenuItem? = null
|
||||
|
||||
/**
|
||||
* Action mode for manga selection.
|
||||
*/
|
||||
|
@ -87,10 +85,18 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||
*/
|
||||
var isFilterUnread = false
|
||||
|
||||
/**
|
||||
* Number of manga per row in grid mode.
|
||||
*/
|
||||
var mangaPerRow = 0
|
||||
private set
|
||||
|
||||
/**
|
||||
* A pool to share view holders between all the registered categories (fragments).
|
||||
*/
|
||||
val pool = RecyclerView.RecycledViewPool()
|
||||
var pool = RecyclerView.RecycledViewPool()
|
||||
|
||||
private var numColumnsSubscription: Subscription? = null
|
||||
|
||||
companion object {
|
||||
/**
|
||||
|
@ -148,6 +154,12 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||
} else {
|
||||
activeCategory = presenter.preferences.lastUsedCategory().getOrDefault()
|
||||
}
|
||||
|
||||
numColumnsSubscription = getColumnsPreferenceForCurrentOrientation().asObservable()
|
||||
.doOnNext { mangaPerRow = it }
|
||||
.skip(1)
|
||||
// Set again the adapter to recalculate the covers height
|
||||
.subscribe { reattachAdapter() }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -156,6 +168,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
numColumnsSubscription?.unsubscribe()
|
||||
tabs.setupWithViewPager(null)
|
||||
tabs.visibility = View.GONE
|
||||
super.onDestroyView()
|
||||
|
@ -197,17 +210,6 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||
}
|
||||
})
|
||||
|
||||
//set the icon for the display mode button
|
||||
displayMode = menu.findItem(R.id.action_library_display_mode).apply {
|
||||
val icon = if (preferences.libraryAsList().getOrDefault())
|
||||
R.drawable.ic_view_module_white_24dp
|
||||
else
|
||||
R.drawable.ic_view_list_white_24dp
|
||||
|
||||
setIcon(icon)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
@ -257,27 +259,40 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||
*/
|
||||
private fun onFilterCheckboxChanged() {
|
||||
presenter.updateLibrary()
|
||||
adapter.notifyDataSetChanged()
|
||||
adapter.refreshRegisteredAdapters()
|
||||
activity.supportInvalidateOptionsMenu()
|
||||
}
|
||||
|
||||
/**
|
||||
* swap display mode
|
||||
* Swap display mode
|
||||
*/
|
||||
private fun swapDisplayMode() {
|
||||
|
||||
presenter.swapDisplayMode()
|
||||
val isListMode = presenter.displayAsList
|
||||
val icon = if (isListMode)
|
||||
R.drawable.ic_view_module_white_24dp
|
||||
else
|
||||
R.drawable.ic_view_list_white_24dp
|
||||
|
||||
displayMode?.setIcon(icon)
|
||||
|
||||
reattachAdapter()
|
||||
}
|
||||
|
||||
/**
|
||||
* Reattaches the adapter to the view pager to recreate fragments
|
||||
*/
|
||||
private fun reattachAdapter() {
|
||||
pool.clear()
|
||||
pool = RecyclerView.RecycledViewPool()
|
||||
val position = view_pager.currentItem
|
||||
view_pager.adapter = adapter
|
||||
view_pager.currentItem = position
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a preference for the number of manga per row based on the current orientation.
|
||||
*
|
||||
* @return the preference.
|
||||
*/
|
||||
private fun getColumnsPreferenceForCurrentOrientation(): Preference<Int> {
|
||||
return if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT)
|
||||
preferences.portraitColumns()
|
||||
else
|
||||
preferences.landscapeColumns()
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the query.
|
||||
|
@ -289,7 +304,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||
|
||||
// Notify the subject the query has changed.
|
||||
if (isResumed) {
|
||||
presenter.searchSubject?.onNext(query)
|
||||
presenter.searchSubject.onNext(query)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@ import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
|
|||
* @param listener a listener to react to the single tap and long tap events.
|
||||
*/
|
||||
|
||||
abstract class LibraryHolder(private val view: View, adapter: LibraryCategoryAdapter, listener: FlexibleViewHolder.OnListItemClickListener)
|
||||
: FlexibleViewHolder(view, adapter, listener) {
|
||||
abstract class LibraryHolder(private val view: View,
|
||||
adapter: LibraryCategoryAdapter,
|
||||
listener: FlexibleViewHolder.OnListItemClickListener)
|
||||
: FlexibleViewHolder(view, adapter, listener) {
|
||||
|
||||
/**
|
||||
* Method called from [LibraryCategoryAdapter.onBindViewHolder]. It updates the data for this
|
||||
|
|
|
@ -71,12 +71,6 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|||
*/
|
||||
val downloadManager: DownloadManager by injectLazy()
|
||||
|
||||
/**
|
||||
* display the library as a list?
|
||||
*/
|
||||
var displayAsList: Boolean = false
|
||||
private set
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Id of the restartable that listens for library updates.
|
||||
|
@ -95,16 +89,6 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|||
start(GET_LIBRARY)
|
||||
}
|
||||
|
||||
add(preferences.libraryAsList().asObservable().subscribe { setDisplayMode(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display mode
|
||||
*
|
||||
* @param asList display as list or not
|
||||
*/
|
||||
fun setDisplayMode(asList: Boolean) {
|
||||
displayAsList = asList
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,6 +289,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|||
* Changes the active display mode.
|
||||
*/
|
||||
fun swapDisplayMode() {
|
||||
val displayAsList = preferences.libraryAsList().getOrDefault()
|
||||
preferences.libraryAsList().set(!displayAsList)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,36 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout
|
||||
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">
|
||||
|
||||
<ViewSwitcher
|
||||
android:id="@+id/library_switcher"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
android:id="@+id/recycler"
|
||||
style="@style/Theme.Widget.GridView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:columnWidth="140dp"
|
||||
tools:listitem="@layout/item_catalogue_grid"/>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/library_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="@dimen/material_component_lists_padding_above_list"
|
||||
tools:listitem="@layout/item_library_list"/>
|
||||
|
||||
</ViewSwitcher>
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
</FrameLayout>
|
10
app/src/main/res/layout/library_grid_recycler.xml
Normal file
10
app/src/main/res/layout/library_grid_recycler.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/library_grid"
|
||||
style="@style/Theme.Widget.GridView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:columnWidth="140dp"
|
||||
tools:listitem="@layout/item_catalogue_grid" />
|
10
app/src/main/res/layout/library_list_recycler.xml
Normal file
10
app/src/main/res/layout/library_list_recycler.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v7.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/library_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="@dimen/material_component_lists_padding_above_list"
|
||||
tools:listitem="@layout/item_library_list" />
|
||||
|
Loading…
Reference in a new issue