Fixes #290: Integrate new Fenix architecture
parent
8af55652be
commit
273f33b244
@ -0,0 +1,24 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.fenix
|
||||
|
||||
import android.content.Context
|
||||
import mozilla.components.service.fretboard.ExperimentDescriptor
|
||||
|
||||
const val EXPERIMENTS_JSON_FILENAME = "experiments.json"
|
||||
const val EXPERIMENTS_BASE_URL = "https://settings.prod.mozaws.net/v1"
|
||||
const val EXPERIMENTS_BUCKET_NAME = "main"
|
||||
// TODO Change this after fenix-experiments is created
|
||||
const val EXPERIMENTS_COLLECTION_NAME = "focus-experiments"
|
||||
|
||||
object Experiments {
|
||||
val AATestDescriptor = ExperimentDescriptor("AAtest")
|
||||
}
|
||||
|
||||
val Context.app: FenixApplication
|
||||
get() = applicationContext as FenixApplication
|
||||
|
||||
fun Context.isInExperiment(descriptor: ExperimentDescriptor): Boolean =
|
||||
app.fretboard.isInExperiment(this, descriptor)
|
@ -0,0 +1,67 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.fenix.search
|
||||
|
||||
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
|
||||
import org.mozilla.fenix.mvi.Reducer
|
||||
import org.mozilla.fenix.mvi.UIComponent
|
||||
import org.mozilla.fenix.mvi.ViewState
|
||||
|
||||
class SearchComponent(
|
||||
private val container: ViewGroup,
|
||||
override val bus: ActionBusFactory,
|
||||
private val onEditComplete: (View) -> Unit,
|
||||
override var initialState: SearchState = SearchState("")
|
||||
) :
|
||||
UIComponent<SearchState, SearchAction, SearchChange>(bus) {
|
||||
|
||||
override val reducer: Reducer<SearchState, SearchChange> = { state, change ->
|
||||
when (change) {
|
||||
is SearchChange.Changed -> state // TODO handle state changes here
|
||||
}
|
||||
}
|
||||
|
||||
override fun initView() = SearchUIView(container, bus)
|
||||
init {
|
||||
setup()
|
||||
}
|
||||
|
||||
fun getView(): BrowserToolbar = uiView.toolbar
|
||||
fun editMode() = getView().editMode()
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun setup(): SearchComponent {
|
||||
render(reducer)
|
||||
getUserInteractionEvents<SearchAction>()
|
||||
.subscribe {
|
||||
Logger("SearchComponent").debug(it.toString())
|
||||
when (it) {
|
||||
is SearchAction.EditComplete -> {
|
||||
onEditComplete.invoke(getView())
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
data class SearchState(val term: String) : ViewState
|
||||
sealed class SearchAction : Action {
|
||||
object UrlClicked : SearchAction()
|
||||
object EditComplete : SearchAction()
|
||||
}
|
||||
|
||||
sealed class SearchChange : Change {
|
||||
object Changed : SearchChange()
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.fenix.search
|
||||
|
||||
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.fragment_search.*
|
||||
import mozilla.components.support.base.log.logger.Logger
|
||||
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.BOTTOM
|
||||
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.TOP
|
||||
import org.jetbrains.anko.constraint.layout.applyConstraintSet
|
||||
import org.mozilla.fenix.Experiments.AATestDescriptor
|
||||
import org.mozilla.fenix.isInExperiment
|
||||
|
||||
internal fun SearchFragment.layoutComponents(layout: ConstraintLayout) {
|
||||
context?.let {
|
||||
when {
|
||||
it.isInExperiment(AATestDescriptor) -> {
|
||||
setInExperimentConstraints(layout)
|
||||
}
|
||||
else -> {
|
||||
setOutOfExperimentConstraints(layout)
|
||||
}
|
||||
}
|
||||
} // we're unattached if context is null
|
||||
}
|
||||
|
||||
internal fun SearchFragment.setInExperimentConstraints(layout: ConstraintLayout) {
|
||||
Logger.debug("Loading in experiment constraints")
|
||||
layout.applyConstraintSet {
|
||||
toolbar_wrapper {
|
||||
connect(
|
||||
TOP to TOP of UNSET,
|
||||
BOTTOM to TOP of pill_wrapper
|
||||
)
|
||||
}
|
||||
awesomeBar {
|
||||
connect(
|
||||
TOP to TOP of PARENT_ID,
|
||||
BOTTOM to TOP of toolbar_wrapper
|
||||
)
|
||||
}
|
||||
(awesomeBar.layoutManager as? LinearLayoutManager)?.reverseLayout = true
|
||||
pill_wrapper {
|
||||
connect(
|
||||
BOTTOM to BOTTOM of PARENT_ID
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun SearchFragment.setOutOfExperimentConstraints(layout: ConstraintLayout) {
|
||||
Logger.debug("Loading out of experiment constraints")
|
||||
layout.applyConstraintSet {
|
||||
toolbar_wrapper {
|
||||
connect(
|
||||
TOP to TOP of PARENT_ID,
|
||||
BOTTOM to TOP of UNSET
|
||||
)
|
||||
}
|
||||
awesomeBar {
|
||||
connect(
|
||||
TOP to TOP of UNSET,
|
||||
TOP to BOTTOM of toolbar_wrapper,
|
||||
BOTTOM to TOP of pill_wrapper
|
||||
)
|
||||
}
|
||||
(awesomeBar.layoutManager as? LinearLayoutManager)?.reverseLayout = false
|
||||
pill_wrapper {
|
||||
connect(
|
||||
BOTTOM to BOTTOM of PARENT_ID
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.fenix.search
|
||||
|
||||
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.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.ext.components
|
||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||
import org.mozilla.fenix.mvi.UIView
|
||||
|
||||
class SearchUIView(container: ViewGroup, bus: ActionBusFactory) :
|
||||
UIView<SearchState>(container, bus) {
|
||||
|
||||
override val view: BrowserToolbar = LayoutInflater.from(container.context)
|
||||
.inflate(R.layout.component_search, container, true)
|
||||
.findViewById(R.id.toolbar)
|
||||
|
||||
private val urlBackground = LayoutInflater.from(container.context)
|
||||
.inflate(R.layout.layout_url_backround, container, false)
|
||||
|
||||
init {
|
||||
view.apply {
|
||||
onUrlClicked = {
|
||||
bus.emit(SearchAction::class.java, SearchAction.UrlClicked)
|
||||
false
|
||||
}
|
||||
|
||||
browserActionMargin = resources.pxToDp(browserActionMarginDp)
|
||||
urlBoxView = urlBackground
|
||||
urlBoxMargin = this.resources.pxToDp(urlBoxMarginDp)
|
||||
|
||||
textColor = ContextCompat.getColor(context, R.color.searchText)
|
||||
textSize = toolbarTextSizeSp
|
||||
hint = context.getString(R.string.search_hint)
|
||||
hintColor = ContextCompat.getColor(context, R.color.searchText)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateView() = Consumer<SearchState> {
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val toolbarTextSizeSp = 14f
|
||||
const val browserActionMarginDp = 8
|
||||
const val urlBoxMarginDp = 8
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<mozilla.components.browser.toolbar.BrowserToolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_margin="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"/>
|
Loading…
Reference in New Issue