1
0
Fork 0

For #7698: Adds search back button animation (#7840)

* For #7698: Adds search back button animation

* Refactor for searchController
master
Sawyer Blatz 2020-01-22 11:15:30 -08:00 committed by GitHub
parent 2372ee6b15
commit 20396f78a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 43 additions and 13 deletions

View File

@ -76,6 +76,7 @@ class DefaultSearchController(
} }
override fun handleEditingCancelled() { override fun handleEditingCancelled() {
store.dispatch(SearchFragmentAction.UpdateEditingCanceled)
navController.navigateUp() navController.navigateUp()
} }

View File

@ -17,7 +17,9 @@ import android.view.ViewGroup
import android.view.ViewStub import android.view.ViewStub
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.marginStart
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.transition.TransitionInflater import androidx.transition.TransitionInflater
import kotlinx.android.synthetic.main.fragment_search.* import kotlinx.android.synthetic.main.fragment_search.*
@ -111,7 +113,8 @@ class SearchFragment : Fragment(), UserInteractionHandler {
showBookmarkSuggestions = requireContext().settings().shouldShowBookmarkSuggestions, showBookmarkSuggestions = requireContext().settings().shouldShowBookmarkSuggestions,
session = session, session = session,
pastedText = pastedText, pastedText = pastedText,
searchAccessPoint = searchAccessPoint searchAccessPoint = searchAccessPoint,
isAnimatingOut = false
) )
) )
} }
@ -199,7 +202,7 @@ class SearchFragment : Fragment(), UserInteractionHandler {
} }
view.back_button.setOnClickListener { view.back_button.setOnClickListener {
findNavController().navigateUp() searchInteractor.onEditingCanceled()
} }
val stubListener = ViewStub.OnInflateListener { _, inflated -> val stubListener = ViewStub.OnInflateListener { _, inflated ->
@ -253,6 +256,7 @@ class SearchFragment : Fragment(), UserInteractionHandler {
updateSearchWithLabel(it) updateSearchWithLabel(it)
updateClipboardSuggestion(it, requireContext().components.clipboardHandler.url) updateClipboardSuggestion(it, requireContext().components.clipboardHandler.url)
updateSearchSuggestionsHintVisibility(it) updateSearchSuggestionsHintVisibility(it)
updateBackButton(it)
} }
startPostponedEnterTransition() startPostponedEnterTransition()
@ -316,6 +320,13 @@ class SearchFragment : Fragment(), UserInteractionHandler {
clipboard_url.text = clipboardUrl clipboard_url.text = clipboardUrl
} }
private fun updateBackButton(searchState: SearchFragmentState) {
if (searchState.isAnimatingOut) {
searchStore.dispatch(SearchFragmentAction.ConsumeEditingCancelled)
animateBackButtonAway()
}
}
override fun onRequestPermissionsResult( override fun onRequestPermissionsResult(
requestCode: Int, requestCode: Int,
permissions: Array<String>, permissions: Array<String>,
@ -352,6 +363,18 @@ class SearchFragment : Fragment(), UserInteractionHandler {
} }
} }
private fun animateBackButtonAway() {
val backButton = requireView().back_button
val xTranslation = with(backButton) {
-(width + marginStart + paddingStart).toFloat()
}
backButton
.animate()
.translationX(xTranslation)
.interpolator = FastOutSlowInInterpolator()
}
companion object { companion object {
private const val SHARED_TRANSITION_MS = 200L private const val SHARED_TRANSITION_MS = 200L
private const val REQUEST_CODE_CAMERA_PERMISSIONS = 1 private const val REQUEST_CODE_CAMERA_PERMISSIONS = 1

View File

@ -57,13 +57,16 @@ data class SearchFragmentState(
val showBookmarkSuggestions: Boolean, val showBookmarkSuggestions: Boolean,
val session: Session?, val session: Session?,
val pastedText: String? = null, val pastedText: String? = null,
val searchAccessPoint: Event.PerformedSearch.SearchAccessPoint? val searchAccessPoint: Event.PerformedSearch.SearchAccessPoint?,
val isAnimatingOut: Boolean
) : State ) : State
/** /**
* Actions to dispatch through the `SearchStore` to modify `SearchState` through the reducer. * Actions to dispatch through the `SearchStore` to modify `SearchState` through the reducer.
*/ */
sealed class SearchFragmentAction : Action { sealed class SearchFragmentAction : Action {
object UpdateEditingCanceled : SearchFragmentAction()
object ConsumeEditingCancelled : SearchFragmentAction()
data class SearchShortcutEngineSelected(val engine: SearchEngine) : SearchFragmentAction() data class SearchShortcutEngineSelected(val engine: SearchEngine) : SearchFragmentAction()
data class SelectNewDefaultSearchEngine(val engine: SearchEngine) : SearchFragmentAction() data class SelectNewDefaultSearchEngine(val engine: SearchEngine) : SearchFragmentAction()
data class ShowSearchShortcutEnginePicker(val show: Boolean) : SearchFragmentAction() data class ShowSearchShortcutEnginePicker(val show: Boolean) : SearchFragmentAction()
@ -91,5 +94,9 @@ private fun searchStateReducer(state: SearchFragmentState, action: SearchFragmen
) )
is SearchFragmentAction.ShowSearchSuggestionsHint -> is SearchFragmentAction.ShowSearchSuggestionsHint ->
state.copy(showSearchSuggestionsHint = action.show) state.copy(showSearchSuggestionsHint = action.show)
is SearchFragmentAction.UpdateEditingCanceled ->
state.copy(isAnimatingOut = true)
is SearchFragmentAction.ConsumeEditingCancelled ->
state.copy(isAnimatingOut = false)
} }
} }

