From ed1e56308715a8b247cdaeb98941761cdd5583fe Mon Sep 17 00:00:00 2001 From: Jeff Boek Date: Wed, 30 Jan 2019 15:51:49 -0800 Subject: [PATCH] Pull awesome bar into a component --- .../mozilla/fenix/search/SearchFragment.kt | 64 +++++++++++-------- .../org/mozilla/fenix/search/SearchLayouts.kt | 1 + .../search/awesomebar/AwesomeBarComponent.kt | 37 +++++++++++ .../search/awesomebar/AwesomeBarUIView.kt | 41 ++++++++++++ .../ToolbarComponent.kt} | 40 ++++-------- .../ToolbarUIView.kt} | 48 +++++++------- .../main/res/layout/component_awesomebar.xml | 21 ++++++ app/src/main/res/layout/fragment_search.xml | 16 ----- 8 files changed, 176 insertions(+), 92 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarComponent.kt create mode 100644 app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarUIView.kt rename app/src/main/java/org/mozilla/fenix/search/{SearchComponent.kt => toolbar/ToolbarComponent.kt} (53%) rename app/src/main/java/org/mozilla/fenix/search/{SearchUIView.kt => toolbar/ToolbarUIView.kt} (58%) create mode 100644 app/src/main/res/layout/component_awesomebar.xml diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt index f0d1838ae..2fc2ca54d 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt @@ -4,23 +4,23 @@ package org.mozilla.fenix.search -import android.annotation.SuppressLint import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.navigation.Navigation -import kotlinx.android.synthetic.main.fragment_search.* import kotlinx.android.synthetic.main.fragment_search.view.* -import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider import org.mozilla.fenix.R -import org.mozilla.fenix.components.toolbar.ToolbarIntegration -import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.mvi.ActionBusFactory +import org.mozilla.fenix.search.awesomebar.AwesomeBarAction +import org.mozilla.fenix.search.awesomebar.AwesomeBarChange +import org.mozilla.fenix.search.awesomebar.AwesomeBarComponent +import org.mozilla.fenix.search.toolbar.* class SearchFragment : Fragment() { - private lateinit var searchComponent: SearchComponent + private lateinit var toolbarComponent: ToolbarComponent + private lateinit var awesomeBarComponent: AwesomeBarComponent override fun onCreateView( inflater: LayoutInflater, @@ -28,40 +28,54 @@ class SearchFragment : Fragment() { savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_search, container, false) - searchComponent = SearchComponent(view.toolbar_wrapper, ActionBusFactory.get(this), - { v -> transitionToBrowser(v) }) + toolbarComponent = ToolbarComponent(view.toolbar_wrapper, ActionBusFactory.get(this)) + awesomeBarComponent = AwesomeBarComponent(view.search_layout, ActionBusFactory.get(this)) return view } override fun onResume() { super.onResume() - searchComponent.editMode() + toolbarComponent.editMode() } - @SuppressLint("CheckResult") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) layoutComponents(view.search_layout) - lifecycle.addObserver( - ToolbarIntegration( - requireContext(), - searchComponent.getView(), - ShippedDomainsProvider().also { it.initialize(requireContext()) }, - requireComponents.core.historyStorage - ) - ) + lifecycle.addObserver((toolbarComponent.uiView as ToolbarUIView).toolbarIntegration) - toolbar_wrapper.clipToOutline = false + view.toolbar_wrapper.clipToOutline = false + + toolbarComponent + .getModelChangeEvents() + .subscribe { + when (it) { + is SearchChange.QueryChanged -> { + ActionBusFactory.get(this).emit(AwesomeBarChange::class.java, AwesomeBarChange.UpdateQuery(it.query)) + } + } + } + + toolbarComponent + .getUserInteractionEvents() + .subscribe { + when (it) { + is SearchAction.UrlCommitted -> transitionToBrowser() + } + } + + awesomeBarComponent + .getUserInteractionEvents() + .subscribe { + when (it) { + is AwesomeBarAction.ItemSelected -> transitionToBrowser() + } + } } - private fun transitionToBrowser(toolbar: View) { - Navigation.findNavController(toolbar) + private fun transitionToBrowser() { + Navigation.findNavController(view!!.search_layout) .navigate(R.id.action_searchFragment_to_browserFragment, null, null) } - - companion object { - const val toolbarTextSizeSp = 14f - } } diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchLayouts.kt b/app/src/main/java/org/mozilla/fenix/search/SearchLayouts.kt index cdadb77bd..eaeee2947 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchLayouts.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchLayouts.kt @@ -8,6 +8,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.UNSET import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.android.synthetic.main.component_awesomebar.* import kotlinx.android.synthetic.main.fragment_search.* import mozilla.components.support.base.log.logger.Logger import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.BOTTOM diff --git a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarComponent.kt b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarComponent.kt new file mode 100644 index 000000000..8ee88af32 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarComponent.kt @@ -0,0 +1,37 @@ +package org.mozilla.fenix.search.awesomebar +/* 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/. */ + +import android.view.ViewGroup +import org.mozilla.fenix.mvi.* + +data class AwesomeBarState(val query: String) : ViewState { + fun updateQuery(query: String) = AwesomeBarState(query) +} + +sealed class AwesomeBarAction: Action { + object ItemSelected: AwesomeBarAction() +} + +sealed class AwesomeBarChange : Change { + data class UpdateQuery(val query: String): AwesomeBarChange() +} + +class AwesomeBarComponent( + private val container: ViewGroup, + override val bus: ActionBusFactory, + override var initialState: AwesomeBarState = AwesomeBarState("") +) : UIComponent(bus) { + override val reducer: Reducer = { state, change -> + when (change) { + is AwesomeBarChange.UpdateQuery -> state.updateQuery(change.query) + } + } + + override fun initView() = AwesomeBarUIView(container, bus) + + init { + render(reducer) + } +} diff --git a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarUIView.kt b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarUIView.kt new file mode 100644 index 000000000..2dbf92466 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarUIView.kt @@ -0,0 +1,41 @@ +package org.mozilla.fenix.search.awesomebar +/* 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/. */ + +import android.view.LayoutInflater +import android.view.ViewGroup +import io.reactivex.functions.Consumer +import mozilla.components.browser.awesomebar.BrowserAwesomeBar +import mozilla.components.feature.awesomebar.provider.ClipboardSuggestionProvider +import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider +import mozilla.components.feature.awesomebar.provider.SessionSuggestionProvider +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.components +import org.mozilla.fenix.mvi.ActionBusFactory +import org.mozilla.fenix.mvi.UIView + +class AwesomeBarUIView(container: ViewGroup, bus: ActionBusFactory) : + UIView(container, bus) { + override val view: BrowserAwesomeBar = LayoutInflater.from(container.context) + .inflate(R.layout.component_awesomebar, container, true) + .findViewById(R.id.awesomeBar) + + init { + with(container.context) { + view.addProviders(ClipboardSuggestionProvider(this, components.useCases.sessionUseCases.loadUrl)) + view.addProviders(SessionSuggestionProvider(components.core.sessionManager, components.useCases.tabsUseCases.selectTab)) + view.addProviders(SearchSuggestionProvider( + components.search.searchEngineManager.getDefaultSearchEngine(this), + components.useCases.searchUseCases.defaultSearch, + SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS) + ) + + view.setOnStopListener { bus.emit(AwesomeBarAction::class.java, AwesomeBarAction.ItemSelected) } + } + } + + override fun updateView() = Consumer { + view.onInputChanged(it.query) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchComponent.kt b/app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarComponent.kt similarity index 53% rename from app/src/main/java/org/mozilla/fenix/search/SearchComponent.kt rename to app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarComponent.kt index ac310d299..bc3465320 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchComponent.kt +++ b/app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarComponent.kt @@ -2,14 +2,11 @@ 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/. */ -package org.mozilla.fenix.search +package org.mozilla.fenix.search.toolbar -import android.annotation.SuppressLint -import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.fragment_browser.* import mozilla.components.browser.toolbar.BrowserToolbar -import mozilla.components.support.base.log.logger.Logger import org.mozilla.fenix.mvi.Action import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.Change @@ -17,51 +14,36 @@ import org.mozilla.fenix.mvi.Reducer import org.mozilla.fenix.mvi.UIComponent import org.mozilla.fenix.mvi.ViewState -class SearchComponent( +class ToolbarComponent( private val container: ViewGroup, override val bus: ActionBusFactory, - private val onEditComplete: (View) -> Unit, override var initialState: SearchState = SearchState("") ) : UIComponent(bus) { override val reducer: Reducer = { state, change -> when (change) { - is SearchChange.Changed -> state // TODO handle state changes here + is SearchChange.QueryChanged -> state.updateQuery(change.query) } } - override fun initView() = SearchUIView(container, bus) + override fun initView() = ToolbarUIView(container, bus) init { - setup() + render(reducer) } fun getView(): BrowserToolbar = uiView.toolbar fun editMode() = getView().editMode() - - @SuppressLint("CheckResult") - fun setup(): SearchComponent { - render(reducer) - getUserInteractionEvents() - .subscribe { - Logger("SearchComponent").debug(it.toString()) - when (it) { - is SearchAction.EditComplete -> { - onEditComplete.invoke(getView()) - } - else -> {} - } - } - return this - } } -data class SearchState(val term: String) : ViewState +data class SearchState(val query: String) : ViewState { + fun updateQuery(query: String) = SearchState(query) +} + sealed class SearchAction : Action { - object UrlClicked : SearchAction() - object EditComplete : SearchAction() + data class UrlCommitted(val url: String): SearchAction() } sealed class SearchChange : Change { - object Changed : SearchChange() + data class QueryChanged(val query: String) : SearchChange() } diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchUIView.kt b/app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarUIView.kt similarity index 58% rename from app/src/main/java/org/mozilla/fenix/search/SearchUIView.kt rename to app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarUIView.kt index 28c860586..fba8ae495 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchUIView.kt +++ b/app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarUIView.kt @@ -2,25 +2,27 @@ 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/. */ -package org.mozilla.fenix.search +package org.mozilla.fenix.search.toolbar import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.content.ContextCompat import io.reactivex.functions.Consumer -import kotlinx.android.synthetic.main.fragment_search.view.* +import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider import mozilla.components.browser.toolbar.BrowserToolbar -import mozilla.components.feature.awesomebar.AwesomeBarFeature -import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider import mozilla.components.support.ktx.android.content.res.pxToDp import org.mozilla.fenix.R +import org.mozilla.fenix.components.toolbar.ToolbarIntegration import org.mozilla.fenix.ext.components +import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.UIView -class SearchUIView(container: ViewGroup, bus: ActionBusFactory) : +class ToolbarUIView(container: ViewGroup, bus: ActionBusFactory) : UIView(container, bus) { + val toolbarIntegration: ToolbarIntegration + override val view: BrowserToolbar = LayoutInflater.from(container.context) .inflate(R.layout.component_search, container, true) .findViewById(R.id.toolbar) @@ -30,10 +32,8 @@ class SearchUIView(container: ViewGroup, bus: ActionBusFactory) : init { view.apply { - onUrlClicked = { - bus.emit(SearchAction::class.java, SearchAction.UrlClicked) - false - } + onUrlClicked = { false } + setOnUrlCommitListener { bus.emit(SearchAction::class.java, SearchAction.UrlCommitted(it)) } browserActionMargin = resources.pxToDp(browserActionMarginDp) urlBoxView = urlBackground @@ -43,21 +43,25 @@ class SearchUIView(container: ViewGroup, bus: ActionBusFactory) : textSize = toolbarTextSizeSp hint = context.getString(R.string.search_hint) hintColor = ContextCompat.getColor(context, R.color.searchText) + + setOnEditListener(object : mozilla.components.concept.toolbar.Toolbar.OnEditListener { + override fun onTextChanged(text: String) { + bus.emit(SearchChange::class.java, SearchChange.QueryChanged(text)) + } + + override fun onStopEditing() { + bus.emit(SearchAction::class.java, SearchAction.UrlCommitted("foo")) + } + }) } - with(container.context) { - AwesomeBarFeature(container.rootView.awesomeBar, view, null, - onEditComplete = { bus.emit(SearchAction::class.java, SearchAction.EditComplete) }) - .addClipboardProvider(this, components.useCases.sessionUseCases.loadUrl) - .addSearchProvider( - components.search.searchEngineManager.getDefaultSearchEngine(this), - components.useCases.searchUseCases.defaultSearch, - SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS - ) - .addSessionProvider( - components.core.sessionManager, - components.useCases.tabsUseCases.selectTab - ) + with(view.context) { + toolbarIntegration = ToolbarIntegration( + this, + view, + ShippedDomainsProvider().also { it.initialize(this) }, + components.core.historyStorage + ) } } diff --git a/app/src/main/res/layout/component_awesomebar.xml b/app/src/main/res/layout/component_awesomebar.xml new file mode 100644 index 000000000..808bcc899 --- /dev/null +++ b/app/src/main/res/layout/component_awesomebar.xml @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index d5691e9b0..d52f651ec 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -24,22 +24,6 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"/> - -