Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
package org.mozilla.fenix.utils
import android.view.View
import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.view.animation.Animation.AnimationListener
import android.view.animation.AnimationSet
import android.view.animation.TranslateAnimation
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.Easing
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.ui.unit.IntSize
import androidx.fragment.app.Fragment
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
const val DURATION_MS_SUB_MENU = 150
const val DELAY_MS_SUB_MENU = DURATION_MS_SUB_MENU - 10
const val DURATION_MS_MAIN_MENU = 75
const val DELAY_MS_MAIN_MENU = DURATION_MS_MAIN_MENU - 5
const val DURATION_MS_TRANSLATIONS = 140
const val DURATION_MS_MAIN_MENU_ITEM = 300
const val DELAY_MS_TRANSLATIONS = DURATION_MS_TRANSLATIONS - 10
private const val SLIDE_DOWN_ANIMATION_DURATION_MS = 150L
private const val SLIDE_DOWN_ANIMATION_ALPHA_DURATION_MS = 100L
/**
* [EnterTransition] when navigating to the main content sheet.
*/
fun enterMenu(duration: Int, delay: Int, easing: Easing = FastOutSlowInEasing): EnterTransition {
return fadeIn(
animationSpec = tween(
durationMillis = duration,
delayMillis = duration + delay,
easing = easing,
),
) + slideInHorizontally(
initialOffsetX = { fullWidth -> -fullWidth / 8 },
animationSpec = tween(
durationMillis = duration,
delayMillis = duration + delay,
easing = easing,
),
)
}
/**
* [ExitTransition] when navigating from the main content sheet.
*/
fun exitMenu(duration: Int, easing: Easing = FastOutSlowInEasing): ExitTransition {
return fadeOut(
animationSpec = tween(
durationMillis = duration,
easing = easing,
),
) + slideOutHorizontally(
targetOffsetX = { fullWidth -> -fullWidth / 8 },
animationSpec = tween(
durationMillis = duration,
easing = easing,
),
)
}
/**
* [EnterTransition] when navigating to the sub menu content sheet.
*/
fun enterSubmenu(duration: Int, delay: Int, easing: Easing = FastOutSlowInEasing): EnterTransition {
return fadeIn(
animationSpec = tween(
durationMillis = duration,
delayMillis = duration + delay,
easing = easing,
),
) + slideInHorizontally(
initialOffsetX = { fullWidth -> fullWidth / 8 },
animationSpec = tween(
durationMillis = duration,
delayMillis = duration + delay,
easing = easing,
),
)
}
/**
* [ExitTransition] when navigating from sub menu content sheet.
*/
fun exitSubmenu(duration: Int, easing: Easing = FastOutSlowInEasing): ExitTransition {
return fadeOut(
animationSpec = tween(
durationMillis = duration,
easing = easing,
),
) + slideOutHorizontally(
targetOffsetX = { fullWidth -> fullWidth / 8 },
animationSpec = tween(
durationMillis = duration,
easing = easing,
),
)
}
/**
* For use with [SizeTransform] to specify how the content should grow based on changes.
*/
fun contentGrowth(
initialSize: IntSize,
targetSize: IntSize,
duration: Int,
): FiniteAnimationSpec<IntSize> {
return keyframes {
// Time the total animations should play
durationMillis = duration * 2
// Stay at the same size for the first duration
IntSize(targetSize.width, initialSize.height) at duration
// At the next duration, grow to full height.
IntSize(targetSize.width, targetSize.height) at duration * 2
}
}
/**
* Fragment animation when navigating a [BottomSheetDialogFragment] to other [Fragment].
*/
@Suppress("EmptyFunctionBlock")
fun View.slideDown(
endOfAnimationCallback: () -> Unit,
) {
val animationSet = AnimationSet(false)
val translateAnimation = TranslateAnimation(0f, 0f, 0f, this.height.toFloat())
translateAnimation.duration = SLIDE_DOWN_ANIMATION_DURATION_MS
val alphaAnimation = AlphaAnimation(1f, 0f)
alphaAnimation.duration = SLIDE_DOWN_ANIMATION_ALPHA_DURATION_MS
animationSet.addAnimation(translateAnimation)
animationSet.addAnimation(alphaAnimation)
animationSet.setAnimationListener(
object : AnimationListener {
override fun onAnimationStart(p0: Animation?) {}
override fun onAnimationEnd(p0: Animation?) {
endOfAnimationCallback()
}
override fun onAnimationRepeat(p0: Animation?) {}
},
)
this.startAnimation(animationSet)
}