Move LibraryHeaderHolder to a new file

This commit is contained in:
Jay 2020-05-18 15:09:54 -04:00
parent 89ea8388ad
commit 71872df9d0
4 changed files with 273 additions and 269 deletions

View File

@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
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.source.SourceManager
import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.lang.removeArticles import eu.kanade.tachiyomi.util.lang.removeArticles
import eu.kanade.tachiyomi.util.system.isLTR import eu.kanade.tachiyomi.util.system.isLTR
@ -23,6 +24,8 @@ import java.util.Locale
class LibraryCategoryAdapter(val controller: LibraryController) : class LibraryCategoryAdapter(val controller: LibraryController) :
FlexibleAdapter<IFlexible<*>>(null, controller, true) { FlexibleAdapter<IFlexible<*>>(null, controller, true) {
val sourceManager by injectLazy<SourceManager>()
init { init {
setDisplayHeadersAtStartUp(true) setDisplayHeadersAtStartUp(true)
} }

View File

@ -923,7 +923,7 @@ class LibraryController(
if (changedMode) { if (changedMode) {
adapter.notifyItemChanged(it) adapter.notifyItemChanged(it)
} else { } else {
(recycler.findViewHolderForAdapterPosition(it) as? LibraryHeaderItem.Holder)?.setSelection() (recycler.findViewHolderForAdapterPosition(it) as? LibraryHeaderHolder)?.setSelection()
} }
} }
} }

View File

