mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-09 05:25:08 +01:00
Parallax scrolling to Manga details page
This commit is contained in:
parent
0d658d4b05
commit
497f965cba
@ -35,6 +35,7 @@ import androidx.core.content.pm.ShortcutInfoCompat
|
|||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
|
import androidx.core.math.MathUtils
|
||||||
import androidx.palette.graphics.Palette
|
import androidx.palette.graphics.Palette
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
@ -100,8 +101,6 @@ import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
|||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
|
||||||
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
||||||
import jp.wasabeef.glide.transformations.MaskTransformation
|
import jp.wasabeef.glide.transformations.MaskTransformation
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
@ -110,6 +109,10 @@ import kotlinx.android.synthetic.main.manga_header_item.*
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
class MangaDetailsController : BaseController,
|
class MangaDetailsController : BaseController,
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
@ -214,14 +217,16 @@ class MangaDetailsController : BaseController,
|
|||||||
val appbarHeight = array.getDimensionPixelSize(0, 0)
|
val appbarHeight = array.getDimensionPixelSize(0, 0)
|
||||||
array.recycle()
|
array.recycle()
|
||||||
val offset = 10.dpToPx
|
val offset = 10.dpToPx
|
||||||
|
var statusBarHeight = -1
|
||||||
|
|
||||||
recycler.doOnApplyWindowInsets { v, insets, _ ->
|
recycler.doOnApplyWindowInsets { v, insets, _ ->
|
||||||
headerHeight = appbarHeight + insets.systemWindowInsetTop
|
headerHeight = appbarHeight + insets.systemWindowInsetTop
|
||||||
|
statusBarHeight = insets.systemWindowInsetTop
|
||||||
swipe_refresh.setProgressViewOffset(false, (-40).dpToPx, headerHeight + offset)
|
swipe_refresh.setProgressViewOffset(false, (-40).dpToPx, headerHeight + offset)
|
||||||
(recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder)
|
(recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder)
|
||||||
?.setTopHeight(headerHeight)
|
?.setTopHeight(headerHeight)
|
||||||
fast_scroller?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
fast_scroller?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
topMargin = headerHeight
|
topMargin = statusBarHeight
|
||||||
bottomMargin = insets.systemWindowInsetBottom
|
bottomMargin = insets.systemWindowInsetBottom
|
||||||
}
|
}
|
||||||
v.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
|
v.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
|
||||||
@ -233,8 +238,56 @@ class MangaDetailsController : BaseController,
|
|||||||
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)
|
||||||
val atTop = !recycler.canScrollVertically(-1)
|
val atTop = !recycler.canScrollVertically(-1)
|
||||||
if ((!atTop && !toolbarIsColored) || (atTop && toolbarIsColored)) {
|
val tY = getHeader()?.backdrop?.translationY ?: 0f
|
||||||
toolbarIsColored = !atTop
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
|
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||||
|
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
|
||||||
|
val atTop = !recycler.canScrollVertically(-1)
|
||||||
|
activity!!.appbar.animate().y(
|
||||||
|
if (closerToTop && !atTop) (-activity!!.appbar.height.toFloat())
|
||||||
|
else 0f
|
||||||
|
).setDuration(shortAnimationDuration.toLong()).start()
|
||||||
|
if (!closerToTop && !atTop && !toolbarIsColored)
|
||||||
|
colorToolbar(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setPaletteColor()
|
||||||
|
|
||||||
|
swipe_refresh.isRefreshing = presenter.isLoading
|
||||||
|
if (manga?.initialized != true)
|
||||||
|
swipe_refresh.post { swipe_refresh.isRefreshing = true }
|
||||||
|
|
||||||
|
swipe_refresh.setOnRefreshListener { presenter.refreshAll() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun colorToolbar(isColor: Boolean) {
|
||||||
|
toolbarIsColored = isColor
|
||||||
val isCurrentController =
|
val isCurrentController =
|
||||||
router?.backstack?.lastOrNull()?.controller() == this@MangaDetailsController
|
router?.backstack?.lastOrNull()?.controller() == this@MangaDetailsController
|
||||||
if (isCurrentController) setTitle()
|
if (isCurrentController) setTitle()
|
||||||
@ -264,16 +317,6 @@ class MangaDetailsController : BaseController,
|
|||||||
}
|
}
|
||||||
colorAnimator?.start()
|
colorAnimator?.start()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
setPaletteColor()
|
|
||||||
|
|
||||||
swipe_refresh.isRefreshing = presenter.isLoading
|
|
||||||
if (manga?.initialized != true)
|
|
||||||
swipe_refresh.post { swipe_refresh.isRefreshing = true }
|
|
||||||
|
|
||||||
swipe_refresh.setOnRefreshListener { presenter.refreshAll() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPaletteColor() {
|
fun setPaletteColor() {
|
||||||
val view = view ?: return
|
val view = view ?: return
|
||||||
@ -345,6 +388,8 @@ class MangaDetailsController : BaseController,
|
|||||||
return recycler?.findViewHolderForItemId(chapter.id!!) as? ChapterHolder
|
return recycler?.findViewHolderForItemId(chapter.id!!) as? ChapterHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getHeader(): MangaHeaderHolder? = recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder
|
||||||
|
|
||||||
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||||
super.onChangeStarted(handler, type)
|
super.onChangeStarted(handler, type)
|
||||||
if (type == ControllerChangeType.PUSH_ENTER || type == ControllerChangeType.POP_ENTER) {
|
if (type == ControllerChangeType.PUSH_ENTER || type == ControllerChangeType.POP_ENTER) {
|
||||||
|
@ -38,6 +38,13 @@
|
|||||||
android:backgroundTint="?android:attr/colorBackground"
|
android:backgroundTint="?android:attr/colorBackground"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/true_backdrop" />
|
app:layout_constraintBottom_toBottomOf="@+id/true_backdrop" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="?android:attr/colorBackground"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/backdrop_gradient"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/top_view"
|
android:id="@+id/top_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
Loading…
Reference in New Issue
Block a user