Enforce unidirectional arch better
parent
580fa1011f
commit
0120558fce
|
@ -8,7 +8,6 @@ import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import mozilla.components.browser.engine.gecko.GeckoEngine
|
import mozilla.components.browser.engine.gecko.GeckoEngine
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
import mozilla.components.browser.session.storage.SessionStorage
|
import mozilla.components.browser.session.storage.SessionStorage
|
||||||
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
|
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
|
||||||
|
@ -19,7 +18,6 @@ import mozilla.components.feature.session.HistoryDelegate
|
||||||
import mozilla.components.lib.crash.handler.CrashHandlerService
|
import mozilla.components.lib.crash.handler.CrashHandlerService
|
||||||
import org.mozilla.geckoview.GeckoRuntime
|
import org.mozilla.geckoview.GeckoRuntime
|
||||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
import org.mozilla.geckoview.GeckoRuntimeSettings
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component group for all core browser functionality.
|
* Component group for all core browser functionality.
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.home.sessions
|
package org.mozilla.fenix.home.sessions
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.support.base.log.logger.Logger
|
|
||||||
import org.mozilla.fenix.mvi.Action
|
import org.mozilla.fenix.mvi.Action
|
||||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
import org.mozilla.fenix.mvi.Change
|
import org.mozilla.fenix.mvi.Change
|
||||||
|
@ -16,10 +14,13 @@ import org.mozilla.fenix.mvi.ViewState
|
||||||
|
|
||||||
class SessionsComponent(
|
class SessionsComponent(
|
||||||
private val container: ViewGroup,
|
private val container: ViewGroup,
|
||||||
override val bus: ActionBusFactory,
|
bus: ActionBusFactory,
|
||||||
override var initialState: SessionsState = SessionsState(emptyList())
|
override var initialState: SessionsState = SessionsState(emptyList())
|
||||||
) :
|
) :
|
||||||
UIComponent<SessionsState, SessionsAction, SessionsChange>(bus) {
|
UIComponent<SessionsState, SessionsAction, SessionsChange>(
|
||||||
|
bus.getManagedEmitter(SessionsAction::class.java),
|
||||||
|
bus.getSafeManagedObservable(SessionsChange::class.java)
|
||||||
|
) {
|
||||||
|
|
||||||
override val reducer: (SessionsState, SessionsChange) -> SessionsState = { state, change ->
|
override val reducer: (SessionsState, SessionsChange) -> SessionsState = { state, change ->
|
||||||
when (change) {
|
when (change) {
|
||||||
|
@ -27,20 +28,10 @@ class SessionsComponent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() = SessionsUIView(container, bus)
|
override fun initView() = SessionsUIView(container, actionEmitter, changesObservable)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setup()
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
|
||||||
fun setup(): SessionsComponent {
|
|
||||||
render(reducer)
|
render(reducer)
|
||||||
getUserInteractionEvents<SessionsAction>()
|
|
||||||
.subscribe {
|
|
||||||
Logger("SessionsComponent").debug(it.toString())
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,18 @@ import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.Observer
|
||||||
import io.reactivex.functions.Consumer
|
import io.reactivex.functions.Consumer
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
|
||||||
import org.mozilla.fenix.mvi.UIView
|
import org.mozilla.fenix.mvi.UIView
|
||||||
|
|
||||||
class SessionsUIView(container: ViewGroup, bus: ActionBusFactory) :
|
class SessionsUIView(
|
||||||
UIView<SessionsState>(container, bus) {
|
container: ViewGroup,
|
||||||
|
actionEmitter: Observer<SessionsAction>,
|
||||||
|
changesObservable: Observable<SessionsChange>
|
||||||
|
) :
|
||||||
|
UIView<SessionsState, SessionsAction, SessionsChange>(container, actionEmitter, changesObservable) {
|
||||||
|
|
||||||
override val view: RecyclerView = LayoutInflater.from(container.context)
|
override val view: RecyclerView = LayoutInflater.from(container.context)
|
||||||
.inflate(R.layout.component_sessions, container, true)
|
.inflate(R.layout.component_sessions, container, true)
|
||||||
|
|
|
@ -27,6 +27,7 @@ import androidx.lifecycle.LifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.OnLifecycleEvent
|
import androidx.lifecycle.OnLifecycleEvent
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.Observer
|
||||||
import io.reactivex.rxkotlin.merge
|
import io.reactivex.rxkotlin.merge
|
||||||
import io.reactivex.subjects.PublishSubject
|
import io.reactivex.subjects.PublishSubject
|
||||||
import io.reactivex.subjects.Subject
|
import io.reactivex.subjects.Subject
|
||||||
|
@ -102,6 +103,10 @@ class ActionBusFactory private constructor(val owner: LifecycleOwner) {
|
||||||
return if (map[clazz] != null) map[clazz] as Observable<T> else create(clazz)
|
return if (map[clazz] != null) map[clazz] as Observable<T> else create(clazz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T : Action> getManagedEmitter(clazz: Class<T>): Observer<T> {
|
||||||
|
return if (map[clazz] != null) map[clazz] as Observer<T> else create(clazz)
|
||||||
|
}
|
||||||
|
|
||||||
fun logMergedObservables() {
|
fun logMergedObservables() {
|
||||||
// TODO make this observe new items in the map and combine them
|
// TODO make this observe new items in the map and combine them
|
||||||
map.values.merge().compose(logState()).subscribe()
|
map.values.merge().compose(logState()).subscribe()
|
||||||
|
@ -131,6 +136,9 @@ inline fun <reified T : Action> LifecycleOwner.emit(event: T) =
|
||||||
inline fun <reified T : Action> LifecycleOwner.getSafeManagedObservable(): Observable<T> =
|
inline fun <reified T : Action> LifecycleOwner.getSafeManagedObservable(): Observable<T> =
|
||||||
ActionBusFactory.get(this).getSafeManagedObservable(T::class.java)
|
ActionBusFactory.get(this).getSafeManagedObservable(T::class.java)
|
||||||
|
|
||||||
|
inline fun <reified T : Action> LifecycleOwner.getManagedEmitter(): Observer<T> =
|
||||||
|
ActionBusFactory.get(this).getManagedEmitter(T::class.java)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns a destroy observable that can be passed to [org.mozilla.fenix.mvi.UIView]s as needed.
|
* This method returns a destroy observable that can be passed to [org.mozilla.fenix.mvi.UIView]s as needed.
|
||||||
* This is deliberately scoped to the attached [LifecycleOwner]'s [Lifecycle.Event.ON_DESTROY]
|
* This is deliberately scoped to the attached [LifecycleOwner]'s [Lifecycle.Event.ON_DESTROY]
|
||||||
|
|
|
@ -5,29 +5,28 @@
|
||||||
package org.mozilla.fenix.mvi
|
package org.mozilla.fenix.mvi
|
||||||
|
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.Observer
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
|
||||||
abstract class UIComponent<S : ViewState, A : Action, C : Change>(open val bus: ActionBusFactory) {
|
abstract class UIComponent<S : ViewState, A : Action, C : Change>(
|
||||||
|
protected val actionEmitter: Observer<A>,
|
||||||
|
protected val changesObservable: Observable<C>
|
||||||
|
) {
|
||||||
|
|
||||||
abstract var initialState: S
|
abstract var initialState: S
|
||||||
abstract val reducer: Reducer<S, C>
|
abstract val reducer: Reducer<S, C>
|
||||||
val uiView: UIView<S> by lazy { initView() }
|
val uiView: UIView<S, A, C> by lazy { initView() }
|
||||||
|
|
||||||
abstract fun initView(): UIView<S>
|
abstract fun initView(): UIView<S, A, C>
|
||||||
open fun getContainerId() = uiView.containerId
|
open fun getContainerId() = uiView.containerId
|
||||||
|
|
||||||
inline fun <reified A : Action> getUserInteractionEvents():
|
|
||||||
Observable<A> = bus.getSafeManagedObservable(A::class.java)
|
|
||||||
|
|
||||||
inline fun <reified C : Change> getModelChangeEvents():
|
|
||||||
Observable<C> = bus.getSafeManagedObservable(C::class.java)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the ViewState to the View through the Reducer
|
* Render the ViewState to the View through the Reducer
|
||||||
*/
|
*/
|
||||||
inline fun <reified C : Change> render(noinline reducer: Reducer<S, C>): Disposable =
|
fun render(reducer: Reducer<S, C>): Disposable =
|
||||||
getModelChangeEvents<C>()
|
changesObservable
|
||||||
.scan(initialState, reducer)
|
.scan(initialState, reducer)
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
|
|
|
@ -7,12 +7,15 @@ package org.mozilla.fenix.mvi
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.Observer
|
||||||
import io.reactivex.functions.Consumer
|
import io.reactivex.functions.Consumer
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
|
||||||
abstract class UIView<S : ViewState>(
|
abstract class UIView<S : ViewState, A : Action, C : Change>(
|
||||||
private val container: ViewGroup,
|
private val container: ViewGroup,
|
||||||
val bus: ActionBusFactory
|
protected val actionEmitter: Observer<A>,
|
||||||
|
protected val changesObservable: Observable<C>
|
||||||
) : LayoutContainer {
|
) : LayoutContainer {
|
||||||
|
|
||||||
abstract val view: View
|
abstract val view: View
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.search
|
package org.mozilla.fenix.search
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -13,10 +14,13 @@ import androidx.navigation.Navigation
|
||||||
import kotlinx.android.synthetic.main.fragment_search.view.*
|
import kotlinx.android.synthetic.main.fragment_search.view.*
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
|
import org.mozilla.fenix.mvi.getSafeManagedObservable
|
||||||
import org.mozilla.fenix.search.awesomebar.AwesomeBarAction
|
import org.mozilla.fenix.search.awesomebar.AwesomeBarAction
|
||||||
import org.mozilla.fenix.search.awesomebar.AwesomeBarChange
|
import org.mozilla.fenix.search.awesomebar.AwesomeBarChange
|
||||||
import org.mozilla.fenix.search.awesomebar.AwesomeBarComponent
|
import org.mozilla.fenix.search.awesomebar.AwesomeBarComponent
|
||||||
import org.mozilla.fenix.search.toolbar.*
|
import org.mozilla.fenix.search.toolbar.SearchAction
|
||||||
|
import org.mozilla.fenix.search.toolbar.ToolbarComponent
|
||||||
|
import org.mozilla.fenix.search.toolbar.ToolbarUIView
|
||||||
|
|
||||||
class SearchFragment : Fragment() {
|
class SearchFragment : Fragment() {
|
||||||
private lateinit var toolbarComponent: ToolbarComponent
|
private lateinit var toolbarComponent: ToolbarComponent
|
||||||
|
@ -30,6 +34,7 @@ class SearchFragment : Fragment() {
|
||||||
val view = inflater.inflate(R.layout.fragment_search, container, false)
|
val view = inflater.inflate(R.layout.fragment_search, container, false)
|
||||||
toolbarComponent = ToolbarComponent(view.toolbar_wrapper, ActionBusFactory.get(this))
|
toolbarComponent = ToolbarComponent(view.toolbar_wrapper, ActionBusFactory.get(this))
|
||||||
awesomeBarComponent = AwesomeBarComponent(view.search_layout, ActionBusFactory.get(this))
|
awesomeBarComponent = AwesomeBarComponent(view.search_layout, ActionBusFactory.get(this))
|
||||||
|
ActionBusFactory.get(this).logMergedObservables()
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +43,7 @@ class SearchFragment : Fragment() {
|
||||||
toolbarComponent.editMode()
|
toolbarComponent.editMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("CheckResult")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
@ -47,26 +53,18 @@ class SearchFragment : Fragment() {
|
||||||
|
|
||||||
view.toolbar_wrapper.clipToOutline = false
|
view.toolbar_wrapper.clipToOutline = false
|
||||||
|
|
||||||
toolbarComponent
|
getSafeManagedObservable<SearchAction>()
|
||||||
.getModelChangeEvents<SearchChange>()
|
|
||||||
.subscribe {
|
.subscribe {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SearchChange.QueryChanged -> {
|
is SearchAction.UrlCommitted -> transitionToBrowser()
|
||||||
ActionBusFactory.get(this).emit(AwesomeBarChange::class.java, AwesomeBarChange.UpdateQuery(it.query))
|
is SearchAction.TextChanged -> {
|
||||||
|
ActionBusFactory.get(this)
|
||||||
|
.emit(AwesomeBarChange::class.java, AwesomeBarChange.UpdateQuery(it.query))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toolbarComponent
|
getSafeManagedObservable<AwesomeBarAction>()
|
||||||
.getUserInteractionEvents<SearchAction>()
|
|
||||||
.subscribe {
|
|
||||||
when (it) {
|
|
||||||
is SearchAction.UrlCommitted -> transitionToBrowser()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
awesomeBarComponent
|
|
||||||
.getUserInteractionEvents<AwesomeBarAction>()
|
|
||||||
.subscribe {
|
.subscribe {
|
||||||
when (it) {
|
when (it) {
|
||||||
is AwesomeBarAction.ItemSelected -> transitionToBrowser()
|
is AwesomeBarAction.ItemSelected -> transitionToBrowser()
|
||||||
|
|
|
@ -4,32 +4,38 @@ package org.mozilla.fenix.search.awesomebar
|
||||||
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import org.mozilla.fenix.mvi.*
|
import org.mozilla.fenix.mvi.Action
|
||||||
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
|
import org.mozilla.fenix.mvi.Change
|
||||||
|
import org.mozilla.fenix.mvi.Reducer
|
||||||
|
import org.mozilla.fenix.mvi.UIComponent
|
||||||
|
import org.mozilla.fenix.mvi.ViewState
|
||||||
|
|
||||||
data class AwesomeBarState(val query: String) : ViewState {
|
data class AwesomeBarState(val query: String) : ViewState
|
||||||
fun updateQuery(query: String) = AwesomeBarState(query)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class AwesomeBarAction: Action {
|
sealed class AwesomeBarAction : Action {
|
||||||
object ItemSelected: AwesomeBarAction()
|
object ItemSelected : AwesomeBarAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class AwesomeBarChange : Change {
|
sealed class AwesomeBarChange : Change {
|
||||||
data class UpdateQuery(val query: String): AwesomeBarChange()
|
data class UpdateQuery(val query: String) : AwesomeBarChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
class AwesomeBarComponent(
|
class AwesomeBarComponent(
|
||||||
private val container: ViewGroup,
|
private val container: ViewGroup,
|
||||||
override val bus: ActionBusFactory,
|
bus: ActionBusFactory,
|
||||||
override var initialState: AwesomeBarState = AwesomeBarState("")
|
override var initialState: AwesomeBarState = AwesomeBarState("")
|
||||||
) : UIComponent<AwesomeBarState, AwesomeBarAction, AwesomeBarChange>(bus) {
|
) : UIComponent<AwesomeBarState, AwesomeBarAction, AwesomeBarChange>(
|
||||||
|
bus.getManagedEmitter(AwesomeBarAction::class.java),
|
||||||
|
bus.getSafeManagedObservable(AwesomeBarChange::class.java)
|
||||||
|
) {
|
||||||
override val reducer: Reducer<AwesomeBarState, AwesomeBarChange> = { state, change ->
|
override val reducer: Reducer<AwesomeBarState, AwesomeBarChange> = { state, change ->
|
||||||
when (change) {
|
when (change) {
|
||||||
is AwesomeBarChange.UpdateQuery -> state.updateQuery(change.query)
|
is AwesomeBarChange.UpdateQuery -> state.copy(query = change.query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() = AwesomeBarUIView(container, bus)
|
override fun initView() = AwesomeBarUIView(container, actionEmitter, changesObservable)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
render(reducer)
|
render(reducer)
|
||||||
|
|
|
@ -5,6 +5,8 @@ package org.mozilla.fenix.search.awesomebar
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.Observer
|
||||||
import io.reactivex.functions.Consumer
|
import io.reactivex.functions.Consumer
|
||||||
import mozilla.components.browser.awesomebar.BrowserAwesomeBar
|
import mozilla.components.browser.awesomebar.BrowserAwesomeBar
|
||||||
import mozilla.components.feature.awesomebar.provider.ClipboardSuggestionProvider
|
import mozilla.components.feature.awesomebar.provider.ClipboardSuggestionProvider
|
||||||
|
@ -13,11 +15,14 @@ import mozilla.components.feature.awesomebar.provider.SessionSuggestionProvider
|
||||||
import mozilla.components.support.ktx.android.graphics.drawable.toBitmap
|
import mozilla.components.support.ktx.android.graphics.drawable.toBitmap
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
|
||||||
import org.mozilla.fenix.mvi.UIView
|
import org.mozilla.fenix.mvi.UIView
|
||||||
|
|
||||||
class AwesomeBarUIView(container: ViewGroup, bus: ActionBusFactory) :
|
class AwesomeBarUIView(
|
||||||
UIView<AwesomeBarState>(container, bus) {
|
container: ViewGroup,
|
||||||
|
actionEmitter: Observer<AwesomeBarAction>,
|
||||||
|
changesObservable: Observable<AwesomeBarChange>
|
||||||
|
) :
|
||||||
|
UIView<AwesomeBarState, AwesomeBarAction, AwesomeBarChange>(container, actionEmitter, changesObservable) {
|
||||||
override val view: BrowserAwesomeBar = LayoutInflater.from(container.context)
|
override val view: BrowserAwesomeBar = LayoutInflater.from(container.context)
|
||||||
.inflate(R.layout.component_awesomebar, container, true)
|
.inflate(R.layout.component_awesomebar, container, true)
|
||||||
.findViewById(R.id.awesomeBar)
|
.findViewById(R.id.awesomeBar)
|
||||||
|
@ -31,18 +36,19 @@ class AwesomeBarUIView(container: ViewGroup, bus: ActionBusFactory) :
|
||||||
getString(R.string.awesomebar_clipboard_title)
|
getString(R.string.awesomebar_clipboard_title)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
view.addProviders(SessionSuggestionProvider(components.core.sessionManager, components.useCases.tabsUseCases.selectTab))
|
view.addProviders(SessionSuggestionProvider(components.core.sessionManager,
|
||||||
|
components.useCases.tabsUseCases.selectTab))
|
||||||
view.addProviders(SearchSuggestionProvider(
|
view.addProviders(SearchSuggestionProvider(
|
||||||
components.search.searchEngineManager.getDefaultSearchEngine(this),
|
components.search.searchEngineManager.getDefaultSearchEngine(this),
|
||||||
components.useCases.searchUseCases.defaultSearch,
|
components.useCases.searchUseCases.defaultSearch,
|
||||||
SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS)
|
SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS)
|
||||||
)
|
)
|
||||||
|
|
||||||
view.setOnStopListener { bus.emit(AwesomeBarAction::class.java, AwesomeBarAction.ItemSelected) }
|
view.setOnStopListener { actionEmitter.onNext(AwesomeBarAction.ItemSelected) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateView() = Consumer<AwesomeBarState> {
|
override fun updateView() = Consumer<AwesomeBarState> {
|
||||||
view.onInputChanged(it.query)
|
view.onInputChanged(it.query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,18 +16,21 @@ import org.mozilla.fenix.mvi.ViewState
|
||||||
|
|
||||||
class ToolbarComponent(
|
class ToolbarComponent(
|
||||||
private val container: ViewGroup,
|
private val container: ViewGroup,
|
||||||
override val bus: ActionBusFactory,
|
bus: ActionBusFactory,
|
||||||
override var initialState: SearchState = SearchState("")
|
override var initialState: SearchState = SearchState("")
|
||||||
) :
|
) :
|
||||||
UIComponent<SearchState, SearchAction, SearchChange>(bus) {
|
UIComponent<SearchState, SearchAction, SearchChange>(
|
||||||
|
bus.getManagedEmitter(SearchAction::class.java),
|
||||||
|
bus.getSafeManagedObservable(SearchChange::class.java)
|
||||||
|
) {
|
||||||
|
|
||||||
override val reducer: Reducer<SearchState, SearchChange> = { state, change ->
|
override val reducer: Reducer<SearchState, SearchChange> = { state, change ->
|
||||||
when (change) {
|
when (change) {
|
||||||
is SearchChange.QueryChanged -> state.updateQuery(change.query)
|
is SearchChange.QueryChanged -> state.copy(query = change.query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() = ToolbarUIView(container, bus)
|
override fun initView() = ToolbarUIView(container, actionEmitter, changesObservable)
|
||||||
init {
|
init {
|
||||||
render(reducer)
|
render(reducer)
|
||||||
}
|
}
|
||||||
|
@ -36,12 +39,11 @@ class ToolbarComponent(
|
||||||
fun editMode() = getView().editMode()
|
fun editMode() = getView().editMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SearchState(val query: String) : ViewState {
|
data class SearchState(val query: String) : ViewState
|
||||||
fun updateQuery(query: String) = SearchState(query)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class SearchAction : Action {
|
sealed class SearchAction : Action {
|
||||||
data class UrlCommitted(val url: String): SearchAction()
|
data class UrlCommitted(val url: String) : SearchAction()
|
||||||
|
data class TextChanged(val query: String) : SearchAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class SearchChange : Change {
|
sealed class SearchChange : Change {
|
||||||
|
|
|
@ -7,6 +7,8 @@ package org.mozilla.fenix.search.toolbar
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.Observer
|
||||||
import io.reactivex.functions.Consumer
|
import io.reactivex.functions.Consumer
|
||||||
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
|
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
|
||||||
import mozilla.components.browser.toolbar.BrowserToolbar
|
import mozilla.components.browser.toolbar.BrowserToolbar
|
||||||
|
@ -14,12 +16,14 @@ import mozilla.components.support.ktx.android.content.res.pxToDp
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.toolbar.ToolbarIntegration
|
import org.mozilla.fenix.components.toolbar.ToolbarIntegration
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.requireComponents
|
|
||||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
|
||||||
import org.mozilla.fenix.mvi.UIView
|
import org.mozilla.fenix.mvi.UIView
|
||||||
|
|
||||||
class ToolbarUIView(container: ViewGroup, bus: ActionBusFactory) :
|
class ToolbarUIView(
|
||||||
UIView<SearchState>(container, bus) {
|
container: ViewGroup,
|
||||||
|
actionEmitter: Observer<SearchAction>,
|
||||||
|
changesObservable: Observable<SearchChange>
|
||||||
|
) :
|
||||||
|
UIView<SearchState, SearchAction, SearchChange>(container, actionEmitter, changesObservable) {
|
||||||
|
|
||||||
val toolbarIntegration: ToolbarIntegration
|
val toolbarIntegration: ToolbarIntegration
|
||||||
|
|
||||||
|
@ -33,7 +37,7 @@ class ToolbarUIView(container: ViewGroup, bus: ActionBusFactory) :
|
||||||
init {
|
init {
|
||||||
view.apply {
|
view.apply {
|
||||||
onUrlClicked = { false }
|
onUrlClicked = { false }
|
||||||
setOnUrlCommitListener { bus.emit(SearchAction::class.java, SearchAction.UrlCommitted(it)) }
|
setOnUrlCommitListener { actionEmitter.onNext(SearchAction.UrlCommitted(it)) }
|
||||||
|
|
||||||
browserActionMargin = resources.pxToDp(browserActionMarginDp)
|
browserActionMargin = resources.pxToDp(browserActionMarginDp)
|
||||||
urlBoxView = urlBackground
|
urlBoxView = urlBackground
|
||||||
|
@ -46,11 +50,11 @@ class ToolbarUIView(container: ViewGroup, bus: ActionBusFactory) :
|
||||||
|
|
||||||
setOnEditListener(object : mozilla.components.concept.toolbar.Toolbar.OnEditListener {
|
setOnEditListener(object : mozilla.components.concept.toolbar.Toolbar.OnEditListener {
|
||||||
override fun onTextChanged(text: String) {
|
override fun onTextChanged(text: String) {
|
||||||
bus.emit(SearchChange::class.java, SearchChange.QueryChanged(text))
|
actionEmitter.onNext(SearchAction.TextChanged(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStopEditing() {
|
override fun onStopEditing() {
|
||||||
bus.emit(SearchAction::class.java, SearchAction.UrlCommitted("foo"))
|
actionEmitter.onNext(SearchAction.UrlCommitted("foo"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue