Closes #16327: Refactor MenuPresenter to use browser store

upstream-sync
Christian Sadilek 4 years ago
parent 50d7792330
commit 4abd399002

@ -1207,8 +1207,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler,
private const val REQUEST_CODE_DOWNLOAD_PERMISSIONS = 1
private const val REQUEST_CODE_PROMPT_PERMISSIONS = 2
private const val REQUEST_CODE_APP_PERMISSIONS = 3
private const val LOADING_PROGRESS_COMPLETE = 100
}
override fun onAccessibilityStateChanged(enabled: Boolean) {

@ -21,6 +21,7 @@ import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.component_browser_top_toolbar.*
import kotlinx.android.synthetic.main.component_browser_top_toolbar.view.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
import mozilla.components.browser.session.Session
import mozilla.components.browser.state.state.ExternalAppType
@ -49,6 +50,7 @@ interface BrowserToolbarViewInteractor {
fun onReaderModePressed(enabled: Boolean)
}
@ExperimentalCoroutinesApi
@SuppressWarnings("LargeClass")
class BrowserToolbarView(
private val container: ViewGroup,

@ -5,36 +5,46 @@
package org.mozilla.fenix.components.toolbar
import android.view.View
import mozilla.components.browser.session.SelectionAwareSessionObserver
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.mapNotNull
import mozilla.components.browser.state.selector.findCustomTabOrSelectedTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.concept.engine.manifest.WebAppManifest
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged
@ExperimentalCoroutinesApi
class MenuPresenter(
private val menuToolbar: BrowserToolbar,
sessionManager: SessionManager,
private val store: BrowserStore,
private val sessionId: String? = null
) : SelectionAwareSessionObserver(sessionManager), View.OnAttachStateChangeListener {
) : View.OnAttachStateChangeListener {
private var scope: CoroutineScope? = null
fun start() {
observeIdOrSelected(sessionId)
menuToolbar.addOnAttachStateChangeListener(this)
scope = store.flowScoped { flow ->
flow.mapNotNull { state -> state.findCustomTabOrSelectedTab(sessionId) }
.ifAnyChanged { tab ->
arrayOf(
tab.content.loading,
tab.content.canGoBack,
tab.content.canGoForward,
tab.content.webAppManifest
)
}
.collect {
invalidateActions()
}
}
}
/** Redraw the refresh/stop button */
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
invalidateActions()
}
/** Redraw the back and forward buttons */
override fun onNavigationStateChanged(session: Session, canGoBack: Boolean, canGoForward: Boolean) {
invalidateActions()
}
/** Redraw the install web app button */
override fun onWebAppManifestChanged(session: Session, manifest: WebAppManifest?) {
invalidateActions()
fun stop() {
scope?.cancel()
}
fun invalidateActions() {

@ -9,6 +9,7 @@ import android.util.AttributeSet
import android.view.View
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.appbar.AppBarLayout
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.concept.engine.EngineView
import mozilla.components.concept.engine.EngineView.InputResult.INPUT_RESULT_UNHANDLED
import org.mozilla.fenix.ext.settings
@ -16,6 +17,7 @@ import org.mozilla.fenix.ext.settings
/**
* ScrollingViewBehavior that will setScrollFlags on BrowserToolbar based on EngineView touch handling
*/
@ExperimentalCoroutinesApi
class SwipeRefreshScrollingViewBehavior(
context: Context,
attrs: AttributeSet?,

@ -8,6 +8,7 @@ import android.content.Context
import android.content.res.Configuration
import androidx.appcompat.content.res.AppCompatResources
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.browser.domains.autocomplete.DomainAutocompleteProvider
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.browser.toolbar.display.DisplayToolbar
@ -24,6 +25,7 @@ import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.theme.ThemeManager
@ExperimentalCoroutinesApi
abstract class ToolbarIntegration(
context: Context,
toolbar: BrowserToolbar,
@ -45,7 +47,7 @@ abstract class ToolbarIntegration(
)
private val menuPresenter =
MenuPresenter(toolbar, context.components.core.sessionManager, sessionId)
MenuPresenter(toolbar, context.components.core.store, sessionId)
init {
toolbar.display.menuBuilder = toolbarMenu.menuBuilder
@ -67,6 +69,7 @@ abstract class ToolbarIntegration(
}
}
@ExperimentalCoroutinesApi
class DefaultToolbarIntegration(
context: Context,
toolbar: BrowserToolbar,

@ -5,11 +5,13 @@
package org.mozilla.fenix.customtabs
import android.content.Context
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.feature.toolbar.ToolbarFeature
import org.mozilla.fenix.components.toolbar.ToolbarIntegration
import org.mozilla.fenix.components.toolbar.ToolbarMenu
@ExperimentalCoroutinesApi
class CustomTabToolbarIntegration(
context: Context,
toolbar: BrowserToolbar,

@ -0,0 +1,88 @@
/* 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.components.toolbar
import io.mockk.clearMocks
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
import mozilla.components.browser.state.action.ContentAction
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.rule.MainCoroutineRule
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ExperimentalCoroutinesApi
class MenuPresenterTest {
private lateinit var store: BrowserStore
private lateinit var testTab: TabSessionState
private lateinit var menuPresenter: MenuPresenter
private lateinit var menuToolbar: BrowserToolbar
private val testDispatcher = TestCoroutineDispatcher()
@get:Rule
val coroutinesTestRule = MainCoroutineRule(testDispatcher)
@Before
fun setup() {
testTab = createTab(url = "https://mozilla.org")
store = BrowserStore(initialState = BrowserState(tabs = listOf(testTab), selectedTabId = testTab.id))
menuToolbar = mockk(relaxed = true)
menuPresenter = MenuPresenter(menuToolbar, store).also {
it.start()
}
clearMocks(menuToolbar)
}
@Test
fun `WHEN loading state is updated THEN toolbar is invalidated`() {
verify(exactly = 0) { menuToolbar.invalidateActions() }
store.dispatch(ContentAction.UpdateLoadingStateAction(testTab.id, true)).joinBlocking()
verify(exactly = 1) { menuToolbar.invalidateActions() }
store.dispatch(ContentAction.UpdateLoadingStateAction(testTab.id, false)).joinBlocking()
verify(exactly = 2) { menuToolbar.invalidateActions() }
}
@Test
fun `WHEN back navigation state is updated THEN toolbar is invalidated`() {
verify(exactly = 0) { menuToolbar.invalidateActions() }
store.dispatch(ContentAction.UpdateBackNavigationStateAction(testTab.id, true)).joinBlocking()
verify(exactly = 1) { menuToolbar.invalidateActions() }
store.dispatch(ContentAction.UpdateBackNavigationStateAction(testTab.id, false)).joinBlocking()
verify(exactly = 2) { menuToolbar.invalidateActions() }
}
@Test
fun `WHEN forward navigation state is updated THEN toolbar is invalidated`() {
verify(exactly = 0) { menuToolbar.invalidateActions() }
store.dispatch(ContentAction.UpdateForwardNavigationStateAction(testTab.id, true)).joinBlocking()
verify(exactly = 1) { menuToolbar.invalidateActions() }
store.dispatch(ContentAction.UpdateForwardNavigationStateAction(testTab.id, false)).joinBlocking()
verify(exactly = 2) { menuToolbar.invalidateActions() }
}
@Test
fun `WHEN web app manifest is updated THEN toolbar is invalidated`() {
verify(exactly = 0) { menuToolbar.invalidateActions() }
store.dispatch(ContentAction.UpdateWebAppManifestAction(testTab.id, mockk())).joinBlocking()
verify(exactly = 1) { menuToolbar.invalidateActions() }
}
}
Loading…
Cancel
Save