mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-24 18:01:50 +01:00
Added animation to scrolling sideways in library list mode
This commit is contained in:
parent
27932e9c06
commit
1966dd594f
@ -183,5 +183,6 @@ class LibraryCategoryAdapter(val libraryListener: LibraryListener) :
|
|||||||
fun selectAll(position: Int)
|
fun selectAll(position: Int)
|
||||||
fun allSelected(position: Int): Boolean
|
fun allSelected(position: Int): Boolean
|
||||||
fun showCategories(position: Int, view: View)
|
fun showCategories(position: Int, view: View)
|
||||||
|
fun recyclerIsScrolling(): Boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,4 +399,5 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||||||
override fun selectAll(position: Int) { }
|
override fun selectAll(position: Int) { }
|
||||||
override fun allSelected(position: Int): Boolean = false
|
override fun allSelected(position: Int): Boolean = false
|
||||||
override fun showCategories(position: Int, view: View) { }
|
override fun showCategories(position: Int, view: View) { }
|
||||||
|
override fun recyclerIsScrolling() = false
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,7 @@ class LibraryHeaderItem(private val categoryF: (Int) -> Category, val catId: Int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun showCatSortOptions() {
|
private fun showCatSortOptions() {
|
||||||
|
if (adapter.libraryListener.recyclerIsScrolling()) return
|
||||||
val category =
|
val category =
|
||||||
(adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category ?: return
|
(adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category ?: return
|
||||||
// Create a PopupMenu, giving it the clicked view for an anchor
|
// Create a PopupMenu, giving it the clicked view for an anchor
|
||||||
|
@ -50,4 +50,9 @@ abstract class LibraryHolder(
|
|||||||
super.onItemReleased(position)
|
super.onItemReleased(position)
|
||||||
(adapter as? LibraryCategoryAdapter)?.libraryListener?.onItemReleased(position)
|
(adapter as? LibraryCategoryAdapter)?.libraryListener?.onItemReleased(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onLongClick(view: View?): Boolean {
|
||||||
|
super.onLongClick(view)
|
||||||
|
return !adapter.libraryListener.recyclerIsScrolling()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
|
import android.animation.Animator
|
||||||
|
import android.animation.AnimatorSet
|
||||||
|
import android.animation.ValueAnimator
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.math.MathUtils.clamp
|
import androidx.core.math.MathUtils.clamp
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@ -26,6 +32,7 @@ import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
|
import eu.kanade.tachiyomi.ui.main.OnTouchEventInterface
|
||||||
import eu.kanade.tachiyomi.ui.main.SpinnerTitleInterface
|
import eu.kanade.tachiyomi.ui.main.SpinnerTitleInterface
|
||||||
import eu.kanade.tachiyomi.ui.main.SwipeGestureInterface
|
import eu.kanade.tachiyomi.ui.main.SwipeGestureInterface
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
@ -33,6 +40,7 @@ import eu.kanade.tachiyomi.util.system.launchUI
|
|||||||
import eu.kanade.tachiyomi.util.view.inflate
|
import eu.kanade.tachiyomi.util.view.inflate
|
||||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||||
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.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||||
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
|
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
|
||||||
import kotlinx.android.synthetic.main.library_grid_recycler.*
|
import kotlinx.android.synthetic.main.library_grid_recycler.*
|
||||||
@ -40,8 +48,13 @@ import kotlinx.android.synthetic.main.library_list_controller.*
|
|||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import kotlinx.android.synthetic.main.spinner_title.view.*
|
import kotlinx.android.synthetic.main.spinner_title.view.*
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import timber.log.Timber
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import kotlin.math.abs
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlin.math.sign
|
||||||
|
|
||||||
class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
@ -49,6 +62,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
FlexibleAdapter.OnItemMoveListener,
|
FlexibleAdapter.OnItemMoveListener,
|
||||||
LibraryCategoryAdapter.LibraryListener,
|
LibraryCategoryAdapter.LibraryListener,
|
||||||
SpinnerTitleInterface,
|
SpinnerTitleInterface,
|
||||||
|
OnTouchEventInterface,
|
||||||
SwipeGestureInterface {
|
SwipeGestureInterface {
|
||||||
|
|
||||||
private lateinit var adapter: LibraryCategoryAdapter
|
private lateinit var adapter: LibraryCategoryAdapter
|
||||||
@ -66,6 +80,17 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
|
|
||||||
private var switchingCategories = false
|
private var switchingCategories = false
|
||||||
|
|
||||||
|
var startPosX:Float? = null
|
||||||
|
var startPosY:Float? = null
|
||||||
|
var moved = false
|
||||||
|
var lockedRecycler = false
|
||||||
|
var lockedY = false
|
||||||
|
var nextCategory:Int? = null
|
||||||
|
var ogCategory:Int? = null
|
||||||
|
var prevCategory:Int? = null
|
||||||
|
private val swipeDistance = 300f
|
||||||
|
var flinging = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recycler view of the list of manga.
|
* Recycler view of the list of manga.
|
||||||
*/
|
*/
|
||||||
@ -73,7 +98,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
|
|
||||||
override fun contentView():View = recycler_layout
|
override fun contentView():View = recycler_layout
|
||||||
|
|
||||||
/* override fun getTitle(): String? {
|
override fun getTitle(): String? {
|
||||||
return if (::customTitleSpinner.isInitialized) customTitleSpinner.category_title.text.toString()
|
return if (::customTitleSpinner.isInitialized) customTitleSpinner.category_title.text.toString()
|
||||||
else super.getTitle()
|
else super.getTitle()
|
||||||
// when {
|
// when {
|
||||||
@ -81,7 +106,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
// spinnerAdapter?.array?.size == 1 -> return spinnerAdapter?.array?.firstOrNull()
|
// spinnerAdapter?.array?.size == 1 -> return spinnerAdapter?.array?.firstOrNull()
|
||||||
// else -> return super.getTitle()
|
// else -> return super.getTitle()
|
||||||
// }
|
// }
|
||||||
}*/
|
}
|
||||||
|
|
||||||
private var scrollListener = object : RecyclerView.OnScrollListener () {
|
private var scrollListener = object : RecyclerView.OnScrollListener () {
|
||||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
@ -115,6 +140,156 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onTouchEvent(event: MotionEvent?) {
|
||||||
|
if (event == null) {
|
||||||
|
resetScrollingValues()
|
||||||
|
resetRecyclerY()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (flinging) return
|
||||||
|
val sheetRect = Rect()
|
||||||
|
val recyclerRect = Rect()
|
||||||
|
bottom_sheet.getGlobalVisibleRect(sheetRect)
|
||||||
|
view?.getGlobalVisibleRect(recyclerRect)
|
||||||
|
|
||||||
|
if (sheetRect.contains(event.x.toInt(), event.y.toInt()) ||
|
||||||
|
!recyclerRect.contains(event.x.toInt(), event.y.toInt())) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (startPosX == null) {
|
||||||
|
startPosX = event.rawX
|
||||||
|
startPosY = event.rawY
|
||||||
|
val position =
|
||||||
|
(recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
|
||||||
|
val order = when (val item = adapter.getItem(position)) {
|
||||||
|
is LibraryHeaderItem -> item.category.order
|
||||||
|
is LibraryItem -> presenter.categories.find { it.id == item.manga.category }?.order
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
if (order != null) {
|
||||||
|
ogCategory = order
|
||||||
|
var newOffsetN = order + 1
|
||||||
|
while (adapter.indexOf(newOffsetN) == -1 && presenter.categories.any { it.order == newOffsetN }) {
|
||||||
|
newOffsetN += 1
|
||||||
|
}
|
||||||
|
if (adapter.indexOf(newOffsetN) != -1)
|
||||||
|
nextCategory = newOffsetN
|
||||||
|
|
||||||
|
if (position == 0) prevCategory = null
|
||||||
|
else {
|
||||||
|
var newOffsetP = order - 1
|
||||||
|
while (adapter.indexOf(newOffsetP) == -1 && presenter.categories.any { it.order == newOffsetP }) {
|
||||||
|
newOffsetP -= 1
|
||||||
|
}
|
||||||
|
if (adapter.indexOf(newOffsetP) != -1)
|
||||||
|
prevCategory = newOffsetP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event.actionMasked != MotionEvent.ACTION_UP && startPosX != null) {
|
||||||
|
val distance = abs(event.rawX - startPosX!!)
|
||||||
|
val sign = sign(event.rawX - startPosX!!)
|
||||||
|
|
||||||
|
if (lockedY) return
|
||||||
|
|
||||||
|
if (distance > 60 && abs(event.rawY - startPosY!!) <= 30 &&
|
||||||
|
!lockedRecycler) {
|
||||||
|
lockedRecycler = true
|
||||||
|
switchingCategories = true
|
||||||
|
if ((prevCategory == null && sign > 0) || (nextCategory == null && sign < 0)) {
|
||||||
|
recycler_layout.x = 0f
|
||||||
|
recycler_layout.alpha = 1f
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else
|
||||||
|
recycler.suppressLayout(true)
|
||||||
|
}
|
||||||
|
else if (!lockedRecycler && abs(event.rawY - startPosY!!) > 30) {
|
||||||
|
lockedY = true
|
||||||
|
resetRecyclerY()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ((prevCategory == null && sign > 0) || (nextCategory == null && sign < 0)) {
|
||||||
|
resetRecyclerY()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (abs(event.rawY - startPosY!!) <= 30 || recycler.isLayoutSuppressed
|
||||||
|
|| lockedRecycler) {
|
||||||
|
if (distance <= swipeDistance * 1.1f) {
|
||||||
|
recycler_layout.x = (max(0f, distance - 50f) * sign) / 3
|
||||||
|
recycler_layout.alpha =
|
||||||
|
(1f - (distance - (swipeDistance * 0.1f)) / swipeDistance)
|
||||||
|
if (moved) {
|
||||||
|
scrollToHeader(ogCategory ?: -1)
|
||||||
|
moved = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!moved) {
|
||||||
|
scrollToHeader((if (sign <= 0) nextCategory else prevCategory) ?: -1)
|
||||||
|
moved = true
|
||||||
|
}
|
||||||
|
recycler_layout.x = ((distance - swipeDistance * 2) * sign) / 3
|
||||||
|
recycler_layout.alpha = ((distance - swipeDistance * 1.1f) / swipeDistance)
|
||||||
|
if (sign > 0) {
|
||||||
|
recycler_layout.x = min(0f, recycler_layout.x)
|
||||||
|
} else {
|
||||||
|
recycler_layout.x = max(0f, recycler_layout.x)
|
||||||
|
}
|
||||||
|
recycler_layout.alpha = min(1f, recycler_layout.alpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event.actionMasked == MotionEvent.ACTION_UP) {
|
||||||
|
recycler_layout.post {
|
||||||
|
if (!flinging) {
|
||||||
|
resetScrollingValues()
|
||||||
|
resetRecyclerY(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetScrollingValues() {
|
||||||
|
startPosX = null
|
||||||
|
startPosY = null
|
||||||
|
nextCategory = null
|
||||||
|
prevCategory = null
|
||||||
|
ogCategory = null
|
||||||
|
lockedY = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetRecyclerY(animated: Boolean = false, time: Long = 100) {
|
||||||
|
moved = false
|
||||||
|
lockedRecycler = false
|
||||||
|
if (animated) {
|
||||||
|
val set = AnimatorSet()
|
||||||
|
val translationXAnimator = ValueAnimator.ofFloat(recycler_layout.x, 0f)
|
||||||
|
translationXAnimator.duration = time
|
||||||
|
translationXAnimator.addUpdateListener {
|
||||||
|
animation -> recycler_layout.x = animation.animatedValue as Float
|
||||||
|
}
|
||||||
|
|
||||||
|
val translationAlphaAnimator = ValueAnimator.ofFloat(recycler_layout.alpha, 1f)
|
||||||
|
translationAlphaAnimator.duration = time
|
||||||
|
translationAlphaAnimator.addUpdateListener {
|
||||||
|
animation -> recycler_layout.alpha = animation.animatedValue as Float
|
||||||
|
}
|
||||||
|
set.playTogether(translationXAnimator, translationAlphaAnimator)
|
||||||
|
set.start()
|
||||||
|
|
||||||
|
launchUI {
|
||||||
|
delay(time)
|
||||||
|
if (!lockedRecycler) switchingCategories = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recycler_layout.x = 0f
|
||||||
|
recycler_layout.alpha = 1f
|
||||||
|
switchingCategories = false
|
||||||
|
}
|
||||||
|
recycler.suppressLayout(false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||||
return inflater.inflate(R.layout.library_list_controller, container, false)
|
return inflater.inflate(R.layout.library_list_controller, container, false)
|
||||||
}
|
}
|
||||||
@ -133,7 +308,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
})
|
})
|
||||||
recycler.setHasFixedSize(true)
|
recycler.setHasFixedSize(true)
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
adapter.fastScroller = fast_scroller
|
//adapter.fastScroller = fast_scroller
|
||||||
recycler.addOnScrollListener(scrollListener)
|
recycler.addOnScrollListener(scrollListener)
|
||||||
|
|
||||||
val tv = TypedValue()
|
val tv = TypedValue()
|
||||||
@ -258,14 +433,26 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scrollToHeader(pos: Int, fade:Boolean = false) {
|
private fun scrollToHeader(pos: Int) {
|
||||||
val headerPosition = adapter.indexOf(pos)
|
val headerPosition = adapter.indexOf(pos)
|
||||||
switchingCategories = true
|
switchingCategories = true
|
||||||
if (headerPosition > -1) {
|
if (headerPosition > -1) {
|
||||||
activity?.appbar?.y = 0f
|
val appbar = activity?.appbar
|
||||||
|
//if (headerPosition == 0)
|
||||||
|
//activity?.appbar?.y = 0f
|
||||||
recycler.suppressLayout(true)
|
recycler.suppressLayout(true)
|
||||||
|
val appbarOffset =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
if (appbar?.y ?: 0f > -20) 0 else
|
||||||
|
(appbar?.y?.plus(view?.rootWindowInsets?.systemWindowInsetTop ?: 0)
|
||||||
|
?: 0f).roundToInt() + 10.dpToPx
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
0
|
||||||
|
}
|
||||||
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
|
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
|
||||||
headerPosition, if (headerPosition == 0) 0 else (-30).dpToPx
|
headerPosition, (if (headerPosition == 0) 0 else (-28).dpToPx)
|
||||||
|
+ appbarOffset
|
||||||
)
|
)
|
||||||
recycler.suppressLayout(false)
|
recycler.suppressLayout(false)
|
||||||
}
|
}
|
||||||
@ -349,6 +536,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun startReading(position: Int) {
|
override fun startReading(position: Int) {
|
||||||
|
if (recyclerIsScrolling()) return
|
||||||
if (adapter.mode == SelectableAdapter.Mode.MULTI) {
|
if (adapter.mode == SelectableAdapter.Mode.MULTI) {
|
||||||
toggleSelection(position)
|
toggleSelection(position)
|
||||||
return
|
return
|
||||||
@ -381,7 +569,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
* @return true if the item should be selected, false otherwise.
|
* @return true if the item should be selected, false otherwise.
|
||||||
*/
|
*/
|
||||||
override fun onItemClick(view: View?, position: Int): Boolean {
|
override fun onItemClick(view: View?, position: Int): Boolean {
|
||||||
if (switchingCategories) return false
|
if (recyclerIsScrolling()) return false
|
||||||
val item = adapter.getItem(position) as? LibraryItem ?: return false
|
val item = adapter.getItem(position) as? LibraryItem ?: return false
|
||||||
return if (adapter.mode == SelectableAdapter.Mode.MULTI) {
|
return if (adapter.mode == SelectableAdapter.Mode.MULTI) {
|
||||||
lastClickPosition = position
|
lastClickPosition = position
|
||||||
@ -399,6 +587,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
* @param position the position of the element clicked.
|
* @param position the position of the element clicked.
|
||||||
*/
|
*/
|
||||||
override fun onItemLongClick(position: Int) {
|
override fun onItemLongClick(position: Int) {
|
||||||
|
if (recyclerIsScrolling()) return
|
||||||
createActionModeIfNeeded()
|
createActionModeIfNeeded()
|
||||||
when {
|
when {
|
||||||
lastClickPosition == -1 -> setSelection(position)
|
lastClickPosition == -1 -> setSelection(position)
|
||||||
@ -586,6 +775,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
override fun onSwipeRight(x: Float, y: Float) = goToNextCategory(x, y,1)
|
override fun onSwipeRight(x: Float, y: Float) = goToNextCategory(x, y,1)
|
||||||
|
|
||||||
private fun goToNextCategory(x: Float, y: Float, offset: Int) {
|
private fun goToNextCategory(x: Float, y: Float, offset: Int) {
|
||||||
|
/*
|
||||||
val sheetRect = Rect()
|
val sheetRect = Rect()
|
||||||
val recyclerRect = Rect()
|
val recyclerRect = Rect()
|
||||||
bottom_sheet.getGlobalVisibleRect(sheetRect)
|
bottom_sheet.getGlobalVisibleRect(sheetRect)
|
||||||
@ -594,13 +784,58 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
if (sheetRect.contains(x.toInt(), y.toInt()) ||
|
if (sheetRect.contains(x.toInt(), y.toInt()) ||
|
||||||
!recyclerRect.contains(x.toInt(), y.toInt())) {
|
!recyclerRect.contains(x.toInt(), y.toInt())) {
|
||||||
return
|
return
|
||||||
|
}*/
|
||||||
|
//jumpToCategory(offset)
|
||||||
|
|
||||||
|
|
||||||
|
if (lockedRecycler && abs(x) > 1000f) {
|
||||||
|
val sign = sign(x).roundToInt()
|
||||||
|
val distance = recycler_layout.alpha
|
||||||
|
val speed = max(3000f / abs(x), 0.75f)
|
||||||
|
Timber.d("Flinged $distance, velo ${abs(x)}, speed $speed")
|
||||||
|
if (sign(recycler_layout.x) == sign(x)) {
|
||||||
|
flinging = true
|
||||||
|
val duration = (distance * 100 * speed).toLong()
|
||||||
|
val set = AnimatorSet()
|
||||||
|
val translationXAnimator = ValueAnimator.ofFloat(recycler_layout.x, sign * 100f)
|
||||||
|
translationXAnimator.duration = duration
|
||||||
|
translationXAnimator.addUpdateListener { animation ->
|
||||||
|
recycler_layout.x = animation.animatedValue as Float
|
||||||
|
}
|
||||||
|
|
||||||
|
val translationAlphaAnimator = ValueAnimator.ofFloat(recycler_layout.alpha, 0f)
|
||||||
|
translationAlphaAnimator.duration = duration
|
||||||
|
translationAlphaAnimator.addUpdateListener { animation ->
|
||||||
|
recycler_layout.alpha = animation.animatedValue as Float
|
||||||
|
}
|
||||||
|
set.playTogether(translationXAnimator, translationAlphaAnimator)
|
||||||
|
set.start()
|
||||||
|
set.addListener(object : Animator.AnimatorListener {
|
||||||
|
override fun onAnimationEnd(animation: Animator?) {
|
||||||
|
recycler_layout.x = -sign * 100f
|
||||||
|
recycler_layout.alpha = 0f
|
||||||
|
scrollToHeader((if (sign <= 0) nextCategory else prevCategory) ?: -1)
|
||||||
|
resetScrollingValues()
|
||||||
|
resetRecyclerY(true, (100 * speed).toLong())
|
||||||
|
flinging = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAnimationCancel(animation: Animator?) {}
|
||||||
|
|
||||||
|
override fun onAnimationRepeat(animation: Animator?) {}
|
||||||
|
|
||||||
|
override fun onAnimationStart(animation: Animator?) {}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun jumpToCategory(offset: Int) {
|
||||||
val position =
|
val position =
|
||||||
(recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
|
(recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
|
||||||
val order = when (val item = adapter.getItem(position)) {
|
val order = when (val item = adapter.getItem(position)) {
|
||||||
is LibraryHeaderItem -> item.category.order
|
is LibraryHeaderItem -> item.category.order
|
||||||
is LibraryItem -> presenter.categories.find { it.id == item.manga.category }?.order
|
is LibraryItem -> presenter.categories.find { it.id == item.manga.category }?.order
|
||||||
?.plus(if (offset < 0) 1 else 0)
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (order != null) {
|
if (order != null) {
|
||||||
@ -608,9 +843,11 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
while (adapter.indexOf(newOffset) == -1 && presenter.categories.any { it.order == newOffset }) {
|
while (adapter.indexOf(newOffset) == -1 && presenter.categories.any { it.order == newOffset }) {
|
||||||
newOffset += offset
|
newOffset += offset
|
||||||
}
|
}
|
||||||
scrollToHeader (newOffset, true)
|
scrollToHeader(newOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popUpMenu(): PopupMenu = titlePopupMenu
|
override fun popUpMenu(): PopupMenu = titlePopupMenu
|
||||||
|
|
||||||
|
override fun recyclerIsScrolling() = switchingCategories || lockedRecycler || lockedY
|
||||||
}
|
}
|
@ -11,6 +11,7 @@ import android.graphics.Rect
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.provider.Settings
|
||||||
import android.view.GestureDetector
|
import android.view.GestureDetector
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
@ -383,7 +384,7 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
return super.startSupportActionMode(callback)
|
return super.startSupportActionMode(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* override fun onSupportActionModeFinished(mode: androidx.appcompat.view.ActionMode) {
|
override fun onSupportActionModeFinished(mode: androidx.appcompat.view.ActionMode) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) launchUI {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) launchUI {
|
||||||
val scale = Settings.Global.getFloat(
|
val scale = Settings.Global.getFloat(
|
||||||
contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f
|
contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f
|
||||||
@ -391,10 +392,11 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
val duration = resources.getInteger(android.R.integer.config_mediumAnimTime) * scale
|
val duration = resources.getInteger(android.R.integer.config_mediumAnimTime) * scale
|
||||||
delay(duration.toLong())
|
delay(duration.toLong())
|
||||||
delay(100)
|
delay(100)
|
||||||
window?.statusBarColor = getResourceColor(android.R.attr.statusBarColor)
|
window?.statusBarColor = ColorUtils.setAlphaComponent(getResourceColor(android.R.attr
|
||||||
|
.colorBackground), 175)
|
||||||
}
|
}
|
||||||
super.onSupportActionModeFinished(mode)
|
super.onSupportActionModeFinished(mode)
|
||||||
}*/
|
}
|
||||||
|
|
||||||
private fun setExtensionsBadge() {
|
private fun setExtensionsBadge() {
|
||||||
val updates = preferences.extensionUpdatesCount().getOrDefault()
|
val updates = preferences.extensionUpdatesCount().getOrDefault()
|
||||||
@ -553,6 +555,9 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
|
|
||||||
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
|
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
|
||||||
gestureDetector.onTouchEvent(ev)
|
gestureDetector.onTouchEvent(ev)
|
||||||
|
val controller = router.backstack.lastOrNull()?.controller()
|
||||||
|
if (controller is OnTouchEventInterface)
|
||||||
|
controller.onTouchEvent(ev)
|
||||||
if (ev?.action == MotionEvent.ACTION_DOWN) {
|
if (ev?.action == MotionEvent.ACTION_DOWN) {
|
||||||
if (snackBar != null && snackBar!!.isShown) {
|
if (snackBar != null && snackBar!!.isShown) {
|
||||||
val sRect = Rect()
|
val sRect = Rect()
|
||||||
@ -687,9 +692,9 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
&& abs(diffY) <= Companion.SWIPE_THRESHOLD * 0.75f
|
&& abs(diffY) <= Companion.SWIPE_THRESHOLD * 0.75f
|
||||||
) {
|
) {
|
||||||
if (diffX > 0) {
|
if (diffX > 0) {
|
||||||
currentGestureDelegate?.onSwipeRight(e1.x, e1.y)
|
currentGestureDelegate?.onSwipeRight(velocityX, e1.y)
|
||||||
} else {
|
} else {
|
||||||
currentGestureDelegate?.onSwipeLeft(e1.x, e1.y)
|
currentGestureDelegate?.onSwipeLeft(velocityX, e1.y)
|
||||||
}
|
}
|
||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
@ -739,6 +744,10 @@ interface BottomNavBarInterface {
|
|||||||
|
|
||||||
interface RootSearchInterface
|
interface RootSearchInterface
|
||||||
|
|
||||||
|
interface OnTouchEventInterface {
|
||||||
|
fun onTouchEvent(event: MotionEvent?)
|
||||||
|
}
|
||||||
|
|
||||||
interface SpinnerTitleInterface {
|
interface SpinnerTitleInterface {
|
||||||
fun popUpMenu(): PopupMenu
|
fun popUpMenu(): PopupMenu
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ fun Controller.scrollViewWith(recycler: RecyclerView,
|
|||||||
swipeRefreshLayout: SwipeRefreshLayout? = null,
|
swipeRefreshLayout: SwipeRefreshLayout? = null,
|
||||||
f: ((WindowInsets) -> Unit)? = null) {
|
f: ((WindowInsets) -> Unit)? = null) {
|
||||||
var statusBarHeight = -1
|
var statusBarHeight = -1
|
||||||
activity!!.appbar.y = 0f
|
activity?.appbar?.y = 0f
|
||||||
recycler.doOnApplyWindowInsets { view, insets, _ ->
|
recycler.doOnApplyWindowInsets { view, insets, _ ->
|
||||||
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
||||||
val array = view.context.obtainStyledAttributes(attrsArray)
|
val array = view.context.obtainStyledAttributes(attrsArray)
|
||||||
@ -335,13 +335,13 @@ fun Controller.scrollViewWith(recycler: RecyclerView,
|
|||||||
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
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)
|
||||||
if (router.backstack.lastOrNull()?.controller() == this@scrollViewWith &&
|
if (router?.backstack?.lastOrNull()?.controller() == this@scrollViewWith &&
|
||||||
statusBarHeight > -1 &&
|
statusBarHeight > -1 &&
|
||||||
activity!!.appbar.height > 0) {
|
activity!!.appbar.height > 0) {
|
||||||
activity!!.appbar.y -= dy
|
activity!!.appbar.y -= dy
|
||||||
activity!!.appbar.y = clamp(
|
activity!!.appbar.y = clamp(
|
||||||
activity!!.appbar.y,
|
activity!!.appbar.y,
|
||||||
-activity!!.appbar.height.toFloat(),// + statusBarHeight,
|
-activity!!.appbar.height.toFloat(),
|
||||||
0f
|
0f
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -350,7 +350,7 @@ fun Controller.scrollViewWith(recycler: RecyclerView,
|
|||||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
super.onScrollStateChanged(recyclerView, newState)
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||||
if (router.backstack.lastOrNull()?.controller() == this@scrollViewWith &&
|
if (router?.backstack?.lastOrNull()?.controller() == this@scrollViewWith &&
|
||||||
statusBarHeight > -1 &&
|
statusBarHeight > -1 &&
|
||||||
activity!!.appbar.height > 0) {
|
activity!!.appbar.height > 0) {
|
||||||
val halfWay = abs((-activity!!.appbar.height.toFloat()) / 2)
|
val halfWay = abs((-activity!!.appbar.height.toFloat()) / 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user