Reusing scroll extension method in manga details
This commit is contained in:
parent
3fc510fe4b
commit
024b075330
8 changed files with 58 additions and 88 deletions
|
@ -291,11 +291,11 @@ class LibraryController(
|
|||
val tv = TypedValue()
|
||||
activity!!.theme.resolveAttribute(R.attr.actionBarTintColor, tv, true)
|
||||
swipe_refresh.setStyle()
|
||||
scrollViewWith(recycler, swipeRefreshLayout = swipe_refresh) { insets ->
|
||||
scrollViewWith(recycler, swipeRefreshLayout = swipe_refresh, afterInsets = { insets ->
|
||||
fast_scroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = insets.systemWindowInsetTop
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
swipe_refresh.setOnRefreshListener {
|
||||
swipe_refresh.isRefreshing = false
|
||||
|
|
|
@ -134,5 +134,6 @@ class MangaDetailsAdapter(
|
|||
fun copyToClipboard(content: String, label: Int)
|
||||
fun zoomImageFromThumb(thumbView: View)
|
||||
fun showTrackingSheet()
|
||||
fun updateScroll()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import androidx.appcompat.widget.PopupMenu
|
|||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.math.MathUtils
|
||||
import androidx.palette.graphics.Palette
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -98,8 +97,8 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
|
|||
import eu.kanade.tachiyomi.util.system.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.pxToDp
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
||||
import eu.kanade.tachiyomi.util.view.getText
|
||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
||||
import eu.kanade.tachiyomi.util.view.setStyle
|
||||
import eu.kanade.tachiyomi.util.view.snack
|
||||
|
@ -114,7 +113,6 @@ import uy.kohesive.injekt.api.get
|
|||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.Locale
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
||||
class MangaDetailsController : BaseController,
|
||||
|
@ -261,98 +259,54 @@ class MangaDetailsController : BaseController,
|
|||
val appbarHeight = array.getDimensionPixelSize(0, 0)
|
||||
array.recycle()
|
||||
val offset = 10.dpToPx
|
||||
var statusBarHeight = -1
|
||||
swipe_refresh.setStyle()
|
||||
swipe_refresh.setDistanceToTriggerSync(70.dpToPx)
|
||||
activity!!.appbar.elevation = 0f
|
||||
|
||||
recycler.doOnApplyWindowInsets { v, insets, _ ->
|
||||
v.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
|
||||
scrollViewWith(recycler, padBottom = true, customPadding = true, afterInsets = { insets ->
|
||||
recycler.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
|
||||
tabletRecycler?.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
|
||||
headerHeight = appbarHeight + insets.systemWindowInsetTop
|
||||
statusBarHeight = insets.systemWindowInsetTop
|
||||
swipe_refresh.setProgressViewOffset(false, (-40).dpToPx, headerHeight + offset)
|
||||
if (isTablet) v.updatePaddingRelative(top = headerHeight + 1.dpToPx)
|
||||
// 1dp extra to line up chapter header and manga header
|
||||
if (isTablet) recycler.updatePaddingRelative(top = headerHeight + 1.dpToPx)
|
||||
getHeader()?.setTopHeight(headerHeight)
|
||||
fast_scroll_layout.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = headerHeight
|
||||
bottomMargin = insets.systemWindowInsetBottom
|
||||
}
|
||||
v.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
|
||||
}
|
||||
}, liftOnScroll = {
|
||||
colorToolbar(it)
|
||||
})
|
||||
|
||||
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
val atTop = !recycler.canScrollVertically(-1)
|
||||
if (!isTablet) {
|
||||
val atTop = !recycler.canScrollVertically(-1)
|
||||
val tY = getHeader()?.backdrop?.translationY ?: 0f
|
||||
getHeader()?.backdrop?.translationY = max(0f, tY + dy * 0.25f)
|
||||
if (router?.backstack?.lastOrNull()
|
||||
?.controller() == this@MangaDetailsController && statusBarHeight > -1 && activity != null && activity!!.appbar.height > 0
|
||||
) {
|
||||
activity!!.appbar.y -= dy
|
||||
activity!!.appbar.y = MathUtils.clamp(
|
||||
activity!!.appbar.y, -activity!!.appbar.height.toFloat(), 0f
|
||||
)
|
||||
}
|
||||
val appBarY = activity?.appbar?.y ?: 0f
|
||||
if ((!atTop && !toolbarIsColored && (appBarY < (-headerHeight + 1) || (dy < 0 && appBarY == 0f))) || (atTop && toolbarIsColored)) {
|
||||
colorToolbar(!atTop)
|
||||
}
|
||||
} else {
|
||||
if ((!atTop && !toolbarIsColored) || (atTop && toolbarIsColored)) {
|
||||
colorToolbar(!atTop)
|
||||
}
|
||||
}
|
||||
if (atTop) {
|
||||
getHeader()?.backdrop?.translationY = 0f
|
||||
activity!!.appbar.y = 0f
|
||||
}
|
||||
if (!isTablet) {
|
||||
if (atTop) getHeader()?.backdrop?.translationY = 0f
|
||||
val fPosition =
|
||||
(recycler.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
|
||||
val scrollFunc: (Boolean) -> Unit = { show ->
|
||||
showScroll = show
|
||||
scrollAnim?.cancel()
|
||||
scrollAnim = fast_scroller.animate().setDuration(100).translationX(
|
||||
if (show) 0f else 25f.dpToPx)
|
||||
scrollAnim?.start()
|
||||
}
|
||||
if (fPosition > 0 && !showScroll) {
|
||||
showScroll = true
|
||||
scrollAnim?.cancel()
|
||||
scrollAnim = fast_scroller.animate().setDuration(100).translationX(0f)
|
||||
scrollAnim?.start()
|
||||
scrollFunc(true)
|
||||
} else if (fPosition <= 0 && showScroll) {
|
||||
showScroll = false
|
||||
scrollAnim?.cancel()
|
||||
scrollAnim =
|
||||
fast_scroller.animate().setDuration(100).translationX(25f.dpToPx)
|
||||
scrollAnim?.start()
|
||||
scrollFunc(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
val atTop = !recycler.canScrollVertically(-1)
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE && !isTablet) {
|
||||
if (router?.backstack?.lastOrNull()
|
||||
?.controller() == this@MangaDetailsController && statusBarHeight > -1 && activity != null &&
|
||||
activity!!.appbar.height > 0
|
||||
) {
|
||||
val halfWay = abs((-activity!!.appbar.height.toFloat()) / 2)
|
||||
val shortAnimationDuration = resources?.getInteger(
|
||||
android.R.integer.config_shortAnimTime
|
||||
) ?: 0
|
||||
val closerToTop = abs(activity!!.appbar.y) - halfWay > 0
|
||||
activity!!.appbar.animate().y(
|
||||
if (closerToTop && !atTop) (-activity!!.appbar.height.toFloat())
|
||||
else 0f
|
||||
).setDuration(shortAnimationDuration.toLong()).start()
|
||||
if (!closerToTop && !atTop && !toolbarIsColored)
|
||||
colorToolbar(true)
|
||||
}
|
||||
}
|
||||
if (atTop && toolbarIsColored) colorToolbar(false)
|
||||
if (atTop) {
|
||||
getHeader()?.backdrop?.translationY = 0f
|
||||
activity!!.appbar.y = 0f
|
||||
}
|
||||
if (atTop) getHeader()?.backdrop?.translationY = 0f
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1004,6 +958,15 @@ class MangaDetailsController : BaseController,
|
|||
presenter.startDownloadingNow(chapter)
|
||||
}
|
||||
|
||||
// In case the recycler is at the bottom and collapsing the header makes it unscrollable
|
||||
override fun updateScroll() {
|
||||
if (!recycler.canScrollVertically(-1)) {
|
||||
getHeader()?.backdrop?.translationY = 0f
|
||||
activity?.appbar?.y = 0f
|
||||
colorToolbar(isColor = false, animate = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadChapters(chapters: List<ChapterItem>) {
|
||||
val view = view ?: return
|
||||
presenter.downloadChapters(chapters)
|
||||
|
|
|
@ -69,6 +69,9 @@ class MangaHeaderHolder(
|
|||
adapter.delegate.favoriteManga(true)
|
||||
true
|
||||
}
|
||||
title.setOnClickListener {
|
||||
title.maxLines = Integer.MAX_VALUE
|
||||
}
|
||||
title.setOnLongClickListener {
|
||||
adapter.delegate.copyToClipboard(title.text.toString(), R.string.title)
|
||||
true
|
||||
|
@ -102,6 +105,9 @@ class MangaHeaderHolder(
|
|||
manga_genres_tags.gone()
|
||||
less_button.gone()
|
||||
more_button_group.visible()
|
||||
adapter.recyclerView.post {
|
||||
adapter.delegate.updateScroll()
|
||||
}
|
||||
}
|
||||
|
||||
fun bindChapters() {
|
||||
|
|
|
@ -117,9 +117,9 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
|
|||
val appBarHeight = array.getDimensionPixelSize(0, 0)
|
||||
array.recycle()
|
||||
swipe_refresh.setStyle()
|
||||
scrollViewWith(recycler, skipFirstSnap = true, swipeRefreshLayout = swipe_refresh) {
|
||||
scrollViewWith(recycler, swipeRefreshLayout = swipe_refresh, afterInsets = {
|
||||
headerHeight = it.systemWindowInsetTop + appBarHeight
|
||||
}
|
||||
})
|
||||
|
||||
presenter.onCreate()
|
||||
if (presenter.recentItems.isNotEmpty()) {
|
||||
|
|
|
@ -121,9 +121,9 @@ class SourceController : NucleusController<SourcePresenter>(),
|
|||
val array = view.context.obtainStyledAttributes(attrsArray)
|
||||
val appBarHeight = array.getDimensionPixelSize(0, 0)
|
||||
array.recycle()
|
||||
scrollViewWith(recycler) {
|
||||
scrollViewWith(recycler, afterInsets = {
|
||||
headerHeight = it.systemWindowInsetTop + appBarHeight
|
||||
}
|
||||
})
|
||||
|
||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
||||
ext_bottom_sheet.onCreate(this)
|
||||
|
|
|
@ -184,11 +184,11 @@ open class BrowseSourceController(bundle: Bundle) :
|
|||
recycler.setHasFixedSize(true)
|
||||
recycler.adapter = adapter
|
||||
|
||||
scrollViewWith(recycler, true) { insets ->
|
||||
scrollViewWith(recycler, true, afterInsets = { insets ->
|
||||
fab.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
bottomMargin = insets.systemWindowInsetBottom + 16.dpToPx
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
|
|
|
@ -9,7 +9,6 @@ import android.view.inputmethod.InputMethodManager
|
|||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.math.MathUtils
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
|
@ -53,9 +52,9 @@ fun Controller.scrollViewWith(
|
|||
recycler: RecyclerView,
|
||||
padBottom: Boolean = false,
|
||||
customPadding: Boolean = false,
|
||||
skipFirstSnap: Boolean = false,
|
||||
swipeRefreshLayout: SwipeRefreshLayout? = null,
|
||||
afterInsets: ((WindowInsets) -> Unit)? = null
|
||||
afterInsets: ((WindowInsets) -> Unit)? = null,
|
||||
liftOnScroll: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
var statusBarHeight = -1
|
||||
activity?.appbar?.y = 0f
|
||||
|
@ -87,14 +86,18 @@ fun Controller.scrollViewWith(
|
|||
var elevate = false
|
||||
val elevateFunc: (Boolean) -> Unit = { el ->
|
||||
elevate = el
|
||||
elevationAnim?.cancel()
|
||||
elevationAnim = ValueAnimator.ofFloat(
|
||||
activity!!.appbar.elevation, if (el) 15f else 0f
|
||||
)
|
||||
elevationAnim?.addUpdateListener { valueAnimator ->
|
||||
activity!!.appbar.elevation = valueAnimator.animatedValue as Float
|
||||
if (liftOnScroll != null) {
|
||||
liftOnScroll.invoke(el)
|
||||
} else {
|
||||
elevationAnim?.cancel()
|
||||
elevationAnim = ValueAnimator.ofFloat(
|
||||
activity!!.appbar.elevation, if (el) 15f else 0f
|
||||
)
|
||||
elevationAnim?.addUpdateListener { valueAnimator ->
|
||||
activity!!.appbar.elevation = valueAnimator.animatedValue as Float
|
||||
}
|
||||
elevationAnim?.start()
|
||||
}
|
||||
elevationAnim?.start()
|
||||
}
|
||||
addLifecycleListener(object : Controller.LifecycleListener() {
|
||||
override fun onChangeStart(
|
||||
|
@ -144,10 +147,7 @@ fun Controller.scrollViewWith(
|
|||
R.integer.config_shortAnimTime
|
||||
) ?: 0
|
||||
val closerToTop = abs(activity!!.appbar.y) - halfWay > 0
|
||||
val atTop = (!customPadding &&
|
||||
(recycler.layoutManager as LinearLayoutManager)
|
||||
.findFirstVisibleItemPosition() < 2 && !skipFirstSnap) ||
|
||||
!recycler.canScrollVertically(-1)
|
||||
val atTop = !recycler.canScrollVertically(-1)
|
||||
activity!!.appbar.animate().y(
|
||||
if (closerToTop && !atTop) (-activity!!.appbar.height.toFloat())
|
||||
else 0f
|
||||
|
|
Reference in a new issue