For #167: Adds browser -> home animation
parent
b717926f72
commit
8e06933e8d
|
@ -168,7 +168,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
swipeRefresh = WeakReference(swipeRefresh),
|
swipeRefresh = WeakReference(swipeRefresh),
|
||||||
arguments = arguments!!
|
arguments = arguments!!
|
||||||
).apply {
|
).apply {
|
||||||
beginAnimationIfNecessary()
|
beginAnimateInIfNecessary()
|
||||||
}
|
}
|
||||||
|
|
||||||
return getSessionById()?.also { session ->
|
return getSessionById()?.also { session ->
|
||||||
|
|
|
@ -41,17 +41,34 @@ class BrowserAnimator(
|
||||||
private val unwrappedSwipeRefresh: View?
|
private val unwrappedSwipeRefresh: View?
|
||||||
get() = swipeRefresh.get()
|
get() = swipeRefresh.get()
|
||||||
|
|
||||||
|
private val browserInValueAnimator = ValueAnimator.ofFloat(0f, END_ANIMATOR_VALUE).apply {
|
||||||
|
addUpdateListener {
|
||||||
|
unwrappedSwipeRefresh?.scaleX = STARTING_XY_SCALE + XY_SCALE_MULTIPLIER * it.animatedFraction
|
||||||
|
unwrappedSwipeRefresh?.scaleY = STARTING_XY_SCALE + XY_SCALE_MULTIPLIER * it.animatedFraction
|
||||||
|
unwrappedSwipeRefresh?.alpha = it.animatedFraction
|
||||||
|
}
|
||||||
|
|
||||||
|
doOnEnd {
|
||||||
|
unwrappedEngineView?.asView()?.visibility = View.VISIBLE
|
||||||
|
unwrappedSwipeRefresh?.background = null
|
||||||
|
arguments.putBoolean(SHOULD_ANIMATE_FLAG, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
interpolator = DecelerateInterpolator()
|
||||||
|
duration = ANIMATION_DURATION
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers the browser animation to run if necessary (based on the SHOULD_ANIMATE_FLAG). Also
|
* Triggers the *in* browser animation to run if necessary (based on the SHOULD_ANIMATE_FLAG). Also
|
||||||
* removes the flag from the bundle so it is not played on future entries into the fragment.
|
* removes the flag from the bundle so it is not played on future entries into the fragment.
|
||||||
*/
|
*/
|
||||||
fun beginAnimationIfNecessary() {
|
fun beginAnimateInIfNecessary() {
|
||||||
val shouldAnimate = arguments.getBoolean(SHOULD_ANIMATE_FLAG, false)
|
val shouldAnimate = arguments.getBoolean(SHOULD_ANIMATE_FLAG, false)
|
||||||
if (shouldAnimate) {
|
if (shouldAnimate) {
|
||||||
viewLifeCycleScope?.launch(Dispatchers.Main) {
|
viewLifeCycleScope?.launch(Dispatchers.Main) {
|
||||||
delay(ANIMATION_DELAY)
|
delay(ANIMATION_DELAY)
|
||||||
captureEngineViewAndDrawStatically {
|
captureEngineViewAndDrawStatically {
|
||||||
animateBrowserEngine(unwrappedSwipeRefresh)
|
browserInValueAnimator.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,26 +79,15 @@ class BrowserAnimator(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Details exactly how the browserEngine animation should look and plays it.
|
* Triggers the *out* browser animation to run.
|
||||||
*/
|
*/
|
||||||
private fun animateBrowserEngine(browserEngine: View?) {
|
fun beginAnimateOut() {
|
||||||
val valueAnimator = ValueAnimator.ofFloat(0f, END_ANIMATOR_VALUE)
|
viewLifeCycleScope?.launch(Dispatchers.Main) {
|
||||||
|
captureEngineViewAndDrawStatically {
|
||||||
valueAnimator.addUpdateListener {
|
unwrappedEngineView?.asView()?.visibility = View.GONE
|
||||||
browserEngine?.scaleX = STARTING_XY_SCALE + XY_SCALE_MULTIPLIER * it.animatedFraction
|
browserInValueAnimator.reverse()
|
||||||
browserEngine?.scaleY = STARTING_XY_SCALE + XY_SCALE_MULTIPLIER * it.animatedFraction
|
}
|
||||||
browserEngine?.alpha = it.animatedFraction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
valueAnimator.doOnEnd {
|
|
||||||
unwrappedEngineView?.asView()?.visibility = View.VISIBLE
|
|
||||||
unwrappedSwipeRefresh?.background = null
|
|
||||||
arguments.putBoolean(SHOULD_ANIMATE_FLAG, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
valueAnimator.interpolator = DecelerateInterpolator()
|
|
||||||
valueAnimator.duration = ANIMATION_DURATION
|
|
||||||
valueAnimator.start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
|
@ -300,7 +301,11 @@ class DefaultBrowserToolbarController(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun animateTabAndNavigateHome() {
|
private fun animateTabAndNavigateHome() {
|
||||||
browserAnimator.captureEngineViewAndDrawStatically {
|
scope.launch {
|
||||||
|
browserAnimator.beginAnimateOut()
|
||||||
|
// Delay for a short amount of time so the browser has time to start animating out
|
||||||
|
// before we transition the fragment. This makes the animation feel smoother
|
||||||
|
delay(ANIMATION_DELAY)
|
||||||
if (!navController.popBackStack(R.id.homeFragment, false)) {
|
if (!navController.popBackStack(R.id.homeFragment, false)) {
|
||||||
val directions = BrowserFragmentDirections.actionBrowserFragmentToHomeFragment()
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToHomeFragment()
|
||||||
navController.nav(
|
navController.nav(
|
||||||
|
@ -356,8 +361,7 @@ class DefaultBrowserToolbarController(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@VisibleForTesting
|
const val ANIMATION_DELAY = 50L
|
||||||
const val TAB_ITEM_TRANSITION_NAME = "tab_item"
|
|
||||||
internal const val TELEMETRY_BROWSER_IDENTIFIER = "browserMenu"
|
internal const val TELEMETRY_BROWSER_IDENTIFIER = "browserMenu"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!-- 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
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:interpolator/decelerate_cubic"
|
||||||
|
android:fromAlpha="0" android:toAlpha="1"
|
||||||
|
android:duration="175" />
|
||||||
|
<scale
|
||||||
|
android:interpolator="@android:interpolator/decelerate_cubic"
|
||||||
|
android:pivotX="50%"
|
||||||
|
android:pivotY="50%"
|
||||||
|
android:fromXScale="108%"
|
||||||
|
android:toXScale="100%"
|
||||||
|
android:fromYScale="108%"
|
||||||
|
android:toYScale="100%"
|
||||||
|
android:duration="175" />
|
||||||
|
</set>
|
|
@ -58,6 +58,7 @@
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/homeFragment"
|
android:id="@+id/homeFragment"
|
||||||
android:name="org.mozilla.fenix.home.HomeFragment"
|
android:name="org.mozilla.fenix.home.HomeFragment"
|
||||||
|
app:enterAnim="@anim/zoom_out_fade"
|
||||||
tools:layout="@layout/fragment_home">
|
tools:layout="@layout/fragment_home">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_homeFragment_to_turnOnSyncFragment"
|
android:id="@+id/action_homeFragment_to_turnOnSyncFragment"
|
||||||
|
@ -76,7 +77,7 @@
|
||||||
android:id="@+id/action_homeFragment_to_browserFragment"
|
android:id="@+id/action_homeFragment_to_browserFragment"
|
||||||
app:destination="@id/browserFragment"
|
app:destination="@id/browserFragment"
|
||||||
app:exitAnim="@anim/zoom_in_fade"
|
app:exitAnim="@anim/zoom_in_fade"
|
||||||
app:popEnterAnim="@anim/fade_in" />
|
app:popEnterAnim="@anim/zoom_out_fade" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_homeFragment_to_libraryFragment"
|
android:id="@+id/action_homeFragment_to_libraryFragment"
|
||||||
app:destination="@id/libraryFragment" />
|
app:destination="@id/libraryFragment" />
|
||||||
|
|
Loading…
Reference in New Issue