Using new (old?) fast scroller in library

New category jumper now shows what catergory you're on while scrolling
This commit is contained in:
Jay 2020-05-06 20:11:06 -04:00
parent a9ec02caac
commit de8cb8c1b0
19 changed files with 242 additions and 345 deletions

View File

@ -177,8 +177,6 @@ class PreferencesHelper(val context: Context) {
fun gridSize() = rxPrefs.getInteger(Keys.gridSize, 2)
fun alwaysShowSeeker() = rxPrefs.getBoolean("always_show_seeker", false)
fun uniformGrid() = rxPrefs.getBoolean(Keys.uniformGrid, true)
fun chaptersDescAsDefault() = rxPrefs.getBoolean("chapters_desc_as_default", true)

View File

@ -85,9 +85,6 @@ class DisplayBottomSheet(private val controller: LibraryController) : BottomShee
uniform_grid.bindToPreference(preferences.uniformGrid()) {
controller.reattachAdapter()
}
autohide_seeker.bindToPreference(preferences.alwaysShowSeeker()) {
controller.updateShowScrollbar(autohide_seeker.isChecked)
}
grid_size_toggle_group.bindToPreference(preferences.gridSize()) {
controller.reattachAdapter()
}

View File

@ -9,12 +9,12 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.util.lang.removeArticles
import eu.kanade.tachiyomi.util.system.timeSpanFromNow
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import kotlin.math.max
/**
* Adapter storing a list of manga in a certain category.
@ -98,57 +98,63 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
isLongPressDragEnabled = libraryListener.canDrag() && s.isNullOrBlank()
}
fun getSectionText(position: Int): String? {
private fun getFirstLetter(name: String): String {
val letter = name.firstOrNull() ?: '#'
return if (letter.isLetter()) getFirstChar(name) else "#"
}
override fun onCreateBubbleText(position: Int): String {
val preferences: PreferencesHelper by injectLazy()
val db: DatabaseHelper by injectLazy()
if (position == itemCount - 1) return "-"
val sorting = if (!preferences.showAllCategories().get()) {
controller.presenter.getCurrentCategory()?.sortingMode() ?: LibrarySort.DRAG_AND_DROP
} else if (preferences.hideCategories().getOrDefault()) {
preferences.librarySortingMode().getOrDefault()
} else {
(headerItems.firstOrNull() as? LibraryHeaderItem)?.category?.sortingMode()
?: LibrarySort.DRAG_AND_DROP
}
if (position == itemCount - 1) return recyclerView.context.getString(R.string.bottom)
return when (val item: IFlexible<*>? = getItem(position)) {
is LibraryHeaderItem ->
if (preferences.hideCategories().getOrDefault() || item.category.id == 0 ||
!preferences.showAllCategories().get()) null
else getFirstChar(item.category.name) +
"\u200B".repeat(max(0, item.category.order))
if (!preferences.hideCategories().getOrDefault()) item.category.name
else recyclerView.context.getString(R.string.top)
is LibraryItem -> {
when (sorting) {
if (!isSingleCategory) {
item.header?.category?.name.orEmpty()
} else if (item.manga.isBlank()) ""
else when (getSort()) {
LibrarySort.DRAG_AND_DROP -> {
val category = db.getCategoriesForManga(item.manga).executeAsBlocking()
.firstOrNull()
if (category == null) null
else getFirstLetter(category.name) + "\u200B".repeat(max(0, category.order))
if (!preferences.hideCategories().getOrDefault()) {
val title = item.manga.title
if (preferences.removeArticles().getOrDefault())
getFirstChar(title.removeArticles())
else getFirstChar(title)
} else {
val category = db.getCategoriesForManga(item.manga)
.executeAsBlocking().firstOrNull()?.name
category ?: recyclerView.context.getString(R.string.default_value)
}
}
LibrarySort.LAST_READ -> {
val id = item.manga.id ?: return ""
val history = db.getHistoryByMangaId(id).executeAsBlocking()
val last = history.maxBy { it.last_read }
if (last != null && last.last_read > 100) getShorterDate(Date(last.last_read))
else "*"
}
LibrarySort.TOTAL -> {
val unread = item.chapterCount
getShortRange(unread)
if (last != null && last.last_read > 100) last.last_read.timeSpanFromNow
else "N/A"
}
LibrarySort.UNREAD -> {
val unread = item.manga.unread
if (unread > 0) getShortRange(unread)
else "R"
if (unread > 0) unread.toString()
else recyclerView.context.getString(R.string.read)
}
LibrarySort.TOTAL -> {
val total = item.chapterCount
if (total > 0) total.toString()
else "N/A"
}
LibrarySort.LATEST_CHAPTER -> {
val lastUpdate = item.manga.last_update
if (lastUpdate > 0) getShorterDate(Date(lastUpdate))
else "*"
if (lastUpdate > 0) lastUpdate.timeSpanFromNow
// getShortDate(Date(lastUpdate))
else "N/A"
}
LibrarySort.DATE_ADDED -> {
val lastUpdate = item.manga.date_added
if (lastUpdate > 0) getShorterDate(Date(lastUpdate))
else "*"
if (lastUpdate > 0) lastUpdate.timeSpanFromNow
else "N/A"
}
else -> {
val title = if (preferences.removeArticles()
@ -163,67 +169,12 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
}
}
private fun getFirstLetter(name: String): String {
val letter = name.firstOrNull() ?: '#'
return if (letter.isLetter()) getFirstChar(name) else "#"
}
override fun onCreateBubbleText(position: Int): String {
private fun getSort(): Int {
val preferences: PreferencesHelper by injectLazy()
val db: DatabaseHelper by injectLazy()
if (position == itemCount - 1) return recyclerView.context.getString(R.string.bottom)
return when (val iFlexible: IFlexible<*>? = getItem(position)) {
is LibraryHeaderItem ->
if (!preferences.hideCategories().getOrDefault()) iFlexible.category.name
else recyclerView.context.getString(R.string.top)
is LibraryItem -> {
if (iFlexible.manga.isBlank()) ""
else when (if (!preferences.showAllCategories().get()) {
controller.presenter.getCurrentCategory()?.sortingMode() ?: LibrarySort.DRAG_AND_DROP
} else preferences.librarySortingMode().getOrDefault()) {
LibrarySort.DRAG_AND_DROP -> {
if (!preferences.hideCategories().getOrDefault()) {
val title = iFlexible.manga.title
if (preferences.removeArticles().getOrDefault())
getFirstChar(title.removeArticles())
else getFirstChar(title)
} else {
val category = db.getCategoriesForManga(iFlexible.manga)
.executeAsBlocking().firstOrNull()?.name
category ?: recyclerView.context.getString(R.string.default_value)
}
}
LibrarySort.LAST_READ -> {
val id = iFlexible.manga.id ?: return ""
val history = db.getHistoryByMangaId(id).executeAsBlocking()
val last = history.maxBy { it.last_read }
if (last != null && last.last_read > 100) getShortDate(Date(last.last_read))
else "N/A"
}
LibrarySort.UNREAD -> {
val unread = iFlexible.manga.unread
if (unread > 0) getRange(unread)
else recyclerView.context.getString(R.string.read)
}
LibrarySort.TOTAL -> {
val total = iFlexible.chapterCount
if (total > 0) getRange(total)
else "N/A"
}
LibrarySort.LATEST_CHAPTER -> {
val lastUpdate = iFlexible.manga.last_update
if (lastUpdate > 0) getShortDate(Date(lastUpdate))
else "N/A"
}
LibrarySort.DATE_ADDED -> {
val lastUpdate = iFlexible.manga.date_added
if (lastUpdate > 0) getShortDate(Date(lastUpdate))
else "N/A"
}
else -> getSectionText(position) ?: ""
}
}
else -> ""
return if (!preferences.showAllCategories().get() && !preferences.hideCategories().getOrDefault()) {
controller.presenter.getCurrentCategory()?.sortingMode() ?: LibrarySort.DRAG_AND_DROP
} else {
preferences.librarySortingMode().getOrDefault()
}
}
@ -254,23 +205,6 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
}
}
private fun getRange(value: Int): String {
return when (value) {
1 -> "1"
2 -> "2"
3 -> "3"
4 -> "4"
5 -> "5"
in 6..10 -> "6-10"
in 11..50 -> "11-50"
in 51..100 -> "51-100"
in 101..500 -> "100-500"
in 499..899 -> "499-900"
in 901..Int.MAX_VALUE -> "900+"
else -> "None"
}
}
private fun getShorterDate(date: Date): String {
val cal = Calendar.getInstance()
cal.time = Date()
@ -286,25 +220,7 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
SimpleDateFormat("''yy", Locale.getDefault()).format(date)
}
private fun getShortDate(date: Date): String {
val cal = Calendar.getInstance()
cal.time = Date()
val yearNow = cal.get(Calendar.YEAR)
val cal2 = Calendar.getInstance()
cal2.time = date
val yearThen = cal2.get(Calendar.YEAR)
return if (yearNow == yearThen)
SimpleDateFormat("MMMM", Locale.getDefault()).format(date)
else
SimpleDateFormat("yyyy", Locale.getDefault()).format(date)
}
interface LibraryListener {
/**
* Called when an item of the list is released.
*/
fun startReading(position: Int)
fun onItemReleased(position: Int)
fun canDrag(): Boolean

View File

@ -33,8 +33,6 @@ import com.bluelinelabs.conductor.ControllerChangeType
import com.github.florent37.viewtooltip.ViewTooltip
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
import com.reddit.indicatorfastscroll.FastScrollerView
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.SelectableAdapter
import eu.davidea.flexibleadapter.items.IFlexible
@ -59,7 +57,6 @@ import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.dpToPxEnd
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
@ -71,11 +68,8 @@ import eu.kanade.tachiyomi.util.view.hide
import eu.kanade.tachiyomi.util.view.isExpanded
import eu.kanade.tachiyomi.util.view.isHidden
import eu.kanade.tachiyomi.util.view.scrollViewWith
import eu.kanade.tachiyomi.util.view.setBackground
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
import eu.kanade.tachiyomi.util.view.setStartTranslationX
import eu.kanade.tachiyomi.util.view.setStyle
import eu.kanade.tachiyomi.util.view.show
import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
@ -156,11 +150,24 @@ class LibraryController(
private val scrollDistanceTilHidden = 1000.dpToPx
private var textAnim: ViewPropertyAnimator? = null
private var scrollAnim: ViewPropertyAnimator? = null
private var alwaysShowScroller: Boolean = preferences.alwaysShowSeeker().getOrDefault()
var hopperGravity: Int = preferences.hopperGravity().get()
set(value) {
field = value
if (category_hopper_frame == null) return
jumper_category_text.updateLayoutParams<CoordinatorLayout.LayoutParams> {
anchorGravity = when (value) {
0 -> Gravity.RIGHT or Gravity.CENTER_VERTICAL
2 -> Gravity.LEFT or Gravity.CENTER_VERTICAL
else -> Gravity.TOP or Gravity.CENTER_HORIZONTAL
}
gravity = anchorGravity
}
}
private var filterTooltip: ViewTooltip? = null
private var elevationAnim: ValueAnimator? = null
private var elevate = false
override fun getTitle(): String? {
return view?.context?.getString(R.string.library)
}
@ -191,42 +198,18 @@ class LibraryController(
setActiveCategory()
if (presenter.categories.size > 1 && dy != 0 && recyclerView.translationY == 0f) {
val headerItem = getHeader() ?: return
val view = fast_scroller ?: return
val height = if (view.childCount > 0) {
view.height - (view.getChildAt(0)?.paddingTop
?: 0) - (view.getChildAt(view.childCount - 1)?.paddingBottom ?: 0)
} else {
view.height
}
val index = adapter.headerItems.indexOf(headerItem)
textAnim?.cancel()
textAnim = text_view_m.animate().alpha(0f).setDuration(250L).setStartDelay(2000)
textAnim?.start()
// fastScroll height * indicator position - center text - fastScroll padding
text_view_m.translationY =
height * (index.toFloat() / (adapter.headerItems.size + 1))
-text_view_m.height / 2 + 16.dpToPx
text_view_m.translationX = 45f.dpToPxEnd
text_view_m.alpha = 1f
text_view_m.text = headerItem.category.name
showCategoryText(headerItem.category.name)
}
}
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (alwaysShowScroller) return
when (newState) {
RecyclerView.SCROLL_STATE_DRAGGING -> {
scrollAnim?.cancel()
if (fast_scroller?.translationX != 0f) {
fast_scroller?.show()
}
fast_scroller.showScrollbar()
}
RecyclerView.SCROLL_STATE_IDLE -> {
scrollAnim = fast_scroller?.hide()
val shortAnimationDuration = resources?.getInteger(
android.R.integer.config_shortAnimTime
) ?: 0
@ -241,9 +224,17 @@ class LibraryController(
}
}
fun showCategoryText(name: String) {
textAnim?.cancel()
textAnim = jumper_category_text.animate().alpha(0f).setDuration(250L).setStartDelay(2000)
textAnim?.start()
jumper_category_text.alpha = 1f
jumper_category_text.text = name
}
fun isAtTop(): Boolean {
return if (presenter.showAllCategories) {
getVisibleHeader() == adapter.headerItems.firstOrNull()
!recycler.canScrollVertically(-1)
} else {
getVisibleHeader()?.category?.id == presenter.categories.firstOrNull()?.id
}
@ -251,7 +242,7 @@ class LibraryController(
fun isAtBottom(): Boolean {
return if (presenter.showAllCategories) {
getVisibleHeader() == adapter.headerItems.lastOrNull()
!recycler.canScrollVertically(1)
} else {
getVisibleHeader()?.category?.id == presenter.categories.lastOrNull()?.id
}
@ -283,13 +274,10 @@ class LibraryController(
super.onViewCreated(view)
view.applyWindowInsetsForRootController(activity!!.bottom_nav)
if (!::presenter.isInitialized) presenter = LibraryPresenter(this)
fast_scroller.setStartTranslationX(!alwaysShowScroller)
fast_scroller.setBackground(!alwaysShowScroller)
adapter = LibraryCategoryAdapter(this)
adapter.expandItemsAtStartUp()
adapter.isRecursiveCollapse = true
setRecyclerLayout()
recycler.manager.spanSizeLookup = (object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
if (libraryLayout == 0) return 1
@ -301,73 +289,12 @@ class LibraryController(
})
recycler.setHasFixedSize(true)
recycler.adapter = adapter
fast_scroller.setupWithRecyclerView(recycler, { position ->
val letter = adapter.getSectionText(position)
if (!singleCategory && presenter.showAllCategories && !adapter.isHeader(
adapter.getItem(
position
)
) && position != adapter.itemCount - 1
) null
else if (letter != null) FastScrollItemIndicator.Text(letter)
else FastScrollItemIndicator.Icon(R.drawable.ic_star_24dp)
})
fast_scroller.useDefaultScroller = false
fast_scroller.itemIndicatorSelectedCallbacks += object :
FastScrollerView.ItemIndicatorSelectedCallback {
override fun onItemIndicatorSelected(
indicator: FastScrollItemIndicator,
indicatorCenterY: Int,
itemPosition: Int
) {
fast_scroller.translationX = 0f
if (!alwaysShowScroller) {
scrollAnim?.cancel()
scrollAnim = fast_scroller.hide(2000)
}
textAnim?.cancel()
textAnim = text_view_m.animate().alpha(0f).setDuration(250L).setStartDelay(2000)
textAnim?.start()
text_view_m.translationY = indicatorCenterY.toFloat() - text_view_m.height / 2
text_view_m.translationX = 0f
text_view_m.alpha = 1f
text_view_m.text = adapter.onCreateBubbleText(itemPosition)
val appbar = activity?.appbar
if (singleCategory) {
val order = when (val item = adapter.getItem(itemPosition)) {
is LibraryHeaderItem -> item
is LibraryItem -> item.header
else -> null
}?.category?.order
if (order != null) {
activeCategory = order
preferences.lastUsedCategory().set(order)
}
}
appbar?.y = 0f
val item = adapter.getItem(itemPosition)
if (item is LibraryHeaderItem) {
scrollToHeader(item.category.order)
} else {
recycler.suppressLayout(true)
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
itemPosition, if (adapter.isSingleCategory) {
0
} else {
if (itemPosition == 0) {
0
} else {
(-40).dpToPx
}
}
)
recycler.suppressLayout(false)
}
}
fast_scroller.addOnScrollStateChangeListener {
swipe_refresh.isEnabled = !it
}
adapter.fastScroller = fast_scroller
recycler.addOnScrollListener(scrollListener)
val tv = TypedValue()
@ -418,6 +345,7 @@ class LibraryController(
else -> Gravity.CENTER
}
}
hopperGravity = preferences.hopperGravity().get()
val gestureDetector = GestureDetectorCompat(activity, LibraryGestureDetector(this))
listOf(category_hopper_layout, up_category, down_category, category_button).forEach {
@ -430,9 +358,9 @@ class LibraryController(
category_layout?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = recycler?.paddingTop ?: 0
}
fast_scroller?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.systemWindowInsetTop
}
// fast_scroller?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
// topMargin = insets.systemWindowInsetTop
// }
})
swipe_refresh.setOnRefreshListener {
@ -509,9 +437,10 @@ class LibraryController(
} else {
newOffset < adapter.headerItems.size
}) {
val newOrder =
(adapter.headerItems[newOffset] as LibraryHeaderItem).category.order
val newCategory = (adapter.headerItems[newOffset] as LibraryHeaderItem).category
val newOrder = newCategory.order
scrollToHeader(newOrder)
showCategoryText(newCategory.name)
} else {
recycler.scrollToPosition(if (next) adapter.itemCount - 1 else 0)
}
@ -525,8 +454,10 @@ class LibraryController(
newOffset < presenter.categories.size
}
) {
val newOrder = presenter.categories[newOffset].order
val newCategory = presenter.categories[newOffset]
val newOrder = newCategory.order
scrollToHeader(newOrder)
showCategoryText(newCategory.name)
}
}
}
@ -586,16 +517,6 @@ class LibraryController(
return order
}
fun updateShowScrollbar(show: Boolean) {
alwaysShowScroller = show
fast_scroller?.setBackground(!show)
if (libraryLayout == 0) reattachAdapter()
scrollAnim?.cancel()
if (show) fast_scroller?.translationX = 0f
else scrollAnim = fast_scroller?.hide()
setRecyclerLayout()
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
return inflater.inflate(R.layout.library_list_controller, container, false)
}
@ -627,8 +548,8 @@ class LibraryController(
else -> .75f
}
recycler.updatePaddingRelative(
start = (if (alwaysShowScroller) 2 else 5).dpToPx,
end = (if (alwaysShowScroller) 12 else 5).dpToPx
start = 5.dpToPx,
end = 5.dpToPx
)
}
}
@ -684,7 +605,7 @@ class LibraryController(
}
fun onNextLibraryUpdate(mangaMap: List<LibraryItem>, freshStart: Boolean = false) {
val view = view ?: return
view ?: return
destroyActionModeIfNeeded()
if (mangaMap.isNotEmpty()) {
empty_view?.hide()
@ -712,12 +633,6 @@ class LibraryController(
} else recycler_layout.alpha = 1f
if (justStarted && freshStart) {
scrollToHeader(activeCategory)
if (!alwaysShowScroller) {
fast_scroller?.show(false)
view.post {
scrollAnim = fast_scroller?.hide(2000)
}
}
}
category_hopper_frame.visibleIf(!singleCategory)
adapter.isLongPressDragEnabled = canDrag()

View File

@ -67,6 +67,7 @@ class LibraryGestureDetector(private val controller: LibraryController) : Gestur
})
}
}
controller.hopperGravity = controller.preferences.hopperGravity().get()
result = true
}
return result

