mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-20 03:59:16 +01:00
Animated insets for the fabs when keyboard shows
The reason I'm on android 11's sdk in the first place Also gonna need a lot of checks because android just deprecated all the inset stuff for pre 11 Some of these changes actually optimzed the tab bar animations a lot
This commit is contained in:
parent
47c2f5f97f
commit
0fa3eef40e
@ -8,6 +8,7 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.util.TypedValue
|
||||
@ -20,12 +21,16 @@ import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewPropertyAnimator
|
||||
import android.view.WindowInsets
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.view.GestureDetectorCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsAnimationCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
@ -80,6 +85,7 @@ import eu.kanade.tachiyomi.util.moveCategories
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.system.getBottomGestureInsets
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.isImeVisible
|
||||
import eu.kanade.tachiyomi.util.system.launchUI
|
||||
import eu.kanade.tachiyomi.util.view.activityBinding
|
||||
import eu.kanade.tachiyomi.util.view.collapse
|
||||
@ -218,6 +224,28 @@ class LibraryController(
|
||||
)
|
||||
}
|
||||
|
||||
val cb = object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {
|
||||
override fun onStart(
|
||||
animation: WindowInsetsAnimationCompat,
|
||||
bounds: WindowInsetsAnimationCompat.BoundsCompat
|
||||
): WindowInsetsAnimationCompat.BoundsCompat {
|
||||
updateHopperY()
|
||||
return bounds
|
||||
}
|
||||
|
||||
override fun onProgress(
|
||||
insets: WindowInsetsCompat,
|
||||
runningAnimations: List<WindowInsetsAnimationCompat>
|
||||
): WindowInsetsCompat {
|
||||
updateHopperY(insets.toWindowInsets())
|
||||
return insets
|
||||
}
|
||||
|
||||
override fun onEnd(animation: WindowInsetsAnimationCompat) {
|
||||
updateHopperY()
|
||||
}
|
||||
}
|
||||
|
||||
private var scrollListener = object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
@ -536,6 +564,8 @@ class LibraryController(
|
||||
}
|
||||
setSwipeRefresh()
|
||||
|
||||
ViewCompat.setWindowInsetsAnimationCallback(view, cb)
|
||||
|
||||
if (selectedMangas.isNotEmpty()) {
|
||||
createActionModeIfNeeded()
|
||||
}
|
||||
@ -691,16 +721,21 @@ class LibraryController(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateHopperY() {
|
||||
fun updateHopperY(windowInsets: WindowInsets? = null) {
|
||||
val view = view ?: return
|
||||
val insets = windowInsets ?: view.rootWindowInsets
|
||||
val listOfYs = mutableListOf(
|
||||
binding.filterBottomSheet.filterBottomSheet.y,
|
||||
activityBinding?.bottomNav?.y ?: binding.filterBottomSheet.filterBottomSheet.y
|
||||
)
|
||||
val insetBottom = view.rootWindowInsets?.systemWindowInsetBottom ?: 0
|
||||
val insetBottom = insets?.systemWindowInsetBottom ?: 0
|
||||
if (!preferences.autohideHopper().get() || activityBinding?.bottomNav == null) {
|
||||
listOfYs.add(view.height - (insetBottom).toFloat())
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && insets?.isImeVisible() == true) {
|
||||
val insetKey = insets.getInsets(WindowInsets.Type.ime() or WindowInsets.Type.systemBars()).bottom
|
||||
listOfYs.add(view.height - (insetKey).toFloat())
|
||||
}
|
||||
binding.categoryHopperFrame.y = -binding.categoryHopperFrame.height +
|
||||
(listOfYs.minOrNull() ?: binding.filterBottomSheet.filterBottomSheet.y) +
|
||||
hopperOffset +
|
||||
|
@ -767,11 +767,15 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
|
||||
setFloatingToolbar(canShowFloatingToolbar(to))
|
||||
val onRoot = router.backstackSize == 1
|
||||
if (onRoot) {
|
||||
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R && !isPush) {
|
||||
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
|
||||
}
|
||||
binding.toolbar.navigationIcon = searchDrawable
|
||||
binding.cardToolbar.navigationIcon = searchDrawable
|
||||
} else {
|
||||
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
}
|
||||
binding.toolbar.navigationIcon = drawerArrow
|
||||
binding.cardToolbar.navigationIcon = drawerArrow
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package eu.kanade.tachiyomi.ui.source.browse
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
@ -35,6 +36,7 @@ import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
|
||||
import eu.kanade.tachiyomi.util.system.connectivityManager
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.view.applyBottomAnimatedInsets
|
||||
import eu.kanade.tachiyomi.util.view.inflate
|
||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
||||
@ -177,11 +179,14 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
recycler,
|
||||
true,
|
||||
afterInsets = { insets ->
|
||||
binding.fab.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
bottomMargin = insets.systemWindowInsetBottom + 16.dpToPx
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
binding.fab.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
bottomMargin = insets.systemWindowInsetBottom + 16.dpToPx
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
binding.fab.applyBottomAnimatedInsets(16.dpToPx)
|
||||
|
||||
recycler.addOnScrollListener(
|
||||
object : RecyclerView.OnScrollListener() {
|
||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.os.Build
|
||||
import android.view.WindowInsets
|
||||
import androidx.annotation.RequiresApi
|
||||
|
||||
fun WindowInsets.getBottomGestureInsets(): Int {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) mandatorySystemGestureInsets.bottom
|
||||
@ -20,3 +21,6 @@ fun WindowInsets.hasSideInsets() = systemWindowInsetLeft > 0 || systemWindowInse
|
||||
fun WindowInsets.hasSideNavBar() =
|
||||
(systemWindowInsetLeft > 0 || systemWindowInsetRight > 0) && !isBottomTappable() &&
|
||||
systemWindowInsetBottom == 0
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
fun WindowInsets.isImeVisible() = isVisible(WindowInsets.Type.ime())
|
||||
|
@ -113,7 +113,11 @@ fun Controller.liftAppbarWith(recycler: RecyclerView, padView: Boolean = false)
|
||||
val headerHeight = insets.systemWindowInsetTop + appBarHeight
|
||||
view.updatePaddingRelative(
|
||||
top = headerHeight,
|
||||
bottom = insets.systemWindowInsetBottom
|
||||
bottom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
insets.getInsets(WindowInsets.Type.ime() or WindowInsets.Type.systemBars()).bottom
|
||||
} else {
|
||||
insets.systemWindowInsetBottom
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -25,6 +25,8 @@ import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsAnimationCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller
|
||||
@ -121,6 +123,57 @@ object RecyclerWindowInsetsListener : View.OnApplyWindowInsetsListener {
|
||||
}
|
||||
}
|
||||
|
||||
fun View.applyBottomAnimatedInsets(bottomMargin: Int = 0) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return
|
||||
val setInsets: ((WindowInsets) -> Unit) = { insets ->
|
||||
updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
val bottom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
insets.getInsets(WindowInsets.Type.systemBars() or WindowInsets.Type.ime()).bottom
|
||||
} else {
|
||||
insets.systemWindowInsetBottom
|
||||
}
|
||||
this.bottomMargin = bottom + bottomMargin
|
||||
}
|
||||
}
|
||||
var handleInsets = true
|
||||
doOnApplyWindowInsets { _, insets, _ ->
|
||||
if (handleInsets) {
|
||||
setInsets(insets)
|
||||
}
|
||||
}
|
||||
|
||||
ViewCompat.setWindowInsetsAnimationCallback(
|
||||
this,
|
||||
object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {
|
||||
override fun onPrepare(animation: WindowInsetsAnimationCompat) {
|
||||
handleInsets = false
|
||||
super.onPrepare(animation)
|
||||
}
|
||||
|
||||
override fun onStart(
|
||||
animation: WindowInsetsAnimationCompat,
|
||||
bounds: WindowInsetsAnimationCompat.BoundsCompat
|
||||
): WindowInsetsAnimationCompat.BoundsCompat {
|
||||
handleInsets = false
|
||||
rootWindowInsets?.let { insets -> setInsets(insets) }
|
||||
return super.onStart(animation, bounds)
|
||||
}
|
||||
override fun onProgress(
|
||||
insets: WindowInsetsCompat,
|
||||
runningAnimations: List<WindowInsetsAnimationCompat>
|
||||
): WindowInsetsCompat {
|
||||
insets.toWindowInsets()?.let { setInsets(it) }
|
||||
return insets
|
||||
}
|
||||
|
||||
override fun onEnd(animation: WindowInsetsAnimationCompat) {
|
||||
handleInsets = true
|
||||
rootWindowInsets?.let { insets -> setInsets(insets) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
object ControllerViewWindowInsetsListener : View.OnApplyWindowInsetsListener {
|
||||
override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets {
|
||||
v.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
@ -155,6 +208,16 @@ fun View.doOnApplyWindowInsets(f: (View, WindowInsets, ViewPaddingState) -> Unit
|
||||
requestApplyInsetsWhenAttached()
|
||||
}
|
||||
|
||||
fun View.doOnApplyWindowInsetsCompat(f: (View, WindowInsetsCompat, ViewPaddingState) -> Unit) {
|
||||
// Create a snapshot of the view's padding state
|
||||
val paddingState = createStateForView(this)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
|
||||
f(v, insets, paddingState)
|
||||
insets
|
||||
}
|
||||
requestApplyInsetsWhenAttached()
|
||||
}
|
||||
|
||||
fun View.applyWindowInsetsForController() {
|
||||
setOnApplyWindowInsetsListener(ControllerViewWindowInsetsListener)
|
||||
requestApplyInsetsWhenAttached()
|
||||
|
Loading…
Reference in New Issue
Block a user