View File

@ -58,6 +58,7 @@ class SearchFragmentStoreTest {
showHistorySuggestions = false, showHistorySuggestions = false,
showBookmarkSuggestions = false, showBookmarkSuggestions = false,
session = null, session = null,
searchAccessPoint = Event.PerformedSearch.SearchAccessPoint.NONE searchAccessPoint = Event.PerformedSearch.SearchAccessPoint.NONE,
isAnimatingOut = false
) )
} }

View File

@ -13,8 +13,8 @@ import io.mockk.Runs
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.verify
import io.mockk.mockkObject import io.mockk.mockkObject
import io.mockk.verify
import mozilla.components.browser.search.SearchEngine import mozilla.components.browser.search.SearchEngine
import mozilla.components.browser.search.SearchEngineManager import mozilla.components.browser.search.SearchEngineManager
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
@ -85,7 +85,7 @@ class SearchInteractorTest {
@Test @Test
fun onEditingCanceled() { fun onEditingCanceled() {
val navController: NavController = mockk(relaxed = true) val navController: NavController = mockk(relaxed = true)
val store: SearchFragmentStore = mockk() val store: SearchFragmentStore = mockk(relaxed = true)
every { store.state } returns mockk(relaxed = true) every { store.state } returns mockk(relaxed = true)
@ -99,6 +99,7 @@ class SearchInteractorTest {
interactor.onEditingCanceled() interactor.onEditingCanceled()
verify { verify {
store.dispatch(SearchFragmentAction.UpdateEditingCanceled)
navController.navigateUp() navController.navigateUp()
} }
} }

View File

@ -3,7 +3,7 @@ package org.mozilla.fenix.detektrules
import io.gitlab.arturbosch.detekt.api.ConsoleReport import io.gitlab.arturbosch.detekt.api.ConsoleReport
import io.gitlab.arturbosch.detekt.api.Detektion import io.gitlab.arturbosch.detekt.api.Detektion
class CustomRulesetConsoleReport: ConsoleReport() { class CustomRulesetConsoleReport : ConsoleReport() {
override fun render(detektion: Detektion): String? { override fun render(detektion: Detektion): String? {
return detektion.findings["mozilla-detekt-rules"]?.fold("") { output, finding -> return detektion.findings["mozilla-detekt-rules"]?.fold("") { output, finding ->
output + finding.locationAsString + ": " + finding.messageOrDescription() output + finding.locationAsString + ": " + finding.messageOrDescription()

View File

@ -8,7 +8,7 @@ import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.RuleSet import io.gitlab.arturbosch.detekt.api.RuleSet
import io.gitlab.arturbosch.detekt.api.RuleSetProvider import io.gitlab.arturbosch.detekt.api.RuleSetProvider
class CustomRulesetProvider: RuleSetProvider { class CustomRulesetProvider : RuleSetProvider {
override val ruleSetId: String = "mozilla-detekt-rules" override val ruleSetId: String = "mozilla-detekt-rules"
override fun instance(config: Config): RuleSet = RuleSet( override fun instance(config: Config): RuleSet = RuleSet(
@ -17,6 +17,4 @@ class CustomRulesetProvider: RuleSetProvider {
MozillaBannedPropertyAccess(config) MozillaBannedPropertyAccess(config)
) )
) )
} }

View File

@ -13,7 +13,7 @@ import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity import io.gitlab.arturbosch.detekt.api.Severity
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
class MozillaBannedPropertyAccess(config: Config = Config.empty): Rule(config) { class MozillaBannedPropertyAccess(config: Config = Config.empty) : Rule(config) {
override val issue = Issue( override val issue = Issue(
"MozillaBannedPropertyAccess", "MozillaBannedPropertyAccess",
Severity.Defect, Severity.Defect,
@ -27,7 +27,6 @@ class MozillaBannedPropertyAccess(config: Config = Config.empty): Rule(config) {
listOf<String>() listOf<String>()
} else { } else {
bannedPropertiesList.split(",") bannedPropertiesList.split(",")
} }
} }
@ -44,7 +43,7 @@ class MozillaBannedPropertyAccess(config: Config = Config.empty): Rule(config) {
CodeSmell( CodeSmell(
issue, issue,
Entity.from(expression), Entity.from(expression),
"Using ${possiblyBannedPropertyAccess} is not allowed because accessing property ${it} is against Mozilla policy. See 'mozilla-detekt-rules' stanza in 'config/detekt.yml' for more information.\n" "Using $possiblyBannedPropertyAccess is not allowed because accessing property $it is against Mozilla policy. See 'mozilla-detekt-rules' stanza in 'config/detekt.yml' for more information.\n"
) )
}.forEach { report(it) } }.forEach { report(it) }
} }