View File

@ -8,7 +8,6 @@ import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
@ -17,7 +16,6 @@ import androidx.appcompat.widget.PopupMenu
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.f2prateek.rx.preferences.Preference
import com.github.florent37.viewtooltip.ViewTooltip
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.SelectableAdapter
@ -27,7 +25,6 @@ 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.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getResourceColor
@ -42,8 +39,7 @@ import uy.kohesive.injekt.api.get
class LibraryHeaderItem(
private val categoryF: (Int) -> Category,
private val catId: Int,
private val showFastScroll: Preference<Boolean>
private val catId: Int
) :
AbstractHeaderItem<LibraryHeaderItem.Holder>() {
@ -55,7 +51,7 @@ class LibraryHeaderItem(
view: View,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
): Holder {
return Holder(view, adapter as LibraryCategoryAdapter, showFastScroll.getOrDefault())
return Holder(view, adapter as LibraryCategoryAdapter)
}
override fun bindViewHolder(
@ -90,7 +86,7 @@ class LibraryHeaderItem(
return -(category.id!!)
}
class Holder(val view: View, private val adapter: LibraryCategoryAdapter, padEnd: Boolean) :
class Holder(val view: View, private val adapter: LibraryCategoryAdapter) :
BaseFlexibleViewHolder(view, adapter, true) {
private val sectionText: TextView = view.findViewById(R.id.category_title)
@ -101,9 +97,6 @@ class LibraryHeaderItem(
private val catProgress: ProgressBar = view.findViewById(R.id.cat_progress)
init {
sortText.updateLayoutParams<ViewGroup.MarginLayoutParams> {
marginEnd = (if (padEnd && adapter.recyclerView.paddingEnd == 0) 12 else 2).dpToPx
}
category_header_layout.setOnClickListener { toggleCategory() }
updateButton.setOnClickListener { addCategoryToUpdate() }
sectionText.setOnLongClickListener {

View File

@ -37,9 +37,6 @@ class LibraryItem(
var unreadType = 2
var chapterCount = -1
private val showFastScroll: Boolean
get() = preferences.alwaysShowSeeker().getOrDefault()
private val uniformSize: Boolean
get() = preferences.uniformGrid().getOrDefault()
@ -62,7 +59,7 @@ class LibraryItem(
val libraryLayout = libraryLayout
val isFixedSize = uniformSize
if (libraryLayout == 0 || manga.isBlank()) {
LibraryListHolder(view, adapter as LibraryCategoryAdapter, showFastScroll)
LibraryListHolder(view, adapter as LibraryCategoryAdapter)
} else {
view.apply {
val coverHeight = (parent.itemWidth / 3f * 4f).toInt()
@ -107,7 +104,7 @@ class LibraryItem(
)
}
} else {
LibraryListHolder(view, adapter as LibraryCategoryAdapter, showFastScroll)
LibraryListHolder(view, adapter as LibraryCategoryAdapter)
}
}

View File

@ -29,16 +29,9 @@ import kotlinx.android.synthetic.main.unread_download_badge.*
class LibraryListHolder(
private val view: View,
adapter: LibraryCategoryAdapter,
padEnd: Boolean
adapter: LibraryCategoryAdapter
) : LibraryHolder(view, adapter) {
init {
badge_view?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
marginEnd = (if (padEnd) 22 else 12).dpToPx
}
}
/**
* Method called from [LibraryCategoryAdapter.onBindViewHolder]. It updates the data for this
* holder with the given manga.

View File

@ -118,11 +118,7 @@ class LibraryPresenter(
private fun blankItem(id: Int = currentCategory): List<LibraryItem> {
return listOf(
LibraryItem(
LibraryManga.createBlank(id), LibraryHeaderItem(
{ getCategory(id) },
id,
preferences.alwaysShowSeeker()
)
LibraryManga.createBlank(id), LibraryHeaderItem({ getCategory(id) }, id)
)
)
}
@ -499,7 +495,6 @@ class LibraryPresenter(
val categories = db.getCategories().executeAsBlocking().toMutableList()
val showCategories = !preferences.hideCategories().getOrDefault()
var libraryManga = db.getLibraryMangas().executeAsBlocking()
val seekPref = preferences.alwaysShowSeeker()
val showAll = showAllCategories
if (!showCategories) libraryManga = libraryManga.distinctBy { it.id }
val categoryAll = Category.createAll(
@ -507,13 +502,13 @@ class LibraryPresenter(
preferences.librarySortingMode().getOrDefault(),
preferences.librarySortingAscending().getOrDefault()
)
val catItemAll = LibraryHeaderItem({ categoryAll }, -1, seekPref)
val catItemAll = LibraryHeaderItem({ categoryAll }, -1)
val categorySet = mutableSetOf<Int>()
val headerItems = (categories.mapNotNull { category ->
val id = category.id
if (id == null) null
else id to LibraryHeaderItem({ getCategory(id) }, id, seekPref)
} + (-1 to catItemAll) + (0 to LibraryHeaderItem({ getCategory(0) }, 0, seekPref))).toMap()
else id to LibraryHeaderItem({ getCategory(id) }, id)
} + (-1 to catItemAll) + (0 to LibraryHeaderItem({ getCategory(0) }, 0))).toMap()
val items = libraryManga.mapNotNull {
val headerItem = (if (!showCategories) catItemAll
else headerItems[it.category]) ?: return@mapNotNull null

View File

@ -0,0 +1,29 @@
package eu.kanade.tachiyomi.ui.library
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import eu.davidea.fastscroller.FastScroller
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.dpToPxEnd
class MaterialFastScroll @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
FastScroller(context, attrs) {
init {
setViewsToUse(
R.layout.material_fastscroll, R.id.fast_scroller_bubble, R.id.fast_scroller_handle
)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
if (isHidden) return false
return super.onTouchEvent(event)
}
override fun setBubbleAndHandlePosition(y: Float) {
super.setBubbleAndHandlePosition(y)
bubble.y = handle.y - bubble.height / 2f + handle.height / 2f
bubble.translationX = (-45f).dpToPxEnd
}
}

View File

@ -55,7 +55,6 @@ class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: Att
val dpWidth = (measuredWidth.pxToDp / 100f).roundToInt()
val count = max(1, (dpWidth / columnWidth).roundToInt())
spanCount = count
// Timber.d("Dp width: $dpWidth - RSpan: $spanCount")
}
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="38dp"/>
<solid android:color="?colorPrimaryVariant" />
<size
android:width="30dp"
android:height="30dp"/>
</shape>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<corners android:radius="8dp"/>
<solid android:color="@color/colorAccent"/>
<size android:width="6dp" android:height="54dp"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="8dp"/>
<solid android:color="@color/fast_scroller_handle_idle"/>
<size android:width="6dp" android:height="54dp"/>
</shape>
</item>
</selector>

View File

@ -173,14 +173,6 @@
android:layout_marginEnd="12dp"
android:text="@string/download_badge" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/autohide_seeker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:text="@string/always_show_library_fast_scroll"/>
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/hide_filters"
android:layout_width="match_parent"

View File

@ -1,11 +1,11 @@
<?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"
style="@style/Theme.Widget.GridView.Catalogue"
android:id="@+id/recycler"
style="@style/Theme.Widget.GridView.Catalogue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="140dp"
android:clipToPadding="false"
android:background="@drawable/bottom_sheet_rounded_background"
tools:listitem="@layout/manga_grid_item"/>
android:clipToPadding="false"
android:columnWidth="140dp"
tools:listitem="@layout/manga_grid_item" />

View File

@ -51,6 +51,15 @@
<include layout="@layout/library_grid_recycler" />
<eu.kanade.tachiyomi.ui.library.MaterialFastScroll
android:id="@+id/fast_scroller"
android:layout_width="match_parent"
app:fastScrollerAutoHideEnabled="true"
app:fastScrollerAutoHideDelayInMillis="1000"
app:fastScrollerBubbleEnabled="true"
app:fastScrollerIgnoreTouchesOutsideHandle="true"
android:layout_height="match_parent"/>
<View
android:id="@+id/recycler_cover"
android:layout_width="match_parent"
@ -61,42 +70,6 @@
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.reddit.indicatorfastscroll.FastScrollerView
android:id="@+id/fast_scroller"
android:layout_width="25dp"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:background="@drawable/fast_scroll_background"
android:elevation="10dp"
android:paddingStart="3dp"
android:paddingTop="8dp"
android:paddingEnd="0dp"
android:paddingBottom="8dp"
android:textColor="?android:attr/textColorPrimaryInverse"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_view_m"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="50dp"
android:alpha="0"
android:background="@drawable/round_textview_background"
android:padding="10dp"
android:textColor="@android:color/white"
app:layout_constraintEnd_toStartOf="@id/fast_scroller"
app:layout_constraintTop_toTopOf="@id/fast_scroller"
tools:alpha="1"
tools:text="Category" />
</androidx.constraintlayout.widget.ConstraintLayout>
<eu.kanade.tachiyomi.widget.EmptyView
android:id="@+id/empty_view"
android:layout_width="wrap_content"
@ -114,11 +87,33 @@
app:layout_anchor="@id/filter_bottom_sheet"
app:layout_anchorGravity="top" />
<com.google.android.material.textview.MaterialTextView
android:elevation="10dp"
android:id="@+id/jumper_category_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_anchor="@id/category_hopper_frame"
android:background="@drawable/bubble_drawable"
android:gravity="center"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:layout_marginBottom="12dp"
android:layout_gravity="start|center"
app:layout_anchorGravity="start|center"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:alpha="0.0"
android:textColor="?actionBarTintColor"
android:textSize="15sp"
tools:alpha="1"
tools:text="Category and a long one"/>
<FrameLayout
android:id="@+id/category_hopper_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center"
android:elevation="11dp"
app:layout_anchor="@id/filter_bottom_sheet"
app:layout_anchorGravity="top|center">

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<View
android:id="@+id/fast_scroller_bar"
android:layout_width="7dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="@android:color/transparent"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end">
<!-- No margin, use padding at the handle -->
<com.google.android.material.textview.MaterialTextView
android:elevation="10dp"
android:id="@+id/fast_scroller_bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_toStartOf="@+id/fast_scroller_handle"
android:background="@drawable/bubble_drawable"
android:gravity="center"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:textColor="?actionBarTintColor"
android:textSize="15sp"
android:visibility="gone"
tools:text="A"
tools:visibility="visible"/>
<!-- Padding is here to have better grab -->
<ImageView
android:id="@+id/fast_scroller_handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:contentDescription="@null"
android:paddingStart="6dp"
android:paddingEnd="4dp"
android:src="@drawable/thumb_drawable"/>
</RelativeLayout>
</merge>

View File

@ -4,7 +4,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="10dp"
app:cardCornerRadius="25dp"

View File

@ -133,7 +133,6 @@
<string name="start_with_filters_hidden">Start with filters hidden</string>
<string name="download_badge">Download badges</string>
<string name="hide_start_reading_button">Hide start reading button</string>
<string name="always_show_library_fast_scroll">Always show library fast scroll</string>
<string name="unread_badges">Unread badges</string>
<string name="uniform_covers">Uniform covers</string>
<string name="x_small">XS</string>