Library toolbar now collaspses again

Moved the show all categories button into the recylcer
This commit is contained in:
Jay 2020-05-04 23:37:46 -04:00
parent f890f5cfff
commit ee2df0f87a
5 changed files with 135 additions and 72 deletions

View File

@ -61,11 +61,10 @@ import eu.kanade.tachiyomi.util.system.dpToPxEnd
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.getItemView import eu.kanade.tachiyomi.util.view.getItemView
import eu.kanade.tachiyomi.util.view.gone import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.hide import eu.kanade.tachiyomi.util.view.hide
import eu.kanade.tachiyomi.util.view.marginTop import eu.kanade.tachiyomi.util.view.scrollViewWith
import eu.kanade.tachiyomi.util.view.setBackground import eu.kanade.tachiyomi.util.view.setBackground
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
import eu.kanade.tachiyomi.util.view.setStartTranslationX import eu.kanade.tachiyomi.util.view.setStartTranslationX
@ -245,12 +244,6 @@ class LibraryController(
fast_scroller.setStartTranslationX(!alwaysShowScroller) fast_scroller.setStartTranslationX(!alwaysShowScroller)
fast_scroller.setBackground(!alwaysShowScroller) fast_scroller.setBackground(!alwaysShowScroller)
show_all.isChecked = preferences.showAllCategories().get()
show_all.setOnCheckedChangeListener { _, isChecked ->
preferences.showAllCategories().set(isChecked)
presenter.getLibrary()
}
adapter = LibraryCategoryAdapter(this) adapter = LibraryCategoryAdapter(this)
adapter.expandItemsAtStartUp() adapter.expandItemsAtStartUp()
adapter.isRecursiveCollapse = true adapter.isRecursiveCollapse = true
@ -312,7 +305,15 @@ class LibraryController(
appbar?.y = 0f appbar?.y = 0f
recycler.suppressLayout(true) recycler.suppressLayout(true)
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset( (recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
itemPosition, 0 itemPosition, if (adapter.isSingleCategory) {
0
} else {
if (itemPosition == 0) {
0
} else {
(-40).dpToPx
}
}
) )
recycler.suppressLayout(false) recycler.suppressLayout(false)
} }
@ -330,25 +331,18 @@ class LibraryController(
scrollToHeader(it) scrollToHeader(it)
showCategories(false) showCategories(false)
} }
swipe_refresh.setDistanceToTriggerSync(150.dpToPx) category_recycler.onShowAllClicked = { isChecked ->
val marginTop = category_layout.marginTop preferences.showAllCategories().set(isChecked)
recycler.doOnApplyWindowInsets { recyclerView, insets, _ -> presenter.getLibrary()
recyclerView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = marginTop + insets.systemWindowInsetTop
} }
scrollViewWith(recycler, swipeRefreshLayout = swipe_refresh, afterInsets = { insets ->
category_layout?.updateLayoutParams<ViewGroup.MarginLayoutParams> { category_layout?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = marginTop + insets.systemWindowInsetTop topMargin = recycler?.paddingTop ?: 0
}
recycler_cover?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = marginTop + insets.systemWindowInsetTop
} }
fast_scroller?.updateLayoutParams<ViewGroup.MarginLayoutParams> { fast_scroller?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.systemWindowInsetTop topMargin = insets.systemWindowInsetTop
} }
swipe_refresh?.setProgressViewOffset( })
true, (marginTop + insets.systemWindowInsetTop) + (-60).dpToPx, marginTop + insets.systemWindowInsetTop + 10.dpToPx
)
}
swipe_refresh.setOnRefreshListener { swipe_refresh.setOnRefreshListener {
swipe_refresh.isRefreshing = false swipe_refresh.isRefreshing = false
@ -605,11 +599,16 @@ class LibraryController(
private fun showCategories(show: Boolean) { private fun showCategories(show: Boolean) {
recycler_cover.isClickable = show recycler_cover.isClickable = show
recycler_cover.isFocusable = show recycler_cover.isFocusable = show
val translateY = if (show) category_layout.height.toFloat() + 12f.dpToPx else 0f val translateY = if (show) {
category_layout.height.toFloat() + recycler.paddingTop
} else {
0f
}
recycler.animate().translationY(translateY).start() recycler.animate().translationY(translateY).start()
recycler_cover.animate().translationY(translateY).start() recycler_cover.animate().translationY(translateY).start()
recycler_cover.animate().alpha(if (show) 0.75f else 0f).start() recycler_cover.animate().alpha(if (show) 0.75f else 0f).start()
if (show) { if (show) {
activity?.appbar?.y = 0f
elevateFunc(false) elevateFunc(false)
activity?.dropdown?.setImageResource(R.drawable.ic_arrow_drop_up_24dp) activity?.dropdown?.setImageResource(R.drawable.ic_arrow_drop_up_24dp)
} else { } else {

View File

@ -1,25 +1,41 @@
package eu.kanade.tachiyomi.ui.library.category package eu.kanade.tachiyomi.ui.library.category
import android.view.View import android.view.View
import android.widget.CheckBox
import android.widget.TextView import android.widget.TextView
import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.items.AbstractItem import com.mikepenz.fastadapter.items.AbstractItem
import com.tfcporciuncula.flow.Preference
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.preference.PreferencesHelper
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class CategoryItem(val category: Category) : class CategoryItem(val category: Category) : AbstractItem<FastAdapter.ViewHolder<CategoryItem>>() {
AbstractItem<CategoryItem.ViewHolder>() {
/** defines the type defining this item. must be unique. preferably an id */ /** defines the type defining this item. must be unique. preferably an id */
override val type: Int = R.id.category_text override val type: Int = if (category.id == -1) {
R.id.auto_checkbox
} else {
R.id.category_text
}
/** defines the layout which will be used for this item in the list */ /** defines the layout which will be used for this item in the list */
override val layoutRes: Int = R.layout.catergory_text_view override val layoutRes: Int = if (category.id == -1) {
R.layout.auto_ext_checkbox
} else {
R.layout.catergory_text_view
}
override var identifier = category.id?.toLong() ?: -1L override var identifier = category.id?.toLong() ?: -1L
override fun getViewHolder(v: View): ViewHolder { override fun getViewHolder(v: View): FastAdapter.ViewHolder<CategoryItem> {
return ViewHolder(v) return if (category.id == -1) {
ShowAllViewHolder(Injekt.get<PreferencesHelper>().showAllCategories(), v)
} else {
ViewHolder(v)
}
} }
class ViewHolder(view: View) : FastAdapter.ViewHolder<CategoryItem>(view) { class ViewHolder(view: View) : FastAdapter.ViewHolder<CategoryItem>(view) {
@ -33,4 +49,19 @@ AbstractItem<CategoryItem.ViewHolder>() {
categoryTitle.text = null categoryTitle.text = null
} }
} }
class ShowAllViewHolder(val pref: Preference<Boolean>, view: View) :
FastAdapter.ViewHolder<CategoryItem>(view) {
val checkbox: CheckBox? = view.findViewById(R.id.auto_checkbox)
init {
checkbox?.setText(R.string.show_all_categories)
}
override fun bindView(item: CategoryItem, payloads: List<Any>) {
checkbox?.isChecked = pref.get()
}
override fun unbindView(item: CategoryItem) {}
}
} }

View File

@ -2,16 +2,19 @@ package eu.kanade.tachiyomi.ui.library.category
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.CheckBox
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.adapters.ItemAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter
import com.mikepenz.fastadapter.listeners.CustomEventHook
import com.mikepenz.fastadapter.listeners.OnBindViewHolderListenerImpl import com.mikepenz.fastadapter.listeners.OnBindViewHolderListenerImpl
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.CategoryImpl
import eu.kanade.tachiyomi.util.view.marginBottom import eu.kanade.tachiyomi.util.view.marginBottom
import eu.kanade.tachiyomi.util.view.marginTop
class CategoryRecyclerView @JvmOverloads constructor( class CategoryRecyclerView @JvmOverloads constructor(
context: Context, context: Context,
@ -21,8 +24,12 @@ class CategoryRecyclerView @JvmOverloads constructor(
val manager = LinearLayoutManager(context) val manager = LinearLayoutManager(context)
private val fastAdapter: FastAdapter<CategoryItem> private val fastAdapter: FastAdapter<CategoryItem>
var onCategoryClicked: (Int) -> Unit = { _ -> } var onCategoryClicked: (Int) -> Unit = { _ -> }
var onShowAllClicked: (Boolean) -> Unit = { }
private val itemAdapter = ItemAdapter<CategoryItem>() private val itemAdapter = ItemAdapter<CategoryItem>()
var selectedCategory: Int = 0 var selectedCategory: Int = 0
val headerItem = CategoryItem(CategoryImpl().apply {
id = -1
})
init { init {
fastAdapter = FastAdapter.with(itemAdapter) fastAdapter = FastAdapter.with(itemAdapter)
@ -31,8 +38,9 @@ class CategoryRecyclerView @JvmOverloads constructor(
} }
fun setCategories(items: List<Category>) { fun setCategories(items: List<Category>) {
itemAdapter.set(items.map(::CategoryItem)) itemAdapter.set(listOf(headerItem) + items.map(::CategoryItem))
fastAdapter.onBindViewHolderListener = (object : OnBindViewHolderListenerImpl<CategoryItem>() { fastAdapter.onBindViewHolderListener =
(object : OnBindViewHolderListenerImpl<CategoryItem>() {
override fun onBindViewHolder( override fun onBindViewHolder(
viewHolder: ViewHolder, viewHolder: ViewHolder,
position: Int, position: Int,
@ -40,26 +48,42 @@ class CategoryRecyclerView @JvmOverloads constructor(
) { ) {
super.onBindViewHolder(viewHolder, position, payloads) super.onBindViewHolder(viewHolder, position, payloads)
(viewHolder as? CategoryItem.ViewHolder)?.categoryTitle?.isSelected = (viewHolder as? CategoryItem.ViewHolder)?.categoryTitle?.isSelected =
selectedCategory == position selectedCategory + 1 == position
} }
}) })
fastAdapter.onClickListener = { _, _, item, _ -> fastAdapter.onClickListener = { _, _, item, _ ->
if (item.category.id != -1)
onCategoryClicked(item.category.order) onCategoryClicked(item.category.order)
true true
} }
fastAdapter.addEventHook(object : CustomEventHook<CategoryItem>() {
override fun onBind(viewHolder: ViewHolder): View? {
return if (viewHolder is CategoryItem.ShowAllViewHolder) {
viewHolder.checkbox
} else {
null
}
}
override fun attachEvent(view: View, viewHolder: ViewHolder) {
(view as? CheckBox)?.setOnCheckedChangeListener { _, isChecked ->
onShowAllClicked(isChecked)
}
}
})
} }
fun setCategories(selected: Int) { fun setCategories(selected: Int) {
selectedCategory = selected selectedCategory = selected
for (i in 0..manager.itemCount) { for (i in 0..manager.itemCount) {
(findViewHolderForAdapterPosition(i) as? CategoryItem.ViewHolder)?.categoryTitle?.isSelected = (findViewHolderForAdapterPosition(i) as? CategoryItem.ViewHolder)?.categoryTitle?.isSelected =
selectedCategory == i selectedCategory + 1 == i
} }
} }
override fun onMeasure(widthSpec: Int, heightSpec: Int) { override fun onMeasure(widthSpec: Int, heightSpec: Int) {
val recyclerView = (parent.parent as ViewGroup).findViewById<RecyclerView>(R.id.recycler) val recyclerView = (parent.parent as ViewGroup).findViewById<RecyclerView>(R.id.recycler)
val top = recyclerView.marginTop val top = recyclerView.paddingTop
val bottom = recyclerView.marginBottom val bottom = recyclerView.marginBottom
val parent = recyclerView.measuredHeight - top - bottom val parent = recyclerView.measuredHeight - top - bottom
val heightS = if (parent > 0) val heightS = if (parent > 0)

View File

@ -96,7 +96,7 @@ fun Controller.scrollViewWith(
elevate = el elevate = el
if (liftOnScroll != null) { if (liftOnScroll != null) {
liftOnScroll.invoke(el) liftOnScroll.invoke(el)
} else { } else if (recycler.translationY == 0f) {
elevationAnim?.cancel() elevationAnim?.cancel()
elevationAnim = ValueAnimator.ofFloat( elevationAnim = ValueAnimator.ofFloat(
activity!!.appbar.elevation, if (el) 15f else 0f activity!!.appbar.elevation, if (el) 15f else 0f
@ -158,7 +158,9 @@ fun Controller.scrollViewWith(
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy) super.onScrolled(recyclerView, dx, dy)
if (router?.backstack?.lastOrNull() if (router?.backstack?.lastOrNull()
?.controller() == this@scrollViewWith && statusBarHeight > -1 && activity != null && activity!!.appbar.height > 0 ?.controller() == this@scrollViewWith && statusBarHeight > -1 &&
activity != null && activity!!.appbar.height > 0 &&
recycler.translationY == 0f
) { ) {
if (!recycler.canScrollVertically(-1)) { if (!recycler.canScrollVertically(-1)) {
val shortAnimationDuration = resources?.getInteger( val shortAnimationDuration = resources?.getInteger(
@ -185,7 +187,9 @@ fun Controller.scrollViewWith(
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) { if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (router?.backstack?.lastOrNull() if (router?.backstack?.lastOrNull()
?.controller() == this@scrollViewWith && statusBarHeight > -1 && activity != null && activity!!.appbar.height > 0 ?.controller() == this@scrollViewWith && statusBarHeight > -1 &&
activity != null && activity!!.appbar.height > 0 &&
recycler.translationY == 0f
) { ) {
val halfWay = abs((-activity!!.appbar.height.toFloat()) / 2) val halfWay = abs((-activity!!.appbar.height.toFloat()) / 2)
val shortAnimationDuration = resources?.getInteger( val shortAnimationDuration = resources?.getInteger(

View File

@ -8,9 +8,9 @@
<ProgressBar <ProgressBar
android:id="@+id/progress" android:id="@+id/progress"
android:layout_gravity="center"
android:layout_width="75dp" android:layout_width="75dp"
android:layout_height="75dp"/> android:layout_height="75dp"
android:layout_gravity="center" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh" android:id="@+id/swipe_refresh"
@ -22,35 +22,40 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/category_layout" android:id="@+id/category_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_marginTop="?actionBarSize"
android:orientation="vertical"
android:gravity="top"
android:layout_height="wrap_content" >
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/show_all"
android:layout_marginStart="6dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/show_all_categories"/> android:layout_marginTop="?actionBarSize"
android:orientation="vertical">
<eu.kanade.tachiyomi.ui.library.category.CategoryRecyclerView <eu.kanade.tachiyomi.ui.library.category.CategoryRecyclerView
android:id="@+id/category_recycler" android:id="@+id/category_recycler"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="8dp"
</LinearLayout> android:alpha="0.1"
android:background="@drawable/shape_gradient_top_shadow"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<include layout="@layout/library_grid_recycler" /> <include layout="@layout/library_grid_recycler" />
<View <View
android:id="@+id/recycler_cover" android:id="@+id/recycler_cover"
android:layout_marginTop="?actionBarSize"
android:alpha="0"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?android:colorBackground"/> android:alpha="0"
android:background="?android:colorBackground" />
</FrameLayout> </FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@ -61,16 +66,16 @@
<com.reddit.indicatorfastscroll.FastScrollerView <com.reddit.indicatorfastscroll.FastScrollerView
android:id="@+id/fast_scroller" android:id="@+id/fast_scroller"
android:textColor="?android:attr/textColorPrimaryInverse"
android:layout_width="25dp" android:layout_width="25dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:elevation="10dp"
android:layout_gravity="end" android:layout_gravity="end"
android:background="@drawable/fast_scroll_background" android:background="@drawable/fast_scroll_background"
android:paddingTop="8dp" android:elevation="10dp"
android:paddingBottom="8dp"
android:paddingStart="3dp" android:paddingStart="3dp"
android:paddingTop="8dp"
android:paddingEnd="0dp" android:paddingEnd="0dp"
android:paddingBottom="8dp"
android:textColor="?android:attr/textColorPrimaryInverse"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
@ -80,14 +85,14 @@
android:id="@+id/text_view_m" android:id="@+id/text_view_m"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:alpha="0"
tools:alpha="1"
android:layout_marginEnd="50dp" android:layout_marginEnd="50dp"
android:alpha="0"
android:background="@drawable/round_textview_background" android:background="@drawable/round_textview_background"
android:padding="10dp" android:padding="10dp"
android:textColor="@android:color/white" android:textColor="@android:color/white"
app:layout_constraintEnd_toStartOf="@id/fast_scroller" app:layout_constraintEnd_toStartOf="@id/fast_scroller"
app:layout_constraintTop_toTopOf="@id/fast_scroller" app:layout_constraintTop_toTopOf="@id/fast_scroller"
tools:alpha="1"
tools:text="Category" /> tools:text="Category" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>