parent
89a260ecd9
commit
3548e58c00
|
@ -41,7 +41,7 @@ class BrowserAnimator(
|
|||
private val unwrappedSwipeRefresh: View?
|
||||
get() = swipeRefresh.get()
|
||||
|
||||
private val browserInValueAnimator = ValueAnimator.ofFloat(0f, END_ANIMATOR_VALUE).apply {
|
||||
private val browserZoomInValueAnimator = 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
|
||||
|
@ -58,9 +58,24 @@ class BrowserAnimator(
|
|||
duration = ANIMATION_DURATION
|
||||
}
|
||||
|
||||
private val browserFadeInValueAnimator = ValueAnimator.ofFloat(0f, END_ANIMATOR_VALUE).apply {
|
||||
addUpdateListener {
|
||||
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 *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.
|
||||
* Triggers the *zoom 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.
|
||||
*/
|
||||
fun beginAnimateInIfNecessary() {
|
||||
val shouldAnimate = arguments.getBoolean(SHOULD_ANIMATE_FLAG, false)
|
||||
|
@ -68,7 +83,7 @@ class BrowserAnimator(
|
|||
viewLifeCycleScope?.launch(Dispatchers.Main) {
|
||||
delay(ANIMATION_DELAY)
|
||||
captureEngineViewAndDrawStatically {
|
||||
browserInValueAnimator.start()
|
||||
browserZoomInValueAnimator.start()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -79,13 +94,25 @@ class BrowserAnimator(
|
|||
}
|
||||
|
||||
/**
|
||||
* Triggers the *out* browser animation to run.
|
||||
* Triggers the *zoom out* browser animation to run.
|
||||
*/
|
||||
fun beginAnimateOut() {
|
||||
viewLifeCycleScope?.launch(Dispatchers.Main) {
|
||||
captureEngineViewAndDrawStatically {
|
||||
unwrappedEngineView?.asView()?.visibility = View.GONE
|
||||
browserInValueAnimator.reverse()
|
||||
browserZoomInValueAnimator.reverse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the *fade out* browser animation to run.
|
||||
*/
|
||||
fun beginFadeOut() {
|
||||
viewLifeCycleScope?.launch(Dispatchers.Main) {
|
||||
captureEngineViewAndDrawStatically {
|
||||
unwrappedEngineView?.asView()?.visibility = View.GONE
|
||||
browserFadeInValueAnimator.reverse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,8 +51,6 @@ interface BrowserToolbarController {
|
|||
fun handleTabCounterClick()
|
||||
}
|
||||
|
||||
typealias onComplete = () -> Unit
|
||||
|
||||
@Suppress("LargeClass")
|
||||
class DefaultBrowserToolbarController(
|
||||
private val store: BrowserFragmentStore,
|
||||
|
|
|
@ -7,6 +7,9 @@ package org.mozilla.fenix.search
|
|||
|
||||
import android.content.Context
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.search.SearchEngine
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.support.ktx.kotlin.isUrl
|
||||
|
@ -41,7 +44,9 @@ interface SearchController {
|
|||
class DefaultSearchController(
|
||||
private val context: Context,
|
||||
private val store: SearchFragmentStore,
|
||||
private val navController: NavController
|
||||
private val navController: NavController,
|
||||
private val lifecycleScope: CoroutineScope,
|
||||
private val clearToolbarFocus: () -> Unit
|
||||
) : SearchController {
|
||||
|
||||
override fun handleUrlCommitted(url: String) {
|
||||
|
@ -75,7 +80,13 @@ class DefaultSearchController(
|
|||
}
|
||||
|
||||
override fun handleEditingCancelled() {
|
||||
navController.navigateUp()
|
||||
lifecycleScope.launch {
|
||||
clearToolbarFocus()
|
||||
// Delay a short amount so the keyboard begins animating away. This makes exit animation
|
||||
// much smoother instead of having two separate parts (keyboard hides THEN animation)
|
||||
delay(KEYBOARD_ANIMATION_DELAY)
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleTextChanged(text: String) {
|
||||
|
@ -164,4 +175,8 @@ class DefaultSearchController(
|
|||
handleExistingSessionSelected(session)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val KEYBOARD_ANIMATION_DELAY = 5L
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import android.view.ViewStub
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.transition.TransitionInflater
|
||||
|
@ -112,9 +113,11 @@ class SearchFragment : Fragment(), UserInteractionHandler {
|
|||
}
|
||||
|
||||
val searchController = DefaultSearchController(
|
||||
activity as HomeActivity,
|
||||
searchStore,
|
||||
findNavController()
|
||||
context = activity as HomeActivity,
|
||||
store = searchStore,
|
||||
navController = findNavController(),
|
||||
lifecycleScope = viewLifecycleOwner.lifecycleScope,
|
||||
clearToolbarFocus = ::clearToolbarFocus
|
||||
)
|
||||
|
||||
searchInteractor = SearchInteractor(
|
||||
|
@ -139,6 +142,10 @@ class SearchFragment : Fragment(), UserInteractionHandler {
|
|||
return view
|
||||
}
|
||||
|
||||
private fun clearToolbarFocus() {
|
||||
toolbarView.view.clearFocus()
|
||||
}
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
@SuppressWarnings("LongMethod")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
@ -286,6 +293,7 @@ class SearchFragment : Fragment(), UserInteractionHandler {
|
|||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
// Note: Actual navigation happens in `handleEditingCancelled` in SearchController
|
||||
return when {
|
||||
qrFeature.onBackPressed() -> {
|
||||
view?.search_scan_button?.isChecked = false
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:interpolator/decelerate_quad"
|
||||
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||
android:duration="150" />
|
||||
android:duration="250" />
|
|
@ -0,0 +1,14 @@
|
|||
<!-- 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_quad"
|
||||
android:fromAlpha="0" android:toAlpha="1"
|
||||
android:duration="125" />
|
||||
<translate
|
||||
android:interpolator="@android:interpolator/decelerate_quad"
|
||||
android:fromYDelta="7%" android:toYDelta="0%"
|
||||
android:duration="125"/>
|
||||
</set>
|
|
@ -5,4 +5,4 @@
|
|||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:interpolator/accelerate_quad"
|
||||
android:fromAlpha="1.0" android:toAlpha="0"
|
||||
android:duration="150" />
|
||||
android:duration="250" />
|
|
@ -0,0 +1,14 @@
|
|||
<!-- 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/accelerate_quad"
|
||||
android:fromAlpha="1" android:toAlpha="0"
|
||||
android:duration="125" />
|
||||
<translate
|
||||
android:interpolator="@android:interpolator/accelerate_quad"
|
||||
android:fromYDelta="0%" android:toYDelta="7%"
|
||||
android:duration="125"/>
|
||||
</set>
|
|
@ -177,12 +177,15 @@
|
|||
<fragment
|
||||
android:id="@+id/browserFragment"
|
||||
android:name="org.mozilla.fenix.browser.BrowserFragment"
|
||||
app:exitAnim="@anim/fade_out"
|
||||
tools:layout="@layout/fragment_browser">
|
||||
<action
|
||||
android:id="@+id/action_browserFragment_to_homeFragment"
|
||||
app:destination="@id/homeFragment" />
|
||||
<action
|
||||
android:id="@+id/action_browserFragment_to_searchFragment"
|
||||
app:enterAnim="@anim/fade_in_up"
|
||||
app:popExitAnim="@anim/fade_out_down"
|
||||
app:destination="@id/searchFragment" />
|
||||
<argument
|
||||
android:name="activeSessionId"
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
|
||||
package org.mozilla.fenix.search
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDirections
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import mozilla.components.browser.search.SearchEngine
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
|
@ -29,10 +32,12 @@ import org.mozilla.fenix.ext.components
|
|||
import org.mozilla.fenix.ext.metrics
|
||||
import org.mozilla.fenix.ext.searchEngineManager
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.search.DefaultSearchController.Companion.KEYBOARD_ANIMATION_DELAY
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import org.mozilla.fenix.whatsnew.clear
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@Config(application = TestApplication::class)
|
||||
class DefaultSearchControllerTest {
|
||||
|
@ -45,6 +50,8 @@ class DefaultSearchControllerTest {
|
|||
private val searchEngine: SearchEngine = mockk(relaxed = true)
|
||||
private val metrics: MetricController = mockk(relaxed = true)
|
||||
private val sessionManager: SessionManager = mockk(relaxed = true)
|
||||
private val lifecycleScope: LifecycleCoroutineScope = mockk(relaxed = true)
|
||||
private val clearToolbarFocus: (() -> Unit) = mockk(relaxed = true)
|
||||
|
||||
private lateinit var controller: DefaultSearchController
|
||||
private lateinit var settings: Settings
|
||||
|
@ -60,7 +67,9 @@ class DefaultSearchControllerTest {
|
|||
controller = DefaultSearchController(
|
||||
context = context,
|
||||
store = store,
|
||||
navController = navController
|
||||
navController = navController,
|
||||
lifecycleScope = lifecycleScope,
|
||||
clearToolbarFocus = clearToolbarFocus
|
||||
)
|
||||
|
||||
settings = testContext.settings().apply { testContext.settings().clear() }
|
||||
|
@ -84,10 +93,23 @@ class DefaultSearchControllerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun handleEditingCancelled() {
|
||||
fun handleEditingCancelled() = runBlockingTest {
|
||||
controller = DefaultSearchController(
|
||||
context = context,
|
||||
store = store,
|
||||
navController = navController,
|
||||
lifecycleScope = this,
|
||||
clearToolbarFocus = clearToolbarFocus
|
||||
)
|
||||
|
||||
controller.handleEditingCancelled()
|
||||
|
||||
verify { navController.navigateUp() }
|
||||
advanceTimeBy(KEYBOARD_ANIMATION_DELAY)
|
||||
|
||||
verify {
|
||||
clearToolbarFocus()
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.mozilla.fenix.search
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDirections
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
@ -14,6 +15,8 @@ import io.mockk.just
|
|||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import mozilla.components.browser.search.SearchEngine
|
||||
import mozilla.components.browser.search.SearchEngineManager
|
||||
import mozilla.components.browser.session.Session
|
||||
|
@ -33,9 +36,14 @@ import org.mozilla.fenix.utils.Settings
|
|||
import org.mozilla.fenix.whatsnew.clear
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@Config(application = TestApplication::class)
|
||||
class SearchInteractorTest {
|
||||
|
||||
private val lifecycleScope: LifecycleCoroutineScope = mockk(relaxed = true)
|
||||
private val clearToolbarFocus = { }
|
||||
|
||||
@Test
|
||||
fun onUrlCommitted() {
|
||||
val context: HomeActivity = mockk(relaxed = true)
|
||||
|
@ -64,7 +72,9 @@ class SearchInteractorTest {
|
|||
val searchController: SearchController = DefaultSearchController(
|
||||
context,
|
||||
store,
|
||||
mockk()
|
||||
mockk(),
|
||||
lifecycleScope,
|
||||
clearToolbarFocus
|
||||
)
|
||||
val interactor = SearchInteractor(searchController)
|
||||
|
||||
|
@ -81,7 +91,7 @@ class SearchInteractorTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun onEditingCanceled() {
|
||||
fun onEditingCanceled() = runBlockingTest {
|
||||
val navController: NavController = mockk(relaxed = true)
|
||||
val store: SearchFragmentStore = mockk(relaxed = true)
|
||||
|
||||
|
@ -90,14 +100,18 @@ class SearchInteractorTest {
|
|||
val searchController: SearchController = DefaultSearchController(
|
||||
mockk(),
|
||||
store,
|
||||
navController
|
||||
navController,
|
||||
this,
|
||||
clearToolbarFocus
|
||||
)
|
||||
val interactor = SearchInteractor(searchController)
|
||||
|
||||
interactor.onEditingCanceled()
|
||||
advanceTimeBy(DefaultSearchController.KEYBOARD_ANIMATION_DELAY)
|
||||
|
||||
verify {
|
||||
navController.navigateUp()
|
||||
clearToolbarFocus()
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +129,9 @@ class SearchInteractorTest {
|
|||
val searchController: SearchController = DefaultSearchController(
|
||||
context,
|
||||
store,
|
||||
mockk()
|
||||
mockk(),
|
||||
lifecycleScope,
|
||||
clearToolbarFocus
|
||||
)
|
||||
val interactor = SearchInteractor(searchController)
|
||||
|
||||
|
@ -149,7 +165,9 @@ class SearchInteractorTest {
|
|||
val searchController: SearchController = DefaultSearchController(
|
||||
context,
|
||||
store,
|
||||
mockk()
|
||||
mockk(),
|
||||
lifecycleScope,
|
||||
clearToolbarFocus
|
||||
)
|
||||
val interactor = SearchInteractor(searchController)
|
||||
|
||||
|
@ -192,7 +210,9 @@ class SearchInteractorTest {
|
|||
val searchController: SearchController = DefaultSearchController(
|
||||
context,
|
||||
store,
|
||||
mockk()
|
||||
mockk(),
|
||||
lifecycleScope,
|
||||
clearToolbarFocus
|
||||
)
|
||||
|
||||
val interactor = SearchInteractor(searchController)
|
||||
|
@ -223,7 +243,9 @@ class SearchInteractorTest {
|
|||
val searchController: SearchController = DefaultSearchController(
|
||||
context,
|
||||
store,
|
||||
mockk()
|
||||
mockk(),
|
||||
lifecycleScope,
|
||||
clearToolbarFocus
|
||||
)
|
||||
val interactor = SearchInteractor(searchController)
|
||||
val searchEngine: SearchEngine = mockk(relaxed = true)
|
||||
|
@ -253,7 +275,9 @@ class SearchInteractorTest {
|
|||
val searchController: SearchController = DefaultSearchController(
|
||||
mockk(),
|
||||
store,
|
||||
navController
|
||||
navController,
|
||||
lifecycleScope,
|
||||
clearToolbarFocus
|
||||
)
|
||||
val interactor = SearchInteractor(searchController)
|
||||
|
||||
|
@ -280,7 +304,9 @@ class SearchInteractorTest {
|
|||
val searchController: SearchController = DefaultSearchController(
|
||||
context,
|
||||
store,
|
||||
navController
|
||||
navController,
|
||||
lifecycleScope,
|
||||
clearToolbarFocus
|
||||
)
|
||||
val interactor = SearchInteractor(searchController)
|
||||
val session = Session("http://mozilla.org", false)
|
||||
|
|
Loading…
Reference in New Issue