@ -0,0 +1,265 @@
package eu.kanade.tachiyomi.ui.library
import android.app.Activity
import android.graphics.Color
import android.util.TypedValue
import android.view.View
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.github.florent37.viewtooltip.ViewTooltip
import eu.davidea.flexibleadapter.SelectableAdapter
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.icon
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.invisible
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.visible
import eu.kanade.tachiyomi.util.view.visibleIf
import kotlinx.android.synthetic.main.library_category_header_item.*
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAdapter) :
BaseFlexibleViewHolder(view, adapter, true) {
private val sectionText: TextView = view.findViewById(R.id.category_title)
private val sortText: TextView = view.findViewById(R.id.category_sort)
private val updateButton: ImageView = view.findViewById(R.id.update_button)
private val checkboxImage: ImageView = view.findViewById(R.id.checkbox)
private val expandImage: ImageView = view.findViewById(R.id.collapse_arrow)
private val catProgress: ProgressBar = view.findViewById(R.id.cat_progress)
init {
category_header_layout.setOnClickListener { toggleCategory() }
updateButton.setOnClickListener { addCategoryToUpdate() }
sectionText.setOnLongClickListener {
adapter.libraryListener.manageCategory(adapterPosition)
true
}
sectionText.setOnClickListener { toggleCategory() }
sortText.setOnClickListener { it.post { showCatSortOptions() } }
checkboxImage.setOnClickListener { selectAll() }
updateButton.drawable.mutate()
}
private fun toggleCategory() {
adapter.libraryListener.toggleCategoryVisibility(adapterPosition)
val tutorial = Injekt.get<PreferencesHelper>().shownLongPressCategoryTutorial()
if (!tutorial.get()) {
ViewTooltip.on(itemView.context as? Activity, sectionText).autoHide(true, 5000L)
.align(ViewTooltip.ALIGN.START).position(ViewTooltip.Position.TOP)
.text(R.string.long_press_category)
.color(itemView.context.getResourceColor(R.attr.colorAccent))
.textSize(TypedValue.COMPLEX_UNIT_SP, 15f).textColor(Color.WHITE)
.withShadow(false).corner(30).arrowWidth(15).arrowHeight(15).distanceWithView(0)
.show()
tutorial.set(true)
}
}
fun bind(item: LibraryHeaderItem) {
val index = adapter.headerItems.indexOf(item)
val previousIsCollapsed =
if (index > 0) {
(adapter.headerItems[index - 1] as? LibraryHeaderItem)?.category?.isHidden
?: false
} else {
false
}
val shorterMargin = adapter.headerItems.firstOrNull() == item
sectionText.updateLayoutParams<ConstraintLayout.LayoutParams> {
topMargin = (when {
shorterMargin -> 2
previousIsCollapsed -> 5
else -> 32
}).dpToPx
}
val category = item.category
if (category.isAlone) sectionText.text = ""
else sectionText.text = category.name
if (category.sourceId != null) {
val icon = adapter.sourceManager.get(category.sourceId!!)?.icon()
icon?.setBounds(0, 0, 32.dpToPx, 32.dpToPx)
sectionText.setCompoundDrawablesRelative(icon, null, null, null)
} else {
sectionText.setCompoundDrawablesRelative(null, null, null, null)
}
val isAscending = category.isAscending()
val sortingMode = category.sortingMode()
val sortDrawable = when {
sortingMode == LibrarySort.DRAG_AND_DROP || sortingMode == null -> R.drawable.ic_sort_white_24dp
if (sortingMode == LibrarySort.DATE_ADDED || sortingMode == LibrarySort.LATEST_CHAPTER || sortingMode == LibrarySort.LAST_READ) !isAscending else isAscending -> R.drawable.ic_arrow_down_white_24dp
else -> R.drawable.ic_arrow_up_white_24dp
}
sortText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, sortDrawable, 0)
sortText.setText(category.sortRes())
expandImage.setImageResource(
if (category.isHidden) R.drawable.ic_expand_more_24dp
else R.drawable.ic_expand_less_24dp)
when {
adapter.mode == SelectableAdapter.Mode.MULTI -> {
checkboxImage.visibleIf(!category.isHidden)
expandImage.visibleIf(category.isHidden && !adapter.isSingleCategory && !category.isDynamic)
updateButton.gone()
catProgress.gone()
setSelection()
}
category.isDynamic -> {
expandImage.gone()
checkboxImage.gone()
catProgress.gone()
updateButton.gone()
}
LibraryUpdateService.categoryInQueue(category.id) -> {
expandImage.visibleIf(!adapter.isSingleCategory)
checkboxImage.gone()
catProgress.visible()
updateButton.invisible()
}
else -> {
expandImage.visibleIf(!adapter.isSingleCategory)
catProgress.gone()
checkboxImage.gone()
updateButton.visibleIf(!adapter.isSingleCategory)
}
}
}
private fun addCategoryToUpdate() {
if (adapter.libraryListener.updateCategory(adapterPosition)) {
catProgress.visible()
updateButton.invisible()
}
}
private fun showCatSortOptions() {
val category =
(adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category ?: return
adapter.controller.activity?.let { activity ->
val items = mutableListOf(
MaterialMenuSheet.MenuSheetItem(
LibrarySort.ALPHA, R.drawable.ic_sort_by_alpha_24dp, R.string.title
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.LAST_READ,
R.drawable.ic_recent_read_outline_24dp,
R.string.last_read
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.LATEST_CHAPTER,
R.drawable.ic_new_releases_24dp,
R.string.latest_chapter
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.UNREAD, R.drawable.ic_eye_24dp, R.string.unread
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.TOTAL,
R.drawable.ic_sort_by_numeric_24dp,
R.string.total_chapters
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.DATE_ADDED,
R.drawable.ic_heart_outline_24dp,
R.string.date_added
)
)
if (category.isDynamic) {
items.add(
MaterialMenuSheet.MenuSheetItem(
LibrarySort.DRAG_AND_DROP,
R.drawable.ic_label_outline_white_24dp,
R.string.category
)
)
}
val sortingMode = category.sortingMode()
val sheet = MaterialMenuSheet(
activity,
items,
activity.getString(R.string.sort_by),
sortingMode
) { sheet, item ->
onCatSortClicked(category, item)
val nCategory =
(adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category
val isAscending = nCategory?.isAscending() ?: false
val drawableRes = getSortRes(item, isAscending)
sheet.setDrawable(item, drawableRes)
false
}
val isAscending = category.isAscending()
val drawableRes = getSortRes(sortingMode, isAscending)
sheet.setDrawable(sortingMode ?: -1, drawableRes)
sheet.show()
}
}
private fun getSortRes(sortingMode: Int?, isAscending: Boolean): Int = when {
sortingMode == LibrarySort.DRAG_AND_DROP -> R.drawable.ic_check_white_24dp
if (sortingMode == LibrarySort.DATE_ADDED ||
sortingMode == LibrarySort.LATEST_CHAPTER ||
sortingMode == LibrarySort.LAST_READ) !isAscending else isAscending ->
R.drawable.ic_arrow_down_white_24dp
else -> R.drawable.ic_arrow_up_white_24dp
}
private fun onCatSortClicked(category: Category, menuId: Int?) {
val modType = if (menuId == null) {
val t = (category.mangaSort?.minus('a') ?: 0) + 1
if (t % 2 != 0) t + 1
else t - 1
} else {
val order = when (menuId) {
LibrarySort.DRAG_AND_DROP -> {
adapter.libraryListener.sortCategory(category.id!!, 'D' - 'a' + 1)
return
}
LibrarySort.DATE_ADDED -> 5
LibrarySort.TOTAL -> 4
LibrarySort.LAST_READ -> 3
LibrarySort.UNREAD -> 2
LibrarySort.LATEST_CHAPTER -> 1
else -> 0
}
if (order == category.catSortingMode()) {
onCatSortClicked(category, null)
return
}
(2 * order + 1)
}
adapter.libraryListener.sortCategory(category.id!!, modType)
}
private fun selectAll() {
adapter.libraryListener.selectAll(adapterPosition)
}
fun setSelection() {
val allSelected = adapter.libraryListener.allSelected(adapterPosition)
val drawable = ContextCompat.getDrawable(
contentView.context,
if (allSelected) R.drawable.ic_check_circle_white_24dp else R.drawable.ic_radio_button_unchecked_white_24dp
)
val tintedDrawable = drawable?.mutate()
tintedDrawable?.setTint(
ContextCompat.getColor(
contentView.context, if (allSelected) R.color.colorAccent
else R.color.gray_button
)
)
checkboxImage.setImageDrawable(tintedDrawable)
}
override fun onLongClick(view: View?): Boolean {
super.onLongClick(view)
return false
}
}

View File

@ -1,46 +1,18 @@
package eu.kanade.tachiyomi.ui.library package eu.kanade.tachiyomi.ui.library
import android.app.Activity
import android.graphics.Color
import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.florent37.viewtooltip.ViewTooltip
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.SelectableAdapter
import eu.davidea.flexibleadapter.items.AbstractHeaderItem import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
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.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.icon
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.invisible
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.visible
import eu.kanade.tachiyomi.util.view.visibleIf
import kotlinx.android.synthetic.main.library_category_header_item.*
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
class LibraryHeaderItem( class LibraryHeaderItem(
private val categoryF: (Int) -> Category, private val categoryF: (Int) -> Category,
val catId: Int val catId: Int
) : ) :
AbstractHeaderItem<LibraryHeaderItem.Holder>() { AbstractHeaderItem<LibraryHeaderHolder>() {
private val sourceManager by injectLazy<SourceManager>()
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return R.layout.library_category_header_item return R.layout.library_category_header_item
@ -49,13 +21,13 @@ class LibraryHeaderItem(
override fun createViewHolder( override fun createViewHolder(
view: View, view: View,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>> adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
): Holder { ): LibraryHeaderHolder {
return Holder(view, adapter as LibraryCategoryAdapter) return LibraryHeaderHolder(view, adapter as LibraryCategoryAdapter)
} }
override fun bindViewHolder( override fun bindViewHolder(
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
holder: Holder, holder: LibraryHeaderHolder,
position: Int, position: Int,
payloads: MutableList<Any?>? payloads: MutableList<Any?>?
) { ) {
@ -84,240 +56,4 @@ class LibraryHeaderItem(
override fun hashCode(): Int { override fun hashCode(): Int {
return -(category.id!!) return -(category.id!!)
} }
class Holder(val view: View, private val adapter: LibraryCategoryAdapter) :
BaseFlexibleViewHolder(view, adapter, true) {
private val sectionText: TextView = view.findViewById(R.id.category_title)
private val sortText: TextView = view.findViewById(R.id.category_sort)
private val updateButton: ImageView = view.findViewById(R.id.update_button)
private val checkboxImage: ImageView = view.findViewById(R.id.checkbox)
private val expandImage: ImageView = view.findViewById(R.id.collapse_arrow)
private val catProgress: ProgressBar = view.findViewById(R.id.cat_progress)
init {
category_header_layout.setOnClickListener { toggleCategory() }
updateButton.setOnClickListener { addCategoryToUpdate() }
sectionText.setOnLongClickListener {
adapter.libraryListener.manageCategory(adapterPosition)
true
}
sectionText.setOnClickListener { toggleCategory() }
sortText.setOnClickListener { it.post { showCatSortOptions() } }
checkboxImage.setOnClickListener { selectAll() }
updateButton.drawable.mutate()
}
private fun toggleCategory() {
adapter.libraryListener.toggleCategoryVisibility(adapterPosition)
val tutorial = Injekt.get<PreferencesHelper>().shownLongPressCategoryTutorial()
if (!tutorial.get()) {
ViewTooltip.on(itemView.context as? Activity, sectionText).autoHide(true, 5000L)
.align(ViewTooltip.ALIGN.START).position(ViewTooltip.Position.TOP)
.text(R.string.long_press_category)
.color(itemView.context.getResourceColor(R.attr.colorAccent))
.textSize(TypedValue.COMPLEX_UNIT_SP, 15f).textColor(Color.WHITE)
.withShadow(false).corner(30).arrowWidth(15).arrowHeight(15).distanceWithView(0)
.show()
tutorial.set(true)
}
}
fun bind(item: LibraryHeaderItem) {
val index = adapter.headerItems.indexOf(item)
val previousIsCollapsed =
if (index > 0) {
(adapter.headerItems[index - 1] as? LibraryHeaderItem)?.category?.isHidden
?: false
} else {
false
}
val shorterMargin = adapter.headerItems.firstOrNull() == item
sectionText.updateLayoutParams<ConstraintLayout.LayoutParams> {
topMargin = (when {
shorterMargin -> 2
previousIsCollapsed -> 5
else -> 32
}).dpToPx
}
val category = item.category
if (category.isAlone) sectionText.text = ""
else sectionText.text = category.name
if (category.sourceId != null) {
val icon = item.sourceManager.get(category.sourceId!!)?.icon()
icon?.setBounds(0, 0, 32.dpToPx, 32.dpToPx)
sectionText.setCompoundDrawablesRelative(icon, null, null, null)
} else {
sectionText.setCompoundDrawablesRelative(null, null, null, null)
}
val isAscending = category.isAscending()
val sortingMode = category.sortingMode()
val sortDrawable = when {
sortingMode == LibrarySort.DRAG_AND_DROP || sortingMode == null -> R.drawable.ic_sort_white_24dp
if (sortingMode == LibrarySort.DATE_ADDED || sortingMode == LibrarySort.LATEST_CHAPTER || sortingMode == LibrarySort.LAST_READ) !isAscending else isAscending -> R.drawable.ic_arrow_down_white_24dp
else -> R.drawable.ic_arrow_up_white_24dp
}
sortText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, sortDrawable, 0)
sortText.setText(category.sortRes())
expandImage.setImageResource(
if (category.isHidden) R.drawable.ic_expand_more_24dp
else R.drawable.ic_expand_less_24dp)
when {
adapter.mode == SelectableAdapter.Mode.MULTI -> {
checkboxImage.visibleIf(!category.isHidden)
expandImage.visibleIf(category.isHidden && !adapter.isSingleCategory && !category.isDynamic)
updateButton.gone()
catProgress.gone()
setSelection()
}
category.isDynamic -> {
expandImage.gone()
checkboxImage.gone()
catProgress.gone()
updateButton.gone()
}
LibraryUpdateService.categoryInQueue(category.id) -> {
expandImage.visibleIf(!adapter.isSingleCategory)
checkboxImage.gone()
catProgress.visible()
updateButton.invisible()
}
else -> {
expandImage.visibleIf(!adapter.isSingleCategory)
catProgress.gone()
checkboxImage.gone()
updateButton.visibleIf(!adapter.isSingleCategory)
}
}
}
private fun addCategoryToUpdate() {
if (adapter.libraryListener.updateCategory(adapterPosition)) {
catProgress.visible()
updateButton.invisible()
}
}
private fun showCatSortOptions() {
val category =
(adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category ?: return
adapter.controller.activity?.let { activity ->
val items = mutableListOf(
MaterialMenuSheet.MenuSheetItem(
LibrarySort.ALPHA, R.drawable.ic_sort_by_alpha_24dp, R.string.title
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.LAST_READ,
R.drawable.ic_recent_read_outline_24dp,
R.string.last_read
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.LATEST_CHAPTER,
R.drawable.ic_new_releases_24dp,
R.string.latest_chapter
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.UNREAD, R.drawable.ic_eye_24dp, R.string.unread
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.TOTAL,
R.drawable.ic_sort_by_numeric_24dp,
R.string.total_chapters
), MaterialMenuSheet.MenuSheetItem(
LibrarySort.DATE_ADDED,
R.drawable.ic_heart_outline_24dp,
R.string.date_added
)
)
if (category.isDynamic) {
items.add(
MaterialMenuSheet.MenuSheetItem(
LibrarySort.DRAG_AND_DROP,
R.drawable.ic_label_outline_white_24dp,
R.string.category
)
)
}
val sortingMode = category.sortingMode()
val sheet = MaterialMenuSheet(
activity,
items,
activity.getString(R.string.sort_by),
sortingMode
) { sheet, item ->
onCatSortClicked(category, item)
val nCategory =
(adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category
val isAscending = nCategory?.isAscending() ?: false
val drawableRes = getSortRes(item, isAscending)
sheet.setDrawable(item, drawableRes)
false
}
val isAscending = category.isAscending()
val drawableRes = getSortRes(sortingMode, isAscending)
sheet.setDrawable(sortingMode ?: -1, drawableRes)
sheet.show()
}
}
private fun getSortRes(sortingMode: Int?, isAscending: Boolean): Int = when {
sortingMode == LibrarySort.DRAG_AND_DROP -> R.drawable.ic_check_white_24dp
if (sortingMode == LibrarySort.DATE_ADDED ||
sortingMode == LibrarySort.LATEST_CHAPTER ||
sortingMode == LibrarySort.LAST_READ) !isAscending else isAscending ->
R.drawable.ic_arrow_down_white_24dp
else -> R.drawable.ic_arrow_up_white_24dp
}
private fun onCatSortClicked(category: Category, menuId: Int?) {
val modType = if (menuId == null) {
val t = (category.mangaSort?.minus('a') ?: 0) + 1
if (t % 2 != 0) t + 1
else t - 1
} else {
val order = when (menuId) {
LibrarySort.DRAG_AND_DROP -> {
adapter.libraryListener.sortCategory(category.id!!, 'D' - 'a' + 1)
return
}
LibrarySort.DATE_ADDED -> 5
LibrarySort.TOTAL -> 4
LibrarySort.LAST_READ -> 3
LibrarySort.UNREAD -> 2
LibrarySort.LATEST_CHAPTER -> 1
else -> 0
}
if (order == category.catSortingMode()) {
onCatSortClicked(category, null)
return
}
(2 * order + 1)
}
adapter.libraryListener.sortCategory(category.id!!, modType)
}
private fun selectAll() {
adapter.libraryListener.selectAll(adapterPosition)
}
fun setSelection() {
val allSelected = adapter.libraryListener.allSelected(adapterPosition)
val drawable = ContextCompat.getDrawable(
contentView.context,
if (allSelected) R.drawable.ic_check_circle_white_24dp else R.drawable.ic_radio_button_unchecked_white_24dp
)
val tintedDrawable = drawable?.mutate()
tintedDrawable?.setTint(
ContextCompat.getColor(
contentView.context, if (allSelected) R.color.colorAccent
else R.color.gray_button
)
)
checkboxImage.setImageDrawable(tintedDrawable)
}
override fun onLongClick(view: View?): Boolean {
super.onLongClick(view)
return false
}
}
} }