2021-09-16 17:37:17 -04:00
|
|
|
package eu.kanade.tachiyomi.widget
|
|
|
|
|
|
|
|
import android.animation.Animator
|
|
|
|
import android.animation.AnimatorListenerAdapter
|
|
|
|
import android.animation.TimeInterpolator
|
|
|
|
import android.content.Context
|
|
|
|
import android.os.Parcel
|
|
|
|
import android.os.Parcelable
|
|
|
|
import android.util.AttributeSet
|
|
|
|
import android.view.ViewPropertyAnimator
|
|
|
|
import androidx.customview.view.AbsSavedState
|
|
|
|
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
|
|
|
|
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
|
|
|
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
|
|
|
import eu.kanade.tachiyomi.R
|
|
|
|
import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale
|
|
|
|
|
|
|
|
class TachiyomiBottomNavigationView @JvmOverloads constructor(
|
|
|
|
context: Context,
|
|
|
|
attrs: AttributeSet? = null,
|
|
|
|
defStyleAttr: Int = R.attr.bottomNavigationStyle,
|
2022-04-08 15:30:30 -04:00
|
|
|
defStyleRes: Int = R.style.Widget_Design_BottomNavigationView,
|
2021-09-16 17:37:17 -04:00
|
|
|
) : BottomNavigationView(context, attrs, defStyleAttr, defStyleRes) {
|
|
|
|
|
|
|
|
private var currentAnimator: ViewPropertyAnimator? = null
|
|
|
|
|
|
|
|
private var currentState = STATE_UP
|
|
|
|
|
|
|
|
override fun onSaveInstanceState(): Parcelable {
|
|
|
|
val superState = super.onSaveInstanceState()
|
|
|
|
return SavedState(superState).also {
|
|
|
|
it.currentState = currentState
|
2022-02-17 22:08:36 -05:00
|
|
|
it.translationY = translationY
|
2021-09-16 17:37:17 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onRestoreInstanceState(state: Parcelable?) {
|
|
|
|
if (state is SavedState) {
|
|
|
|
super.onRestoreInstanceState(state.superState)
|
2022-02-17 22:08:36 -05:00
|
|
|
super.setTranslationY(state.translationY)
|
|
|
|
currentState = state.currentState
|
2021-09-16 17:37:17 -04:00
|
|
|
} else {
|
|
|
|
super.onRestoreInstanceState(state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun setTranslationY(translationY: Float) {
|
|
|
|
// Disallow translation change when state down
|
|
|
|
if (currentState == STATE_DOWN) return
|
|
|
|
super.setTranslationY(translationY)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Shows this view up.
|
|
|
|
*/
|
2022-02-17 22:08:36 -05:00
|
|
|
fun slideUp() = post {
|
2021-09-16 17:37:17 -04:00
|
|
|
currentAnimator?.cancel()
|
|
|
|
clearAnimation()
|
|
|
|
|
|
|
|
currentState = STATE_UP
|
|
|
|
animateTranslation(
|
|
|
|
0F,
|
2022-02-17 22:08:36 -05:00
|
|
|
SLIDE_UP_ANIMATION_DURATION,
|
2022-04-08 16:44:23 -04:00
|
|
|
LinearOutSlowInInterpolator(),
|
2021-09-16 17:37:17 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hides this view down. [setTranslationY] won't work until [slideUp] is called.
|
|
|
|
*/
|
2022-02-17 22:08:36 -05:00
|
|
|
fun slideDown() = post {
|
2021-09-16 17:37:17 -04:00
|
|
|
currentAnimator?.cancel()
|
|
|
|
clearAnimation()
|
|
|
|
|
|
|
|
currentState = STATE_DOWN
|
|
|
|
animateTranslation(
|
|
|
|
height.toFloat(),
|
2022-02-17 22:08:36 -05:00
|
|
|
SLIDE_DOWN_ANIMATION_DURATION,
|
2022-04-08 16:44:23 -04:00
|
|
|
FastOutLinearInInterpolator(),
|
2021-09-16 17:37:17 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun animateTranslation(targetY: Float, duration: Long, interpolator: TimeInterpolator) {
|
|
|
|
currentAnimator = animate()
|
|
|
|
.translationY(targetY)
|
|
|
|
.setInterpolator(interpolator)
|
|
|
|
.setDuration(duration)
|
|
|
|
.applySystemAnimatorScale(context)
|
|
|
|
.setListener(object : AnimatorListenerAdapter() {
|
|
|
|
override fun onAnimationEnd(animation: Animator?) {
|
|
|
|
currentAnimator = null
|
|
|
|
postInvalidate()
|
|
|
|
}
|
2022-05-10 17:54:52 -04:00
|
|
|
},)
|
2021-09-16 17:37:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal class SavedState : AbsSavedState {
|
|
|
|
var currentState = STATE_UP
|
2022-02-17 22:08:36 -05:00
|
|
|
var translationY = 0F
|
2021-09-16 17:37:17 -04:00
|
|
|
|
|
|
|
constructor(superState: Parcelable) : super(superState)
|
|
|
|
|
|
|
|
constructor(source: Parcel, loader: ClassLoader?) : super(source, loader) {
|
2022-02-17 22:08:36 -05:00
|
|
|
currentState = source.readInt()
|
|
|
|
translationY = source.readFloat()
|
2021-09-16 17:37:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun writeToParcel(out: Parcel, flags: Int) {
|
|
|
|
super.writeToParcel(out, flags)
|
2022-02-17 22:08:36 -05:00
|
|
|
out.writeInt(currentState)
|
|
|
|
out.writeFloat(translationY)
|
2021-09-16 17:37:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
@JvmField
|
|
|
|
val CREATOR: Parcelable.ClassLoaderCreator<SavedState> = object : Parcelable.ClassLoaderCreator<SavedState> {
|
|
|
|
override fun createFromParcel(source: Parcel, loader: ClassLoader): SavedState {
|
|
|
|
return SavedState(source, loader)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun createFromParcel(source: Parcel): SavedState {
|
|
|
|
return SavedState(source, null)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun newArray(size: Int): Array<SavedState> {
|
|
|
|
return newArray(size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
private const val STATE_DOWN = 1
|
|
|
|
private const val STATE_UP = 2
|
|
|
|
|
|
|
|
private const val SLIDE_UP_ANIMATION_DURATION = 225L
|
|
|
|
private const val SLIDE_DOWN_ANIMATION_DURATION = 175L
|
|
|
|
}
|
|
|
|
}
|