diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3b4003d72d..42278fcf8c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -206,7 +206,6 @@ dependencies { implementation("me.zhanghai.android.systemuihelper:library:1.0.0") implementation("com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0") implementation("com.github.mthli:Slice:v1.2") - implementation("com.reddit:indicator-fast-scroll:1.2.1") implementation("com.github.kizitonwose:AndroidTagGroup:1.6.0") implementation("com.github.chrisbanes:PhotoView:2.3.0") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/MaterialFastScroll.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/MaterialFastScroll.kt index fee9c6209f..a1a3cb345c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/MaterialFastScroll.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/MaterialFastScroll.kt @@ -3,9 +3,12 @@ package eu.kanade.tachiyomi.ui.library import android.content.Context import android.util.AttributeSet import android.view.MotionEvent +import androidx.recyclerview.widget.RecyclerView import eu.davidea.fastscroller.FastScroller import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.dpToPxEnd +import eu.kanade.tachiyomi.util.view.marginTop +import kotlin.math.abs class MaterialFastScroll @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : FastScroller(context, attrs) { @@ -16,6 +19,7 @@ class MaterialFastScroll @JvmOverloads constructor(context: Context, attrs: Attr ) autoHideEnabled = true ignoreTouchesOutsideHandle = true + updateScrollListener() } override fun onTouchEvent(event: MotionEvent): Boolean { @@ -30,4 +34,22 @@ class MaterialFastScroll @JvmOverloads constructor(context: Context, attrs: Attr bubble.translationX = (-45f).dpToPxEnd } } + + private fun updateScrollListener() { + onScrollListener = object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + if (!isEnabled || bubble == null || handle.isSelected) return + val verticalScrollOffset = recyclerView.computeVerticalScrollOffset() + val verticalScrollRange = recyclerView.computeVerticalScrollRange() - marginTop + val proportion = + verticalScrollOffset.toFloat() / (verticalScrollRange - height).toFloat() + setBubbleAndHandlePosition(height * proportion) + // If scroll amount is small, don't show it + if (minimumScrollThreshold == 0 || dy == 0 || abs(dy) > minimumScrollThreshold || scrollbarAnimator.isAnimating) { + showScrollbar() + if (autoHideEnabled) hideScrollbar() + } + } + } + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsAdapter.kt index 162b9bbbc6..b3c55d6c60 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsAdapter.kt @@ -59,54 +59,33 @@ class MangaDetailsAdapter( } } - fun getSectionText(position: Int): String? { - val chapter = getItem(position) as? ChapterItem ?: return null - if (position == itemCount - 1) return "-" - return when (presenter.scrollType) { - MangaDetailsPresenter.MULTIPLE_VOLUMES, MangaDetailsPresenter.MULTIPLE_SEASONS -> - presenter.getGroupNumber(chapter)?.toString() ?: "*" - MangaDetailsPresenter.HUNDREDS_OF_CHAPTERS -> - if (chapter.chapter_number < 0) "*" - else (chapter.chapter_number / 100).toInt().toString() - MangaDetailsPresenter.TENS_OF_CHAPTERS -> - if (chapter.chapter_number < 0) "*" - else (chapter.chapter_number / 10).toInt().toString() - else -> null - } - } - - fun getFullText(position: Int): String { + override fun onCreateBubbleText(position: Int): String { val chapter = getItem(position) as? ChapterItem ?: return recyclerView.context.getString(R.string.top) - if (position == itemCount - 1) return recyclerView.context.getString(R.string.bottom) return when (val scrollType = presenter.scrollType) { MangaDetailsPresenter.MULTIPLE_VOLUMES, MangaDetailsPresenter.MULTIPLE_SEASONS -> { val volume = presenter.getGroupNumber(chapter) - if (volume != null) recyclerView.context.getString( - if (scrollType == MangaDetailsPresenter.MULTIPLE_SEASONS) R.string.season_ - else R.string.volume_, volume) - else recyclerView.context.getString(R.string.unknown) + if (volume != null) { + recyclerView.context.getString( + if (scrollType == MangaDetailsPresenter.MULTIPLE_SEASONS) R.string.season_ + else R.string.volume_, volume + ) + } else { + recyclerView.context.getString(R.string.unknown) + } } - MangaDetailsPresenter.HUNDREDS_OF_CHAPTERS -> recyclerView.context.getString( - R.string.chapters_, get100sRange( - chapter.chapter_number - ) - ) MangaDetailsPresenter.TENS_OF_CHAPTERS -> recyclerView.context.getString( R.string.chapters_, get10sRange( chapter.chapter_number ) ) - else -> recyclerView.context.getString(R.string.unknown) - } - } - - private fun get100sRange(value: Float): String { - val number = value.toInt() - return if (number < 100) "0-99" - else { - val hundred = number / 100 - "${hundred}00-${hundred}99" + else -> if (chapter.chapter_number > 0) { + recyclerView.context.getString( + R.string.chapter_, decimalFormat.format(chapter.chapter_number) + ) + } else { + chapter.name + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt index feb45edf64..2a92a1c256 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt @@ -53,8 +53,6 @@ import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.signature.ObjectKey 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.kanade.tachiyomi.R @@ -101,14 +99,10 @@ import eu.kanade.tachiyomi.util.system.isOnline import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.getText -import eu.kanade.tachiyomi.util.view.hide import eu.kanade.tachiyomi.util.view.requestPermissionsSafe 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 @@ -205,7 +199,7 @@ class MangaDetailsController : BaseController, setRecycler(view) setPaletteColor() - setFastScroller() + adapter?.fastScroller = fast_scroller2 presenter.onCreate() swipe_refresh.isRefreshing = presenter.isLoading @@ -259,17 +253,6 @@ class MangaDetailsController : BaseController, override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { val atTop = !recycler.canScrollVertically(-1) if (atTop) getHeader()?.backdrop?.translationY = 0f - when (newState) { - RecyclerView.SCROLL_STATE_DRAGGING -> { - scrollAnim?.cancel() - if (fast_scroller.translationX != 0f) { - showFastScroller() - } - } - RecyclerView.SCROLL_STATE_IDLE -> { - scrollAnim = fast_scroller.hide() - } - } } }) } @@ -281,51 +264,12 @@ class MangaDetailsController : BaseController, swipe_refresh.setProgressViewOffset(false, (-40).dpToPx, headerHeight + offset) // 1dp extra to line up chapter header and manga header getHeader()?.setTopHeight(headerHeight) - fast_scroll_layout.updateLayoutParams { + fast_scroller2.updateLayoutParams { topMargin = headerHeight bottomMargin = insets.systemWindowInsetBottom } } - private fun setFastScroller() { - fast_scroller.setStartTranslationX(true) - fast_scroller.setBackground(true) - fast_scroller.setupWithRecyclerView(recycler, { position -> - val letter = adapter?.getSectionText(position) - when { - presenter.scrollType == 0 -> null - 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 - ) { - scrollAnim?.cancel() - scrollAnim = fast_scroller.hide(2000) - - textAnim?.cancel() - textAnim = text_view_m.animate().alpha(0f).setDuration(250L).setStartDelay(1000) - textAnim?.start() - - text_view_m.translationY = indicatorCenterY.toFloat() - text_view_m.height / 2 - text_view_m.alpha = 1f - text_view_m.text = adapter?.getFullText(itemPosition) - val appbar = activity?.appbar - appbar?.y = 0f - (recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset( - itemPosition, headerHeight - ) - colorToolbar(itemPosition > 0, false) - } - } - } - /** Set the toolbar to fully transparent or colored and translucent */ fun colorToolbar(isColor: Boolean, animate: Boolean = true) { if (isColor == toolbarIsColored) return @@ -594,12 +538,6 @@ class MangaDetailsController : BaseController, activity?.invalidateOptionsMenu() } - private fun showFastScroller(animate: Boolean = true) { - if (presenter.scrollType != 0) { - fast_scroller.show(animate) - } - } - private fun addMangaHeader() { if (adapter?.scrollableHeaders?.isEmpty() == true) { adapter?.removeAllScrollableHeaders() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt index 74a08cb67f..fbe601e08a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt @@ -251,7 +251,6 @@ class MangaDetailsPresenter( scrollType = when { hasMultipleVolumes(chapters) -> MULTIPLE_VOLUMES hasMultipleSeasons(chapters) -> MULTIPLE_SEASONS - hasHundredsOfChapters(chapters) -> HUNDREDS_OF_CHAPTERS hasTensOfChapters(chapters) -> TENS_OF_CHAPTERS else -> 0 } @@ -283,7 +282,7 @@ class MangaDetailsPresenter( val volNum = getVolumeNumber(it) if (volNum != null) { volumeSet.add(volNum) - if (volumeSet.size >= 3) return true + if (volumeSet.size >= 2) return true } } return false @@ -295,18 +294,14 @@ class MangaDetailsPresenter( val volNum = getSeasonNumber(it) if (volNum != null) { volumeSet.add(volNum) - if (volumeSet.size >= 3) return true + if (volumeSet.size >= 2) return true } } return false } - private fun hasHundredsOfChapters(chapters: List): Boolean { - return chapters.size > 300 - } - private fun hasTensOfChapters(chapters: List): Boolean { - return chapters.size in 21..300 + return chapters.size > 20 } /** @@ -878,7 +873,6 @@ class MangaDetailsPresenter( companion object { const val MULTIPLE_VOLUMES = 1 const val TENS_OF_CHAPTERS = 2 - const val HUNDREDS_OF_CHAPTERS = 3 - const val MULTIPLE_SEASONS = 4 + const val MULTIPLE_SEASONS = 3 } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/FastScrollerExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/FastScrollerExtensions.kt deleted file mode 100644 index 50eb2f677d..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/FastScrollerExtensions.kt +++ /dev/null @@ -1,37 +0,0 @@ -package eu.kanade.tachiyomi.util.view - -import android.content.res.ColorStateList -import android.graphics.Color -import android.view.ViewPropertyAnimator -import androidx.core.content.ContextCompat -import com.reddit.indicatorfastscroll.FastScrollerView -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.system.dpToPxEnd -import eu.kanade.tachiyomi.util.system.getResourceColor - -fun FastScrollerView.setBackground(hasBackground: Boolean) { - background = if (hasBackground) ContextCompat.getDrawable( - context, R.drawable.fast_scroll_background - ) else null - textColor = ColorStateList.valueOf( - if (hasBackground) Color.WHITE - else context.getResourceColor(android.R.attr.textColorPrimary) - ) - iconColor = textColor -} - -fun FastScrollerView.setStartTranslationX(shouldHide: Boolean) { - translationX = if (shouldHide) 25f.dpToPxEnd else 0f -} - -fun FastScrollerView.hide(duration: Long = 1000): ViewPropertyAnimator { - val scrollAnim = animate().setStartDelay(duration).setDuration(250) - .translationX(25f.dpToPxEnd) - scrollAnim.start() - return scrollAnim -} - -fun FastScrollerView.show(animate: Boolean = true) { - if (animate) animate().setStartDelay(0).setDuration(100).translationX(0f).start() - else translationX = 0f -} diff --git a/app/src/main/res/layout/manga_details_controller.xml b/app/src/main/res/layout/manga_details_controller.xml index fd6035f177..9ae2abb61e 100644 --- a/app/src/main/res/layout/manga_details_controller.xml +++ b/app/src/main/res/layout/manga_details_controller.xml @@ -14,55 +14,25 @@ android:background="?android:colorBackground"> - + android:layout_height="match_parent"> - + - - - - - - + android:layout_height="match_parent" + app:fastScrollerBubbleEnabled="true" />