Add back pressed animation + update controller push/pop animation

Likely am gonna revert for the stable just to save myself the headache

Limiting the new animations to Android 10+, new animations will still play on 10+ devices, but wont keep the view on low ram devices
This commit is contained in:
Jays2Kings 2023-10-16 20:26:51 -07:00
parent a6c49f0970
commit 59e11ff486
12 changed files with 224 additions and 70 deletions

View file

@ -269,9 +269,9 @@ dependencies {
implementation("com.getkeepsafe.taptargetview:taptargetview:1.13.3")
// Conductor
val conductorVersion = "3.0.0"
val conductorVersion = "4.0.0-preview-3"
implementation("com.bluelinelabs:conductor:$conductorVersion")
implementation("com.github.tachiyomiorg:conductor-support-preference:$conductorVersion")
implementation("com.github.tachiyomiorg:conductor-support-preference:3.0.0")
// Shizuku
val shizukuVersion = "12.1.0"

View file

@ -8,7 +8,6 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.BackEventCompat
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.forEach
import androidx.core.view.isVisible
@ -18,6 +17,7 @@ import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.view.BackHandlerControllerInterface
import eu.kanade.tachiyomi.util.view.activityBinding
import eu.kanade.tachiyomi.util.view.isControllerVisible
import eu.kanade.tachiyomi.util.view.removeQueryListener
@ -27,7 +27,7 @@ import kotlinx.coroutines.cancel
import timber.log.Timber
abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
Controller(bundle) {
Controller(bundle), BackHandlerControllerInterface {
lateinit var binding: VB
lateinit var viewScope: CoroutineScope
@ -72,12 +72,14 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
open fun onViewCreated(view: View) { }
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
if (type.isEnter) {
if (type.isEnter && isControllerVisible) {
setTitle()
} else if (type.isEnter) {
view?.alpha = 0f
} else {
removeQueryListener()
}
setHasOptionsMenu(type.isEnter)
setHasOptionsMenu(type.isEnter && isControllerVisible)
super.onChangeStarted(handler, type)
}
@ -95,12 +97,6 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
open fun canStillGoBack(): Boolean { return false }
open fun handleOnBackStarted(backEvent: BackEventCompat) {}
open fun handleOnBackProgressed(backEvent: BackEventCompat) {}
open fun handleOnBackCancelled() {}
open val mainRecycler: RecyclerView?
get() = null

View file

@ -0,0 +1,61 @@
package eu.kanade.tachiyomi.ui.base.controller
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.view.View
import android.view.ViewGroup
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.changehandler.AnimatorChangeHandler
class CrossFadeChangeHandler : AnimatorChangeHandler {
constructor() : super()
constructor(removesFromViewOnPush: Boolean) : super(removesFromViewOnPush)
constructor(duration: Long) : super(duration)
constructor(duration: Long, removesFromViewOnPush: Boolean) : super(
duration,
removesFromViewOnPush,
)
override fun getAnimator(
container: ViewGroup,
from: View?,
to: View?,
isPush: Boolean,
toAddedToContainer: Boolean,
): Animator {
val animatorSet = AnimatorSet()
if (to != null) {
val start = if (toAddedToContainer) 0F else to.alpha
animatorSet.play(ObjectAnimator.ofFloat(to, View.ALPHA, start, 1f))
}
if (from != null) {
animatorSet.play(ObjectAnimator.ofFloat(from, View.ALPHA, 0f))
}
if (isPush) {
if (from != null) {
animatorSet.play(ObjectAnimator.ofFloat(from, View.TRANSLATION_X, -from.width.toFloat() * 0.2f))
}
if (to != null) {
animatorSet.play(ObjectAnimator.ofFloat(to, View.TRANSLATION_X, to.width.toFloat() * 0.2f, 0f))
}
} else {
if (from != null) {
animatorSet.play(ObjectAnimator.ofFloat(from, View.TRANSLATION_X, from.width.toFloat() * 0.2f))
}
if (to != null) {
// Allow this to have a nice transition when coming off an aborted push animation
val fromLeft = from?.translationX ?: 0F
animatorSet.play(ObjectAnimator.ofFloat(to, View.TRANSLATION_X, fromLeft - to.width * 0.2f, 0f))
}
}
return animatorSet
}
override fun resetFromView(from: View) {
from.translationX = 0f
}
override fun copy(): ControllerChangeHandler =
CrossFadeChangeHandler(animationDuration, removesFromViewOnPush)
}

View file

@ -6,12 +6,13 @@ import android.animation.ObjectAnimator
import android.view.View
import android.view.ViewGroup
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.changehandler.AnimatorChangeHandler
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
/**
* A variation of [FadeChangeHandler] that only fades in.
*/
class OneWayFadeChangeHandler : FadeChangeHandler {
class OneWayFadeChangeHandler : AnimatorChangeHandler {
constructor()
constructor(removesFromViewOnPush: Boolean) : super(removesFromViewOnPush)
constructor(duration: Long) : super(duration)
@ -20,7 +21,6 @@ class OneWayFadeChangeHandler : FadeChangeHandler {
removesFromViewOnPush,
)
var fadeOut = true
override fun getAnimator(
container: ViewGroup,
from: View?,
@ -34,17 +34,17 @@ class OneWayFadeChangeHandler : FadeChangeHandler {
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, start, 1f))
}
if (from != null && (!isPush || removesFromViewOnPush())) {
if (fadeOut) {
animator.play(ObjectAnimator.ofFloat(from, View.ALPHA, 0f))
} else {
container.removeView(from)
}
if (from != null && (!isPush || removesFromViewOnPush)) {
container.removeView(from)
}
return animator
}
override fun resetFromView(from: View) {
from.alpha = 1f
}
override fun copy(): ControllerChangeHandler {
return OneWayFadeChangeHandler(animationDuration, removesFromViewOnPush())
return OneWayFadeChangeHandler(animationDuration, removesFromViewOnPush)
}
}

View file

@ -27,7 +27,6 @@ import android.view.Window
import android.view.WindowManager
import androidx.activity.BackEventCompat
import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.IdRes
import androidx.appcompat.view.ActionMode
@ -115,6 +114,7 @@ import eu.kanade.tachiyomi.util.system.materialAlertDialog
import eu.kanade.tachiyomi.util.system.prepareSideNavContext
import eu.kanade.tachiyomi.util.system.rootWindowInsetsCompat
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.BackHandlerControllerInterface
import eu.kanade.tachiyomi.util.view.backgroundColor
import eu.kanade.tachiyomi.util.view.blurBehindWindow
import eu.kanade.tachiyomi.util.view.canStillGoBack
@ -212,7 +212,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
get() = max(binding.toolbar.height, binding.cardFrame.height, binding.appBar.attrToolbarHeight)
private var actionMode: ActionMode? = null
var backPressedCallback: OnBackPressedCallback? = null
private var backPressedCallback: OnBackPressedCallback? = null
private val backCallback = {
pressingBack()
reEnableBackPressedCallBack()
@ -253,23 +253,41 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
super.onCreate(savedInstanceState)
backPressedCallback = object : OnBackPressedCallback(enabled = true) {
var controllerHandlesBackPress = false
override fun handleOnBackPressed() {
backCallback()
}
override fun handleOnBackStarted(backEvent: BackEventCompat) {
val controller = router.backstack.lastOrNull()?.controller as? BaseController<*>
controller?.handleOnBackStarted(backEvent)
controllerHandlesBackPress = false
if (!(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
ViewCompat.getRootWindowInsets(window.decorView)
?.isVisible(WindowInsetsCompat.Type.ime()) == true
) &&
actionMode == null &&
!(binding.searchToolbar.hasExpandedActionView() && binding.cardFrame.isVisible)
) {
controllerHandlesBackPress = true
}
if (controllerHandlesBackPress) {
val controller = router.backstack.lastOrNull()?.controller as? BackHandlerControllerInterface
controller?.handleOnBackStarted(backEvent)
}
}
override fun handleOnBackProgressed(backEvent: BackEventCompat) {
val controller = router.backstack.lastOrNull()?.controller as? BaseController<*>
controller?.handleOnBackProgressed(backEvent)
if (controllerHandlesBackPress) {
val controller = router.backstack.lastOrNull()?.controller as? BackHandlerControllerInterface
controller?.handleOnBackProgressed(backEvent)
}
}
override fun handleOnBackCancelled() {
val controller = router.backstack.lastOrNull()?.controller as? BaseController<*>
controller?.handleOnBackCancelled()
if (controllerHandlesBackPress) {
val controller = router.backstack.lastOrNull()?.controller as? BackHandlerControllerInterface
controller?.handleOnBackCancelled()
}
}
}
onBackPressedDispatcher.addCallback(backPressedCallback!!)
@ -501,6 +519,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
container: ViewGroup,
handler: ControllerChangeHandler,
) {
to?.view?.alpha = 1f
syncActivityViewWithController(to, from, isPush)
binding.appBar.isVisible = true
binding.appBar.alpha = 1f
@ -519,6 +538,9 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
) {
nav.translationY = 0f
showDLQueueTutorial()
if (!(from is DialogController || to is DialogController) && from != null) {
from.view?.alpha = 0f
}
if (router.backstackSize == 1) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R && !isPush) {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
@ -705,8 +727,8 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
if (insets == null) return
window.navigationBarColor = when {
Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1 -> {
// basically if in landscape on a phone
// For lollipop, draw opaque nav bar
// basically if in landscape on a phone, solid black bar
// otherwise translucent dark theme or black if light theme
when {
insets.hasSideNavBar() -> Color.BLACK
isInNightMode() -> ColorUtils.setAlphaComponent(

View file

@ -661,10 +661,12 @@ class MangaDetailsController :
super.onChangeStarted(handler, type)
isPushing = true
if (type.isEnter) {
activityBinding?.appBar?.y = 0f
activityBinding?.appBar?.updateAppBarAfterY(binding.recycler)
updateToolbarTitleAlpha(0f)
setStatusBarAndToolbar()
if (isControllerVisible) {
activityBinding?.appBar?.y = 0f
activityBinding?.appBar?.updateAppBarAfterY(binding.recycler)
updateToolbarTitleAlpha(0f)
setStatusBarAndToolbar()
}
} else {
if (router.backstack.lastOrNull()?.controller is DialogController) {
return

View file

@ -495,12 +495,16 @@ class RecentsController(bundle: Bundle? = null) :
override fun handleOnBackProgressed(backEvent: BackEventCompat) {
if (showingDownloads) {
binding.downloadBottomSheet.dlBottomSheet.sheetBehavior?.updateBackProgress(backEvent)
} else {
super.handleOnBackProgressed(backEvent)
}
}
override fun handleOnBackCancelled() {
if (showingDownloads) {
binding.downloadBottomSheet.dlBottomSheet.sheetBehavior?.cancelBackProgress()
} else {
super.handleOnBackCancelled()
}
}
@ -889,30 +893,33 @@ class RecentsController(bundle: Bundle? = null) :
if (type.isEnter) {
if (type == ControllerChangeType.POP_ENTER) presenter.onCreate()
binding.downloadBottomSheet.dlBottomSheet.dismiss()
activityBinding?.mainTabs?.let { tabs ->
tabs.removeAllTabs()
tabs.clearOnTabSelectedListeners()
val selectedTab = presenter.viewType
RecentsViewType.entries.forEach { viewType ->
tabs.addTab(
tabs.newTab().setText(viewType.stringRes).also { tab ->
tab.view.compatToolTipText = null
if (isControllerVisible) {
activityBinding?.mainTabs?.let { tabs ->
tabs.removeAllTabs()
tabs.clearOnTabSelectedListeners()
val selectedTab = presenter.viewType
RecentsViewType.entries.forEach { viewType ->
tabs.addTab(
tabs.newTab().setText(viewType.stringRes).also { tab ->
tab.view.compatToolTipText = null
},
viewType == selectedTab,
)
}
tabs.addOnTabSelectedListener(
object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
setViewType(RecentsViewType.valueOf(tab?.position))
}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabReselected(tab: TabLayout.Tab?) {
binding.recycler.smoothScrollToTop()
}
},
viewType == selectedTab,
)
(activity as? MainActivity)?.showTabBar(true)
}
tabs.addOnTabSelectedListener(
object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
setViewType(RecentsViewType.valueOf(tab?.position))
}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabReselected(tab: TabLayout.Tab?) {
binding.recycler.smoothScrollToTop()
}
},
)
(activity as? MainActivity)?.showTabBar(true)
}
} else {
val lastController = router.backstack.lastOrNull()?.controller
@ -929,7 +936,7 @@ class RecentsController(bundle: Bundle? = null) :
if (type == ControllerChangeType.POP_ENTER) {
setBottomPadding()
}
if (type.isEnter) {
if (type.isEnter && isControllerVisible) {
updateTitleAndMenu()
}
}

View file

@ -26,7 +26,10 @@ import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.BackHandlerControllerInterface
import eu.kanade.tachiyomi.util.view.activityBinding
import eu.kanade.tachiyomi.util.view.backgroundColor
import eu.kanade.tachiyomi.util.view.isControllerVisible
import eu.kanade.tachiyomi.util.view.scrollViewWith
import eu.kanade.tachiyomi.widget.LinearLayoutManagerAccurateOffset
import kotlinx.coroutines.MainScope
@ -34,7 +37,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.Locale
abstract class SettingsController : PreferenceController() {
abstract class SettingsController : PreferenceController(), BackHandlerControllerInterface {
var preferenceKey: String? = null
val preferences: PreferencesHelper = Injekt.get()
@ -47,6 +50,7 @@ abstract class SettingsController : PreferenceController() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
val view = super.onCreateView(inflater, container, savedInstanceState)
view.backgroundColor = view.context.getResourceColor(R.attr.background)
scrollViewWith(listView, padBottom = true)
return view
}
@ -123,10 +127,12 @@ abstract class SettingsController : PreferenceController() {
}
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
if (type.isEnter) {
if (type.isEnter && isControllerVisible) {
setTitle()
} else if (type.isEnter) {
view?.alpha = 0f
}
setHasOptionsMenu(type.isEnter)
setHasOptionsMenu(type.isEnter && isControllerVisible)
super.onChangeStarted(handler, type)
}

View file

@ -358,7 +358,7 @@ class BrowseController :
val controller = ExtensionFilterController()
router.pushController(
RouterTransaction.with(controller)
.popChangeHandler(SettingsSourcesFadeChangeHandler())
.popChangeHandler(FadeChangeHandler())
.pushChangeHandler(FadeChangeHandler()),
)
}
@ -494,12 +494,16 @@ class BrowseController :
override fun handleOnBackProgressed(backEvent: BackEventCompat) {
if (showingExtensions && !binding.bottomSheet.root.canStillGoBack()) {
binding.bottomSheet.root.sheetBehavior?.updateBackProgress(backEvent)
} else {
super.handleOnBackProgressed(backEvent)
}
}
override fun handleOnBackCancelled() {
if (showingExtensions && !binding.bottomSheet.root.canStillGoBack()) {
binding.bottomSheet.root.sheetBehavior?.cancelBackProgress()
} else {
super.handleOnBackCancelled()
}
}
@ -531,7 +535,7 @@ class BrowseController :
binding.bottomSheet.root.updateExtTitle()
binding.bottomSheet.root.presenter.refreshExtensions()
presenter.updateSources()
if (type.isEnter) {
if (type.isEnter && isControllerVisible) {
activityBinding?.appBar?.doOnNextLayout {
activityBinding?.appBar?.y = 0f
activityBinding?.appBar?.updateAppBarAfterY(binding.sourceRecycler)
@ -696,7 +700,7 @@ class BrowseController :
val controller = SettingsSourcesController()
router.pushController(
RouterTransaction.with(controller)
.popChangeHandler(SettingsSourcesFadeChangeHandler())
.popChangeHandler(FadeChangeHandler())
.pushChangeHandler(FadeChangeHandler()),
)
}
@ -733,8 +737,6 @@ class BrowseController :
}
}
class SettingsSourcesFadeChangeHandler : FadeChangeHandler()
@Parcelize
data class SmartSearchConfig(val origTitle: String, val origMangaId: Long) : Parcelable

View file

@ -26,6 +26,7 @@ import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
import eu.kanade.tachiyomi.util.system.rootWindowInsetsCompat
import eu.kanade.tachiyomi.util.view.activityBinding
import eu.kanade.tachiyomi.util.view.isControllerVisible
import eu.kanade.tachiyomi.util.view.scrollViewWith
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
import eu.kanade.tachiyomi.util.view.snack
@ -169,7 +170,7 @@ open class GlobalSearchController(
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeStarted(handler, type)
if (type.isEnter) {
if (type.isEnter && isControllerVisible) {
val searchView = activityBinding?.searchToolbar?.searchView ?: return
val searchItem = activityBinding?.searchToolbar?.searchItem ?: return
searchItem.expandActionView()

View file

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.util.view
import android.Manifest
import android.animation.Animator
import android.animation.ValueAnimator
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@ -18,10 +19,13 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.activity.BackEventCompat
import androidx.annotation.CallSuper
import androidx.annotation.MainThread
import androidx.appcompat.widget.SearchView
import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.graphics.ColorUtils
import androidx.core.math.MathUtils
import androidx.core.net.toUri
@ -45,6 +49,7 @@ import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
@ -52,6 +57,7 @@ import eu.kanade.tachiyomi.databinding.MainActivityBinding
import eu.kanade.tachiyomi.ui.base.SmallToolbarInterface
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.CrossFadeChangeHandler
import eu.kanade.tachiyomi.ui.base.controller.OneWayFadeChangeHandler
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
@ -70,6 +76,7 @@ import eu.kanade.tachiyomi.widget.StatefulNestedScrollView
import uy.kohesive.injekt.injectLazy
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.random.Random
@ -664,7 +671,9 @@ fun Controller.moveRecyclerViewUp(allTheWayUp: Boolean = false, scrollUpAnyway:
val recycler = mainRecyclerView ?: return
val activityBinding = activityBinding ?: return
val appBarOffset = activityBinding.appBar.toolbarDistanceToTop
if (allTheWayUp && recycler.computeVerticalScrollOffset() - recycler.paddingTop <= fullAppBarHeight ?: activityBinding.appBar.preLayoutHeight) {
if (allTheWayUp && recycler.computeVerticalScrollOffset() - recycler.paddingTop <=
(fullAppBarHeight ?: activityBinding.appBar.preLayoutHeight)
) {
(recycler.layoutManager as? LinearLayoutManager)?.scrollToPosition(0)
(recycler.layoutManager as? StaggeredGridLayoutManager)?.scrollToPosition(0)
recycler.post {
@ -782,14 +791,27 @@ fun Controller.requestFilePermissionsSafe(
}
fun Controller.withFadeTransaction(): RouterTransaction {
val isLowRam by lazy { activity?.getSystemService<ActivityManager>()?.isLowRamDevice == true }
return RouterTransaction.with(this)
.pushChangeHandler(OneWayFadeChangeHandler())
.popChangeHandler(OneWayFadeChangeHandler())
.pushChangeHandler(
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
FadeChangeHandler()
} else {
CrossFadeChangeHandler(duration = 250, removesFromViewOnPush = isLowRam)
},
)
.popChangeHandler(
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
FadeChangeHandler()
} else {
CrossFadeChangeHandler(duration = 150, removesFromViewOnPush = isLowRam)
},
)
}
fun Controller.withFadeInTransaction(): RouterTransaction {
return RouterTransaction.with(this)
.pushChangeHandler(OneWayFadeChangeHandler().apply { fadeOut = false })
.pushChangeHandler(FadeChangeHandler())
.popChangeHandler(OneWayFadeChangeHandler())
}
@ -830,3 +852,37 @@ fun Router.canStillGoBack(): Boolean {
}
return false
}
interface BackHandlerControllerInterface {
fun handleOnBackStarted(backEvent: BackEventCompat) {
}
@CallSuper
fun handleOnBackProgressed(backEvent: BackEventCompat) {
if (this !is Controller) return
if (router.backstackSize > 1) {
val progress = ((backEvent.progress.takeIf { it > 0.001f } ?: 0f) * 0.5f).pow(0.6f)
view?.let { view ->
view.alpha = 1f - progress
view.x = progress * view.width * 0.15f
router.backstack[router.backstackSize - 2].controller.view?.let { view2 ->
view2.alpha = progress
view2.x = view.x - view.width * 0.2f
}
}
}
}
@CallSuper
fun handleOnBackCancelled() {
if (this !is Controller) return
view?.alpha = 1f
view?.x = 0f
if (router.backstackSize > 1) {
router.backstack[router.backstackSize - 2].controller.view?.let { view ->
view.alpha = 0f
view.x = 0f
}
}
}
}

View file

@ -3,6 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?background"
android:layout_width="match_parent"
android:id="@+id/source_layout"
android:layout_height="match_parent">