[fenix] For https://github.com/mozilla-mobile/fenix/issues/4124: Migrate BrowserToolbar to Libstate (https://github.com/mozilla-mobile/fenix/pull/4279)
* For https://github.com/mozilla-mobile/fenix/issues/4124: Migrate BrowserToolbar to Libstate * Restores QuickActionSheetReducer * Improve tests * Make QuickActionSheetController * Finalize tests * Breaks out QuickActionSheetState * Fix comments * Adds BrowserStoreTestpull/600/head
parent
4aeab46a23
commit
a8a228e24d
@ -0,0 +1,71 @@
|
|||||||
|
/* 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 android.content.Context
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
|
import org.mozilla.fenix.browser.readermode.ReaderModeController
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
import org.mozilla.fenix.ext.metrics
|
||||||
|
import org.mozilla.fenix.quickactionsheet.QuickActionSheetController
|
||||||
|
import org.mozilla.fenix.quickactionsheet.QuickActionSheetViewInteractor
|
||||||
|
|
||||||
|
class BrowserInteractor(
|
||||||
|
private val context: Context,
|
||||||
|
private val store: BrowserStore,
|
||||||
|
private val browserToolbarController: BrowserToolbarController,
|
||||||
|
private val quickActionSheetController: QuickActionSheetController,
|
||||||
|
private val readerModeController: ReaderModeController,
|
||||||
|
private val currentSession: Session
|
||||||
|
) : BrowserToolbarViewInteractor, QuickActionSheetViewInteractor {
|
||||||
|
|
||||||
|
override fun onBrowserToolbarClicked() {
|
||||||
|
browserToolbarController.handleToolbarClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBrowserToolbarMenuItemTapped(item: ToolbarMenu.Item) {
|
||||||
|
browserToolbarController.handleToolbarItemInteraction(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuickActionSheetOpened() {
|
||||||
|
context.metrics.track(Event.QuickActionSheetOpened)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuickActionSheetClosed() {
|
||||||
|
context.metrics.track(Event.QuickActionSheetClosed)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuickActionSheetSharePressed() {
|
||||||
|
quickActionSheetController.handleShare()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuickActionSheetDownloadPressed() {
|
||||||
|
quickActionSheetController.handleDownload()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuickActionSheetBookmarkPressed() {
|
||||||
|
quickActionSheetController.handleBookmark()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuickActionSheetReadPressed() {
|
||||||
|
context.metrics.track(Event.QuickActionSheetReadTapped)
|
||||||
|
val enabled = currentSession.readerMode
|
||||||
|
if (enabled) {
|
||||||
|
readerModeController.hideReaderView()
|
||||||
|
} else {
|
||||||
|
readerModeController.showReaderView()
|
||||||
|
}
|
||||||
|
store.dispatch(QuickActionSheetAction.ReaderActiveStateChange(!enabled))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuickActionSheetOpenLinkPressed() {
|
||||||
|
quickActionSheetController.handleOpenLink()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuickActionSheetAppearancePressed() {
|
||||||
|
// TODO telemetry: https://github.com/mozilla-mobile/fenix/issues/2267
|
||||||
|
readerModeController.showControls()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/* 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 mozilla.components.lib.state.Action
|
||||||
|
import mozilla.components.lib.state.State
|
||||||
|
import mozilla.components.lib.state.Store
|
||||||
|
|
||||||
|
class BrowserStore(initialState: BrowserState) :
|
||||||
|
Store<BrowserState, BrowserAction>(initialState, ::browserStateReducer)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state for the Browser Screen
|
||||||
|
* @property quickActionSheetState: state of the quick action sheet
|
||||||
|
*/
|
||||||
|
data class BrowserState(
|
||||||
|
val quickActionSheetState: QuickActionSheetState
|
||||||
|
) : State
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state for the QuickActionSheet
|
||||||
|
* @property readable Whether or not the current session can display a reader view
|
||||||
|
* @property bookmarked Whether or not the current session is already bookmarked
|
||||||
|
* @property readerActive Whether or not the current session is in reader mode
|
||||||
|
* @property bounceNeeded Whether or not the quick action sheet should bounce
|
||||||
|
*/
|
||||||
|
data class QuickActionSheetState(
|
||||||
|
val readable: Boolean,
|
||||||
|
val bookmarked: Boolean,
|
||||||
|
val readerActive: Boolean,
|
||||||
|
val bounceNeeded: Boolean,
|
||||||
|
val isAppLink: Boolean
|
||||||
|
) : State
|
||||||
|
|
||||||
|
sealed class BrowserAction : Action
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions to dispatch through the [QuickActionSheetStore] to modify [QuickActionSheetState] through the reducer.
|
||||||
|
*/
|
||||||
|
sealed class QuickActionSheetAction : BrowserAction() {
|
||||||
|
data class BookmarkedStateChange(val bookmarked: Boolean) : QuickActionSheetAction()
|
||||||
|
data class ReadableStateChange(val readable: Boolean) : QuickActionSheetAction()
|
||||||
|
data class ReaderActiveStateChange(val active: Boolean) : QuickActionSheetAction()
|
||||||
|
data class AppLinkStateChange(val isAppLink: Boolean) : QuickActionSheetAction()
|
||||||
|
object BounceNeededChange : QuickActionSheetAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reducers for [BrowserStore].
|
||||||
|
*
|
||||||
|
* A top level reducer that receives the current [BrowserState] and an [Action] and then delegates to the proper child
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun browserStateReducer(
|
||||||
|
state: BrowserState,
|
||||||
|
action: BrowserAction
|
||||||
|
): BrowserState {
|
||||||
|
return when (action) {
|
||||||
|
is QuickActionSheetAction -> {
|
||||||
|
QuickActionSheetStateReducer.reduce(state, action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces [QuickActionSheetAction]s to update [BrowserState].
|
||||||
|
*/
|
||||||
|
internal object QuickActionSheetStateReducer {
|
||||||
|
fun reduce(state: BrowserState, action: QuickActionSheetAction): BrowserState {
|
||||||
|
return when (action) {
|
||||||
|
is QuickActionSheetAction.BookmarkedStateChange ->
|
||||||
|
state.copy(quickActionSheetState = state.quickActionSheetState.copy(bookmarked = action.bookmarked))
|
||||||
|
is QuickActionSheetAction.ReadableStateChange ->
|
||||||
|
state.copy(quickActionSheetState = state.quickActionSheetState.copy(readable = action.readable))
|
||||||
|
is QuickActionSheetAction.ReaderActiveStateChange ->
|
||||||
|
state.copy(quickActionSheetState = state.quickActionSheetState.copy(readerActive = action.active))
|
||||||
|
is QuickActionSheetAction.BounceNeededChange ->
|
||||||
|
state.copy(quickActionSheetState = state.quickActionSheetState.copy(bounceNeeded = true))
|
||||||
|
is QuickActionSheetAction.AppLinkStateChange -> {
|
||||||
|
state.copy(quickActionSheetState = state.quickActionSheetState.copy(isAppLink = action.isAppLink))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
/* 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 android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.core.widget.NestedScrollView
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
|
import mozilla.components.concept.engine.EngineView
|
||||||
|
import org.mozilla.fenix.BrowsingModeManager
|
||||||
|
import org.mozilla.fenix.HomeActivity
|
||||||
|
import org.mozilla.fenix.IntentReceiverActivity
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.browser.BrowserFragment
|
||||||
|
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
||||||
|
import org.mozilla.fenix.collections.CreateCollectionViewModel
|
||||||
|
import org.mozilla.fenix.collections.getStepForCollectionsSize
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
|
import org.mozilla.fenix.ext.nav
|
||||||
|
import org.mozilla.fenix.ext.toTab
|
||||||
|
import org.mozilla.fenix.lib.Do
|
||||||
|
import org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior
|
||||||
|
import org.mozilla.fenix.settings.SupportUtils
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that handles the view manipulation of the BrowserToolbar, triggered by the Interactor
|
||||||
|
*/
|
||||||
|
interface BrowserToolbarController {
|
||||||
|
fun handleToolbarItemInteraction(item: ToolbarMenu.Item)
|
||||||
|
fun handleToolbarClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultBrowserToolbarController(
|
||||||
|
private val context: Context,
|
||||||
|
private val navController: NavController,
|
||||||
|
private val findInPageLauncher: () -> Unit,
|
||||||
|
private val nestedScrollQuickActionView: NestedScrollView,
|
||||||
|
private val engineView: EngineView,
|
||||||
|
private val currentSession: Session,
|
||||||
|
private val viewModel: CreateCollectionViewModel
|
||||||
|
) : BrowserToolbarController {
|
||||||
|
|
||||||
|
override fun handleToolbarClick() {
|
||||||
|
context.components.analytics.metrics.track(
|
||||||
|
Event.SearchBarTapped(Event.SearchBarTapped.Source.BROWSER)
|
||||||
|
)
|
||||||
|
navController.nav(
|
||||||
|
R.id.browserFragment,
|
||||||
|
BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(
|
||||||
|
currentSession.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ComplexMethod")
|
||||||
|
override fun handleToolbarItemInteraction(item: ToolbarMenu.Item) {
|
||||||
|
val sessionUseCases = context.components.useCases.sessionUseCases
|
||||||
|
trackToolbarItemInteraction(item)
|
||||||
|
|
||||||
|
Do exhaustive when (item) {
|
||||||
|
ToolbarMenu.Item.Back -> sessionUseCases.goBack.invoke(currentSession)
|
||||||
|
ToolbarMenu.Item.Forward -> sessionUseCases.goForward.invoke(currentSession)
|
||||||
|
ToolbarMenu.Item.Reload -> sessionUseCases.reload.invoke(currentSession)
|
||||||
|
ToolbarMenu.Item.Stop -> sessionUseCases.stopLoading.invoke(currentSession)
|
||||||
|
ToolbarMenu.Item.Settings -> navController.nav(
|
||||||
|
R.id.browserFragment,
|
||||||
|
BrowserFragmentDirections.actionBrowserFragmentToSettingsFragment()
|
||||||
|
)
|
||||||
|
ToolbarMenu.Item.Library -> navController.nav(
|
||||||
|
R.id.browserFragment,
|
||||||
|
BrowserFragmentDirections.actionBrowserFragmentToLibraryFragment()
|
||||||
|
)
|
||||||
|
is ToolbarMenu.Item.RequestDesktop -> sessionUseCases.requestDesktopSite.invoke(
|
||||||
|
item.isChecked,
|
||||||
|
currentSession
|
||||||
|
)
|
||||||
|
ToolbarMenu.Item.Share -> {
|
||||||
|
currentSession.url.apply {
|
||||||
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToShareFragment(this)
|
||||||
|
navController.nav(R.id.browserFragment, directions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.NewPrivateTab -> {
|
||||||
|
val directions = BrowserFragmentDirections
|
||||||
|
.actionBrowserFragmentToSearchFragment(null)
|
||||||
|
navController.nav(R.id.browserFragment, directions)
|
||||||
|
(context as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.FindInPage -> {
|
||||||
|
(BottomSheetBehavior.from(nestedScrollQuickActionView) as QuickActionSheetBehavior).apply {
|
||||||
|
state = BottomSheetBehavior.STATE_COLLAPSED
|
||||||
|
}
|
||||||
|
findInPageLauncher()
|
||||||
|
context.components.analytics.metrics.track(Event.FindInPageOpened)
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.ReportIssue -> {
|
||||||
|
currentSession.url.apply {
|
||||||
|
val reportUrl = String.format(BrowserFragment.REPORT_SITE_ISSUE_URL, this)
|
||||||
|
context.components.useCases.tabsUseCases.addTab.invoke(reportUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.Help -> {
|
||||||
|
context.components.useCases.tabsUseCases.addTab.invoke(
|
||||||
|
SupportUtils.getSumoURLForTopic(
|
||||||
|
context,
|
||||||
|
SupportUtils.SumoTopic.HELP
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.NewTab -> {
|
||||||
|
val directions = BrowserFragmentDirections
|
||||||
|
.actionBrowserFragmentToSearchFragment(null)
|
||||||
|
navController.nav(R.id.browserFragment, directions)
|
||||||
|
(context as HomeActivity).browsingModeManager.mode =
|
||||||
|
BrowsingModeManager.Mode.Normal
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.SaveToCollection -> {
|
||||||
|
currentSession.let {
|
||||||
|
val tab = it.toTab(context)
|
||||||
|
viewModel.tabs = listOf(tab)
|
||||||
|
val selectedSet = mutableSetOf(tab)
|
||||||
|
viewModel.selectedTabs = selectedSet
|
||||||
|
viewModel.tabCollections =
|
||||||
|
context.components.core.tabCollectionStorage.cachedTabCollections.reversed()
|
||||||
|
viewModel.saveCollectionStep = viewModel.tabCollections.getStepForCollectionsSize()
|
||||||
|
viewModel.snackbarAnchorView = nestedScrollQuickActionView
|
||||||
|
viewModel.previousFragmentId = R.id.browserFragment
|
||||||
|
|
||||||
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment()
|
||||||
|
navController.nav(R.id.browserFragment, directions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.OpenInFenix -> {
|
||||||
|
// Release the session from this view so that it can immediately be rendered by a different view
|
||||||
|
engineView.release()
|
||||||
|
|
||||||
|
// Strip the CustomTabConfig to turn this Session into a regular tab and then select it
|
||||||
|
currentSession.customTabConfig = null
|
||||||
|
context.components.core.sessionManager.select(currentSession)
|
||||||
|
|
||||||
|
// Switch to the actual browser which should now display our new selected session
|
||||||
|
context.startActivity(Intent(context, IntentReceiverActivity::class.java).also {
|
||||||
|
it.action = Intent.ACTION_VIEW
|
||||||
|
it.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
})
|
||||||
|
|
||||||
|
// Close this activity since it is no longer displaying any session
|
||||||
|
(context as Activity).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ComplexMethod")
|
||||||
|
private fun trackToolbarItemInteraction(item: ToolbarMenu.Item) {
|
||||||
|
val eventItem = when (item) {
|
||||||
|
ToolbarMenu.Item.Back -> Event.BrowserMenuItemTapped.Item.BACK
|
||||||
|
ToolbarMenu.Item.Forward -> Event.BrowserMenuItemTapped.Item.FORWARD
|
||||||
|
ToolbarMenu.Item.Reload -> Event.BrowserMenuItemTapped.Item.RELOAD
|
||||||
|
ToolbarMenu.Item.Stop -> Event.BrowserMenuItemTapped.Item.STOP
|
||||||
|
ToolbarMenu.Item.Settings -> Event.BrowserMenuItemTapped.Item.SETTINGS
|
||||||
|
ToolbarMenu.Item.Library -> Event.BrowserMenuItemTapped.Item.LIBRARY
|
||||||
|
is ToolbarMenu.Item.RequestDesktop ->
|
||||||
|
if (item.isChecked) {
|
||||||
|
Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_ON
|
||||||
|
} else {
|
||||||
|
Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_OFF
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolbarMenu.Item.NewPrivateTab -> Event.BrowserMenuItemTapped.Item.NEW_PRIVATE_TAB
|
||||||
|
ToolbarMenu.Item.FindInPage -> Event.BrowserMenuItemTapped.Item.FIND_IN_PAGE
|
||||||
|
ToolbarMenu.Item.ReportIssue -> Event.BrowserMenuItemTapped.Item.REPORT_SITE_ISSUE
|
||||||
|
ToolbarMenu.Item.Help -> Event.BrowserMenuItemTapped.Item.HELP
|
||||||
|
ToolbarMenu.Item.NewTab -> Event.BrowserMenuItemTapped.Item.NEW_TAB
|
||||||
|
ToolbarMenu.Item.OpenInFenix -> Event.BrowserMenuItemTapped.Item.OPEN_IN_FENIX
|
||||||
|
ToolbarMenu.Item.Share -> Event.BrowserMenuItemTapped.Item.SHARE
|
||||||
|
ToolbarMenu.Item.SaveToCollection -> Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION
|
||||||
|
}
|
||||||
|
|
||||||
|
context.components.analytics.metrics.track(Event.BrowserMenuItemTapped(eventItem))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
package org.mozilla.fenix.components.toolbar
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
|
import mozilla.components.browser.toolbar.BrowserToolbar
|
||||||
|
import mozilla.components.support.ktx.android.util.dpToFloat
|
||||||
|
import mozilla.components.support.ktx.android.util.dpToPx
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ThemeManager
|
||||||
|
import org.mozilla.fenix.customtabs.CustomTabToolbarMenu
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
|
|
||||||
|
interface BrowserToolbarViewInteractor {
|
||||||
|
fun onBrowserToolbarClicked()
|
||||||
|
fun onBrowserToolbarMenuItemTapped(item: ToolbarMenu.Item)
|
||||||
|
}
|
||||||
|
|
||||||
|
class BrowserToolbarView(
|
||||||
|
private val container: ViewGroup,
|
||||||
|
private val interactor: BrowserToolbarViewInteractor,
|
||||||
|
private val currentSession: Session
|
||||||
|
) : LayoutContainer {
|
||||||
|
|
||||||
|
override val containerView: View?
|
||||||
|
get() = container
|
||||||
|
|
||||||
|
private val urlBackground = LayoutInflater.from(container.context)
|
||||||
|
.inflate(R.layout.layout_url_background, container, false)
|
||||||
|
|
||||||
|
val view: BrowserToolbar = LayoutInflater.from(container.context)
|
||||||
|
.inflate(R.layout.component_search, container, true)
|
||||||
|
.findViewById(R.id.toolbar)
|
||||||
|
|
||||||
|
val toolbarIntegration: ToolbarIntegration
|
||||||
|
|
||||||
|
init {
|
||||||
|
// We need access to the customSessionId. We don't directly have access since we aren't passing session id in
|
||||||
|
// So we need to access it through the store...?
|
||||||
|
|
||||||
|
with(container.context) {
|
||||||
|
val sessionManager = components.core.sessionManager
|
||||||
|
val isCustomTabSession = currentSession.isCustomTabSession()
|
||||||
|
|
||||||
|
view.apply {
|
||||||
|
elevation = TOOLBAR_ELEVATION.dpToFloat(resources.displayMetrics)
|
||||||
|
|
||||||
|
onUrlClicked = {
|
||||||
|
interactor.onBrowserToolbarClicked()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
browserActionMargin = browserActionMarginDp.dpToPx(resources.displayMetrics)
|
||||||
|
|
||||||
|
urlBoxView = if (isCustomTabSession) null else urlBackground
|
||||||
|
progressBarGravity = if (isCustomTabSession) PROGRESS_BOTTOM else PROGRESS_TOP
|
||||||
|
|
||||||
|
textColor = ContextCompat.getColor(context, R.color.photonGrey30)
|
||||||
|
|
||||||
|
hint = context.getString(R.string.search_hint)
|
||||||
|
|
||||||
|
suggestionBackgroundColor = ContextCompat.getColor(
|
||||||
|
container.context,
|
||||||
|
R.color.suggestion_highlight_color
|
||||||
|
)
|
||||||
|
|
||||||
|
textColor = ContextCompat.getColor(
|
||||||
|
container.context,
|
||||||
|
ThemeManager.resolveAttribute(R.attr.primaryText, container.context)
|
||||||
|
)
|
||||||
|
|
||||||
|
hintColor = ContextCompat.getColor(
|
||||||
|
container.context,
|
||||||
|
ThemeManager.resolveAttribute(R.attr.secondaryText, container.context)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val menuToolbar = if (isCustomTabSession) {
|
||||||
|
CustomTabToolbarMenu(
|
||||||
|
this,
|
||||||
|
sessionManager,
|
||||||
|
currentSession.id,
|
||||||
|
onItemTapped = {
|
||||||
|
interactor.onBrowserToolbarMenuItemTapped(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
DefaultToolbarMenu(
|
||||||
|
this,
|
||||||
|
hasAccountProblem = components.backgroundServices.accountManager.accountNeedsReauth(),
|
||||||
|
requestDesktopStateProvider = { currentSession.desktopMode },
|
||||||
|
onItemTapped = { interactor.onBrowserToolbarMenuItemTapped(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbarIntegration = ToolbarIntegration(
|
||||||
|
this,
|
||||||
|
view,
|
||||||
|
container,
|
||||||
|
menuToolbar,
|
||||||
|
ShippedDomainsProvider().also { it.initialize(this) },
|
||||||
|
components.core.historyStorage,
|
||||||
|
components.core.sessionManager,
|
||||||
|
currentSession.id,
|
||||||
|
currentSession.private
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(state: BrowserState) {
|
||||||
|
// TODO Leaving this as a stub for now since we don't actually have anything to update ever...?
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TOOLBAR_ELEVATION = 16
|
||||||
|
private const val PROGRESS_BOTTOM = 0
|
||||||
|
private const val PROGRESS_TOP = 1
|
||||||
|
const val browserActionMarginDp = 8
|
||||||
|
}
|
||||||
|
}
|
@ -1,63 +0,0 @@
|
|||||||
/* 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 android.view.ViewGroup
|
|
||||||
import kotlinx.android.synthetic.main.component_search.*
|
|
||||||
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.UIComponentViewModelBase
|
|
||||||
import org.mozilla.fenix.mvi.UIComponentViewModelProvider
|
|
||||||
import org.mozilla.fenix.mvi.ViewState
|
|
||||||
|
|
||||||
class ToolbarComponent(
|
|
||||||
private val container: ViewGroup,
|
|
||||||
bus: ActionBusFactory,
|
|
||||||
private val sessionId: String?,
|
|
||||||
private val isPrivate: Boolean,
|
|
||||||
viewModelProvider: UIComponentViewModelProvider<SearchState, SearchChange>
|
|
||||||
) :
|
|
||||||
UIComponent<SearchState, SearchAction, SearchChange>(
|
|
||||||
bus.getManagedEmitter(SearchAction::class.java),
|
|
||||||
bus.getSafeManagedObservable(SearchChange::class.java),
|
|
||||||
viewModelProvider
|
|
||||||
) {
|
|
||||||
|
|
||||||
override fun initView() = ToolbarUIView(
|
|
||||||
sessionId,
|
|
||||||
isPrivate,
|
|
||||||
container,
|
|
||||||
actionEmitter,
|
|
||||||
changesObservable
|
|
||||||
)
|
|
||||||
|
|
||||||
init {
|
|
||||||
bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setOnSiteSecurityClickedListener(listener: () -> Unit) {
|
|
||||||
uiView.toolbar.setOnSiteSecurityClickedListener(listener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SearchState : ViewState
|
|
||||||
|
|
||||||
sealed class SearchAction : Action {
|
|
||||||
object ToolbarClicked : SearchAction()
|
|
||||||
data class ToolbarMenuItemTapped(val item: ToolbarMenu.Item) : SearchAction()
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class SearchChange : Change
|
|
||||||
|
|
||||||
class ToolbarViewModel(initialState: SearchState) :
|
|
||||||
UIComponentViewModelBase<SearchState, SearchChange>(initialState, reducer) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val reducer: Reducer<SearchState, SearchChange> = { state, _ -> state }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/* 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 org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.components.metrics.MetricController
|
|
||||||
|
|
||||||
// This method triggers the complexity warning. However it's actually not that hard to understand.
|
|
||||||
@SuppressWarnings("ComplexMethod")
|
|
||||||
fun trackToolbarItemInteraction(metrics: MetricController, action: SearchAction.ToolbarMenuItemTapped) {
|
|
||||||
val item = when (action.item) {
|
|
||||||
ToolbarMenu.Item.Back -> Event.BrowserMenuItemTapped.Item.BACK
|
|
||||||
ToolbarMenu.Item.Forward -> Event.BrowserMenuItemTapped.Item.FORWARD
|
|
||||||
ToolbarMenu.Item.Reload -> Event.BrowserMenuItemTapped.Item.RELOAD
|
|
||||||
ToolbarMenu.Item.Stop -> Event.BrowserMenuItemTapped.Item.STOP
|
|
||||||
ToolbarMenu.Item.Settings -> Event.BrowserMenuItemTapped.Item.SETTINGS
|
|
||||||
ToolbarMenu.Item.Library -> Event.BrowserMenuItemTapped.Item.LIBRARY
|
|
||||||
is ToolbarMenu.Item.RequestDesktop -> if (action.item.isChecked) {
|
|
||||||
Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_ON
|
|
||||||
} else {
|
|
||||||
Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_OFF
|
|
||||||
}
|
|
||||||
ToolbarMenu.Item.NewPrivateTab -> Event.BrowserMenuItemTapped.Item.NEW_PRIVATE_TAB
|
|
||||||
ToolbarMenu.Item.FindInPage -> Event.BrowserMenuItemTapped.Item.FIND_IN_PAGE
|
|
||||||
ToolbarMenu.Item.ReportIssue -> Event.BrowserMenuItemTapped.Item.REPORT_SITE_ISSUE
|
|
||||||
ToolbarMenu.Item.Help -> Event.BrowserMenuItemTapped.Item.HELP
|
|
||||||
ToolbarMenu.Item.NewTab -> Event.BrowserMenuItemTapped.Item.NEW_TAB
|
|
||||||
ToolbarMenu.Item.OpenInFenix -> Event.BrowserMenuItemTapped.Item.OPEN_IN_FENIX
|
|
||||||
ToolbarMenu.Item.Share -> Event.BrowserMenuItemTapped.Item.SHARE
|
|
||||||
ToolbarMenu.Item.SaveToCollection -> Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION
|
|
||||||
}
|
|
||||||
|
|
||||||
metrics.track(Event.BrowserMenuItemTapped(item))
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
/* 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 android.view.LayoutInflater
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import io.reactivex.Observable
|
|
||||||
import io.reactivex.Observer
|
|
||||||
import io.reactivex.functions.Consumer
|
|
||||||
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
|
|
||||||
import mozilla.components.browser.toolbar.BrowserToolbar
|
|
||||||
import mozilla.components.support.ktx.android.util.dpToFloat
|
|
||||||
import mozilla.components.support.ktx.android.util.dpToPx
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.customtabs.CustomTabToolbarMenu
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.ext.getColorFromAttr
|
|
||||||
import org.mozilla.fenix.mvi.UIView
|
|
||||||
|
|
||||||
class ToolbarUIView(
|
|
||||||
sessionId: String?,
|
|
||||||
isPrivate: Boolean,
|
|
||||||
container: ViewGroup,
|
|
||||||
actionEmitter: Observer<SearchAction>,
|
|
||||||
changesObservable: Observable<SearchChange>
|
|
||||||
) :
|
|
||||||
UIView<SearchState, SearchAction, SearchChange>(container, actionEmitter, changesObservable) {
|
|
||||||
|
|
||||||
val toolbarIntegration: ToolbarIntegration
|
|
||||||
|
|
||||||
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_background, container, false)
|
|
||||||
|
|
||||||
init {
|
|
||||||
val sessionManager = view.context.components.core.sessionManager
|
|
||||||
val session = sessionId?.let { sessionManager.findSessionById(it) }
|
|
||||||
?: sessionManager.selectedSession
|
|
||||||
val isCustomTabSession = session?.isCustomTabSession() == true
|
|
||||||
|
|
||||||
view.apply {
|
|
||||||
elevation = TOOLBAR_ELEVATION.dpToFloat(resources.displayMetrics)
|
|
||||||
|
|
||||||
onUrlClicked = {
|
|
||||||
actionEmitter.onNext(SearchAction.ToolbarClicked)
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
browserActionMargin = browserActionMarginDp.dpToPx(resources.displayMetrics)
|
|
||||||
|
|
||||||
urlBoxView = if (isCustomTabSession) null else urlBackground
|
|
||||||
progressBarGravity = if (isCustomTabSession) PROGRESS_BOTTOM else PROGRESS_TOP
|
|
||||||
|
|
||||||
textColor = ContextCompat.getColor(context, R.color.photonGrey30)
|
|
||||||
|
|
||||||
hint = context.getString(R.string.search_hint)
|
|
||||||
|
|
||||||
suggestionBackgroundColor = ContextCompat.getColor(context, R.color.suggestion_highlight_color)
|
|
||||||
textColor = context.getColorFromAttr(R.attr.primaryText)
|
|
||||||
hintColor = context.getColorFromAttr(R.attr.secondaryText)
|
|
||||||
}
|
|
||||||
|
|
||||||
with(view.context) {
|
|
||||||
val menuToolbar = if (isCustomTabSession) {
|
|
||||||
CustomTabToolbarMenu(
|
|
||||||
this,
|
|
||||||
sessionManager,
|
|
||||||
sessionId,
|
|
||||||
onItemTapped = { actionEmitter.onNext(SearchAction.ToolbarMenuItemTapped(it)) }
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
DefaultToolbarMenu(this,
|
|
||||||
hasAccountProblem = components.backgroundServices.accountManager.accountNeedsReauth(),
|
|
||||||
requestDesktopStateProvider = { session?.desktopMode ?: false },
|
|
||||||
onItemTapped = { actionEmitter.onNext(SearchAction.ToolbarMenuItemTapped(it)) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
toolbarIntegration = ToolbarIntegration(
|
|
||||||
this,
|
|
||||||
view,
|
|
||||||
container,
|
|
||||||
menuToolbar,
|
|
||||||
ShippedDomainsProvider().also { it.initialize(this) },
|
|
||||||
components.core.historyStorage,
|
|
||||||
components.core.sessionManager,
|
|
||||||
sessionId,
|
|
||||||
isPrivate
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateView() = Consumer<SearchState> {}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TOOLBAR_ELEVATION = 16
|
|
||||||
private const val PROGRESS_BOTTOM = 0
|
|
||||||
private const val PROGRESS_TOP = 1
|
|
||||||
const val browserActionMarginDp = 8
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/* 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.quickactionsheet
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.annotation.CallSuper
|
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.feature.app.links.AppLinksUseCases
|
|
||||||
import org.mozilla.fenix.browser.readermode.ReaderModeController
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.ext.metrics
|
|
||||||
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interactor for the QuickActionSheet
|
|
||||||
*/
|
|
||||||
class QuickActionInteractor(
|
|
||||||
private val context: Context,
|
|
||||||
private val readerModeController: ReaderModeController,
|
|
||||||
private val quickActionStore: QuickActionSheetStore,
|
|
||||||
private val shareUrl: (String) -> Unit,
|
|
||||||
private val bookmarkTapped: (Session) -> Unit,
|
|
||||||
private val appLinksUseCases: AppLinksUseCases
|
|
||||||
) : QuickActionSheetInteractor {
|
|
||||||
|
|
||||||
private val selectedSession
|
|
||||||
inline get() = context.components.core.sessionManager.selectedSession
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onOpened() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetOpened)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onClosed() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onSharedPressed() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetShareTapped)
|
|
||||||
selectedSession?.url?.let(shareUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onDownloadsPressed() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetDownloadTapped)
|
|
||||||
ItsNotBrokenSnack(context).showSnackbar(issueNumber = "348")
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onBookmarkPressed() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetBookmarkTapped)
|
|
||||||
selectedSession?.let(bookmarkTapped)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onReadPressed() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetReadTapped)
|
|
||||||
val enabled = selectedSession?.readerMode ?: false
|
|
||||||
if (enabled) {
|
|
||||||
readerModeController.hideReaderView()
|
|
||||||
} else {
|
|
||||||
readerModeController.showReaderView()
|
|
||||||
}
|
|
||||||
quickActionStore.dispatch(QuickActionSheetAction.ReaderActiveStateChange(!enabled))
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onOpenAppLinkPressed() {
|
|
||||||
val getRedirect = appLinksUseCases.appLinkRedirect
|
|
||||||
val redirect = selectedSession?.let {
|
|
||||||
getRedirect.invoke(it.url)
|
|
||||||
} ?: return
|
|
||||||
|
|
||||||
redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
appLinksUseCases.openAppLink.invoke(redirect)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onAppearancePressed() {
|
|
||||||
// TODO telemetry: https://github.com/mozilla-mobile/fenix/issues/2267
|
|
||||||
readerModeController.showControls()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,64 @@
|
|||||||
|
/* 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.quickactionsheet
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
|
import mozilla.components.feature.app.links.AppLinksUseCases
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
import org.mozilla.fenix.ext.metrics
|
||||||
|
import org.mozilla.fenix.ext.nav
|
||||||
|
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that handles the view manipulation of the QuickActionSheet, triggered by the Interactor
|
||||||
|
*/
|
||||||
|
interface QuickActionSheetController {
|
||||||
|
fun handleShare()
|
||||||
|
fun handleDownload()
|
||||||
|
fun handleBookmark()
|
||||||
|
fun handleOpenLink()
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultQuickActionSheetController(
|
||||||
|
private val context: Context,
|
||||||
|
private val navController: NavController,
|
||||||
|
private val currentSession: Session,
|
||||||
|
private val appLinksUseCases: AppLinksUseCases,
|
||||||
|
private val bookmarkTapped: (Session) -> Unit
|
||||||
|
) : QuickActionSheetController {
|
||||||
|
|
||||||
|
override fun handleShare() {
|
||||||
|
context.metrics.track(Event.QuickActionSheetShareTapped)
|
||||||
|
currentSession.url.let {
|
||||||
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToShareFragment(it)
|
||||||
|
navController.nav(R.id.browserFragment, directions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleDownload() {
|
||||||
|
context.metrics.track(Event.QuickActionSheetDownloadTapped)
|
||||||
|
ItsNotBrokenSnack(context).showSnackbar(issueNumber = "348")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleBookmark() {
|
||||||
|
context.metrics.track(Event.QuickActionSheetBookmarkTapped)
|
||||||
|
bookmarkTapped(currentSession)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleOpenLink() {
|
||||||
|
val getRedirect = appLinksUseCases.appLinkRedirect
|
||||||
|
val redirect = currentSession.let {
|
||||||
|
getRedirect.invoke(it.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
appLinksUseCases.openAppLink.invoke(redirect)
|
||||||
|
}
|
||||||
|
}
|
@ -1,63 +0,0 @@
|
|||||||
/* 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.quickactionsheet
|
|
||||||
|
|
||||||
import mozilla.components.lib.state.Action
|
|
||||||
import mozilla.components.lib.state.State
|
|
||||||
import mozilla.components.lib.state.Store
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The [Store] for holding the [QuickActionSheetState] and applying [QuickActionSheetAction]s.
|
|
||||||
*/
|
|
||||||
class QuickActionSheetStore(initialState: QuickActionSheetState) :
|
|
||||||
Store<QuickActionSheetState, QuickActionSheetAction>(initialState, ::quickActionSheetStateReducer)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The state for the QuickActionSheet found in the Browser Fragment
|
|
||||||
* @property readable Whether or not the current session can display a reader view
|
|
||||||
* @property bookmarked Whether or not the current session is already bookmarked
|
|
||||||
* @property readerActive Whether or not the current session is in reader mode
|
|
||||||
* @property bounceNeeded Whether or not the quick action sheet should bounce
|
|
||||||
*/
|
|
||||||
data class QuickActionSheetState(
|
|
||||||
val readable: Boolean,
|
|
||||||
val bookmarked: Boolean,
|
|
||||||
val readerActive: Boolean,
|
|
||||||
val bounceNeeded: Boolean,
|
|
||||||
val isAppLink: Boolean
|
|
||||||
) : State
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Actions to dispatch through the [QuickActionSheetStore] to modify [QuickActionSheetState] through the reducer.
|
|
||||||
*/
|
|
||||||
sealed class QuickActionSheetAction : Action {
|
|
||||||
data class BookmarkedStateChange(val bookmarked: Boolean) : QuickActionSheetAction()
|
|
||||||
data class ReadableStateChange(val readable: Boolean) : QuickActionSheetAction()
|
|
||||||
data class ReaderActiveStateChange(val active: Boolean) : QuickActionSheetAction()
|
|
||||||
data class AppLinkStateChange(val isAppLink: Boolean) : QuickActionSheetAction()
|
|
||||||
object BounceNeededChange : QuickActionSheetAction()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reduces [QuickActionSheetAction]s to update [QuickActionSheetState].
|
|
||||||
*/
|
|
||||||
fun quickActionSheetStateReducer(
|
|
||||||
state: QuickActionSheetState,
|
|
||||||
action: QuickActionSheetAction
|
|
||||||
): QuickActionSheetState {
|
|
||||||
return when (action) {
|
|
||||||
is QuickActionSheetAction.BookmarkedStateChange ->
|
|
||||||
state.copy(bookmarked = action.bookmarked)
|
|
||||||
is QuickActionSheetAction.ReadableStateChange ->
|
|
||||||
state.copy(readable = action.readable)
|
|
||||||
is QuickActionSheetAction.ReaderActiveStateChange ->
|
|
||||||
state.copy(readerActive = action.active)
|
|
||||||
is QuickActionSheetAction.BounceNeededChange ->
|
|
||||||
state.copy(bounceNeeded = true)
|
|
||||||
is QuickActionSheetAction.AppLinkStateChange -> {
|
|
||||||
state.copy(isAppLink = action.isAppLink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,258 @@
|
|||||||
|
package org.mozilla.fenix.components.toolbar
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import org.mozilla.fenix.browser.readermode.ReaderModeController
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
|
import org.mozilla.fenix.ext.metrics
|
||||||
|
import org.mozilla.fenix.quickactionsheet.QuickActionSheetController
|
||||||
|
|
||||||
|
class BrowserInteractorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onBrowserToolbarClicked() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val browserToolbarController: BrowserToolbarController = mockk(relaxed = true)
|
||||||
|
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
browserToolbarController,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk()
|
||||||
|
)
|
||||||
|
|
||||||
|
interactor.onBrowserToolbarClicked()
|
||||||
|
|
||||||
|
verify { browserToolbarController.handleToolbarClick() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onBrowserToolbarMenuItemTapped() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val browserToolbarController: BrowserToolbarController = mockk(relaxed = true)
|
||||||
|
val item: ToolbarMenu.Item = mockk()
|
||||||
|
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
browserToolbarController,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk()
|
||||||
|
)
|
||||||
|
|
||||||
|
interactor.onBrowserToolbarMenuItemTapped(item)
|
||||||
|
|
||||||
|
verify { browserToolbarController.handleToolbarItemInteraction(item) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetOpened() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val metrics: MetricController = mockk()
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk()
|
||||||
|
)
|
||||||
|
|
||||||
|
every { context.metrics } returns metrics
|
||||||
|
every { metrics.track(Event.QuickActionSheetOpened) } just Runs
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetOpened()
|
||||||
|
|
||||||
|
verify { metrics.track(Event.QuickActionSheetOpened) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetClosed() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val metrics: MetricController = mockk()
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk()
|
||||||
|
)
|
||||||
|
|
||||||
|
every { context.metrics } returns metrics
|
||||||
|
every { metrics.track(Event.QuickActionSheetClosed) } just Runs
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetClosed()
|
||||||
|
|
||||||
|
verify { metrics.track(Event.QuickActionSheetClosed) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetSharePressed() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val session: Session = mockk()
|
||||||
|
val quickActionSheetController: QuickActionSheetController = mockk(relaxed = true)
|
||||||
|
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
quickActionSheetController,
|
||||||
|
mockk(),
|
||||||
|
session
|
||||||
|
)
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetSharePressed()
|
||||||
|
|
||||||
|
verify { quickActionSheetController.handleShare() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetDownloadPressed() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val metrics: MetricController = mockk()
|
||||||
|
val quickActionSheetController: QuickActionSheetController = mockk(relaxed = true)
|
||||||
|
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
quickActionSheetController,
|
||||||
|
mockk(),
|
||||||
|
mockk()
|
||||||
|
)
|
||||||
|
|
||||||
|
every { context.metrics } returns metrics
|
||||||
|
every { metrics.track(Event.QuickActionSheetDownloadTapped) } just Runs
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetDownloadPressed()
|
||||||
|
|
||||||
|
verify { quickActionSheetController.handleDownload() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetBookmarkPressed() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val session: Session = mockk()
|
||||||
|
val quickActionSheetController: QuickActionSheetController = mockk(relaxed = true)
|
||||||
|
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
quickActionSheetController,
|
||||||
|
mockk(),
|
||||||
|
session
|
||||||
|
)
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetBookmarkPressed()
|
||||||
|
|
||||||
|
verify { quickActionSheetController.handleBookmark() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetReadPressed() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val metrics: MetricController = mockk()
|
||||||
|
val session: Session = mockk()
|
||||||
|
val readerModeController: ReaderModeController = mockk(relaxed = true)
|
||||||
|
val browserStore: BrowserStore = mockk(relaxed = true)
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
browserStore,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
readerModeController,
|
||||||
|
session
|
||||||
|
)
|
||||||
|
|
||||||
|
every { context.metrics } returns metrics
|
||||||
|
every { context.components.core.sessionManager.selectedSession } returns session
|
||||||
|
every { session.readerMode } returns false
|
||||||
|
every { metrics.track(Event.QuickActionSheetReadTapped) } just Runs
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetReadPressed()
|
||||||
|
|
||||||
|
verify { metrics.track(Event.QuickActionSheetReadTapped) }
|
||||||
|
verify { readerModeController.showReaderView() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetReadPressedWithActiveReaderMode() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val metrics: MetricController = mockk()
|
||||||
|
val session: Session = mockk()
|
||||||
|
val readerModeController: ReaderModeController = mockk(relaxed = true)
|
||||||
|
val browserStore: BrowserStore = mockk(relaxed = true)
|
||||||
|
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
browserStore,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
readerModeController,
|
||||||
|
session
|
||||||
|
)
|
||||||
|
|
||||||
|
every { context.metrics } returns metrics
|
||||||
|
every { context.components.core.sessionManager.selectedSession } returns session
|
||||||
|
every { session.readerMode } returns true
|
||||||
|
every { metrics.track(Event.QuickActionSheetReadTapped) } just Runs
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetReadPressed()
|
||||||
|
|
||||||
|
verify { metrics.track(Event.QuickActionSheetReadTapped) }
|
||||||
|
verify { readerModeController.hideReaderView() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetOpenLinkPressed() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val session: Session = mockk()
|
||||||
|
val quickActionSheetController: QuickActionSheetController = mockk(relaxed = true)
|
||||||
|
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
quickActionSheetController,
|
||||||
|
mockk(),
|
||||||
|
session
|
||||||
|
)
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetOpenLinkPressed()
|
||||||
|
|
||||||
|
verify { quickActionSheetController.handleOpenLink() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onQuickActionSheetAppearancePressed() {
|
||||||
|
val context: Context = mockk()
|
||||||
|
val readerModeController: ReaderModeController = mockk(relaxed = true)
|
||||||
|
|
||||||
|
val interactor = BrowserInteractor(
|
||||||
|
context,
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
mockk(),
|
||||||
|
readerModeController,
|
||||||
|
mockk()
|
||||||
|
)
|
||||||
|
|
||||||
|
interactor.onQuickActionSheetAppearancePressed()
|
||||||
|
|
||||||
|
verify { readerModeController.showControls() }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/* 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 kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNotSame
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class BrowserStoreTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun bookmarkStateChange() = runBlocking {
|
||||||
|
val initialState = defaultBrowserState()
|
||||||
|
val store = BrowserStore(initialState)
|
||||||
|
|
||||||
|
store.dispatch(QuickActionSheetAction.BookmarkedStateChange(true)).join()
|
||||||
|
assertNotSame(initialState, store.state)
|
||||||
|
assertEquals(store.state.quickActionSheetState.bookmarked, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun readableStateChange() = runBlocking {
|
||||||
|
val initialState = defaultBrowserState()
|
||||||
|
val store = BrowserStore(initialState)
|
||||||
|
|
||||||
|
store.dispatch(QuickActionSheetAction.ReadableStateChange(true)).join()
|
||||||
|
assertNotSame(initialState, store.state)
|
||||||
|
assertEquals(store.state.quickActionSheetState.readable, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun readerActiveStateChange() = runBlocking {
|
||||||
|
val initialState = defaultBrowserState()
|
||||||
|
val store = BrowserStore(initialState)
|
||||||
|
|
||||||
|
store.dispatch(QuickActionSheetAction.ReaderActiveStateChange(true)).join()
|
||||||
|
assertNotSame(initialState, store.state)
|
||||||
|
assertEquals(store.state.quickActionSheetState.readerActive, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun bounceNeededChange() = runBlocking {
|
||||||
|
val initialState = defaultBrowserState()
|
||||||
|
val store = BrowserStore(initialState)
|
||||||
|
|
||||||
|
store.dispatch(QuickActionSheetAction.BounceNeededChange).join()
|
||||||
|
assertNotSame(initialState, store.state)
|
||||||
|
assertEquals(store.state.quickActionSheetState.bounceNeeded, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun appLinkStateChange() = runBlocking {
|
||||||
|
val initialState = defaultBrowserState()
|
||||||
|
val store = BrowserStore(initialState)
|
||||||
|
|
||||||
|
store.dispatch(QuickActionSheetAction.AppLinkStateChange(true)).join()
|
||||||
|
assertNotSame(initialState, store.state)
|
||||||
|
assertEquals(store.state.quickActionSheetState.isAppLink, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun defaultBrowserState(): BrowserState = BrowserState(
|
||||||
|
quickActionSheetState = defaultQuickActionSheetState()
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun defaultQuickActionSheetState(): QuickActionSheetState = QuickActionSheetState(
|
||||||
|
readable = false,
|
||||||
|
bookmarked = false,
|
||||||
|
readerActive = false,
|
||||||
|
bounceNeeded = false,
|
||||||
|
isAppLink = false
|
||||||
|
)
|
||||||
|
}
|
@ -1,274 +0,0 @@
|
|||||||
/* 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.quickactionsheet
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import io.mockk.Runs
|
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.just
|
|
||||||
import io.mockk.mockk
|
|
||||||
import io.mockk.verify
|
|
||||||
import junit.framework.Assert.assertEquals
|
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.browser.session.SessionManager
|
|
||||||
import mozilla.components.feature.app.links.AppLinkRedirect
|
|
||||||
import mozilla.components.feature.app.links.AppLinksUseCases
|
|
||||||
import org.junit.Test
|
|
||||||
import org.mozilla.fenix.browser.readermode.ReaderModeController
|
|
||||||
import org.mozilla.fenix.components.Analytics
|
|
||||||
import org.mozilla.fenix.components.Components
|
|
||||||
import org.mozilla.fenix.components.Core
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.components.metrics.MetricController
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.ext.metrics
|
|
||||||
|
|
||||||
class QuickActionInteractorTest {
|
|
||||||
@Test
|
|
||||||
fun onOpened() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val metrics: MetricController = mockk()
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk()
|
|
||||||
)
|
|
||||||
|
|
||||||
every { context.metrics } returns metrics
|
|
||||||
every { metrics.track(Event.QuickActionSheetOpened) } just Runs
|
|
||||||
|
|
||||||
interactor.onOpened()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetOpened) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onClosed() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val metrics: MetricController = mockk()
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk()
|
|
||||||
)
|
|
||||||
|
|
||||||
every { context.metrics } returns metrics
|
|
||||||
every { metrics.track(Event.QuickActionSheetClosed) } just Runs
|
|
||||||
|
|
||||||
interactor.onClosed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetClosed) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onSharedPressed() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val session: Session = mockk()
|
|
||||||
var selectedSessionUrl = ""
|
|
||||||
|
|
||||||
val metrics: MetricController = mockk()
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
{ selectedSessionUrl = it },
|
|
||||||
mockk(),
|
|
||||||
mockk()
|
|
||||||
)
|
|
||||||
|
|
||||||
val components: Components = mockk()
|
|
||||||
val core: Core = mockk()
|
|
||||||
val sessionManager: SessionManager = mockk()
|
|
||||||
|
|
||||||
val analytics: Analytics = mockk()
|
|
||||||
|
|
||||||
every { session.url } returns "mozilla.org"
|
|
||||||
every { context.components } returns components
|
|
||||||
every { components.analytics } returns analytics
|
|
||||||
every { metrics.track(Event.QuickActionSheetShareTapped) } just Runs
|
|
||||||
// Since we are mocking components, we must manually define metrics as `analytics.metrics`
|
|
||||||
every { analytics.metrics } returns metrics
|
|
||||||
every { components.core } returns core
|
|
||||||
every { core.sessionManager } returns sessionManager
|
|
||||||
every { sessionManager.selectedSession } returns session
|
|
||||||
|
|
||||||
interactor.onSharedPressed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetShareTapped) }
|
|
||||||
assertEquals("mozilla.org", selectedSessionUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onDownloadsPressed() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val metrics: MetricController = mockk()
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk()
|
|
||||||
)
|
|
||||||
|
|
||||||
every { context.metrics } returns metrics
|
|
||||||
every { metrics.track(Event.QuickActionSheetDownloadTapped) } just Runs
|
|
||||||
|
|
||||||
interactor.onDownloadsPressed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetDownloadTapped) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onBookmarkPressed() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val session: Session = mockk()
|
|
||||||
var bookmarkedSession: Session? = null
|
|
||||||
|
|
||||||
val metrics: MetricController = mockk()
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
{ bookmarkedSession = it },
|
|
||||||
mockk()
|
|
||||||
)
|
|
||||||
|
|
||||||
val components: Components = mockk()
|
|
||||||
val core: Core = mockk()
|
|
||||||
val sessionManager: SessionManager = mockk()
|
|
||||||
|
|
||||||
val analytics: Analytics = mockk()
|
|
||||||
|
|
||||||
every { session.url } returns "mozilla.org"
|
|
||||||
every { context.components } returns components
|
|
||||||
every { components.analytics } returns analytics
|
|
||||||
every { metrics.track(Event.QuickActionSheetBookmarkTapped) } just Runs
|
|
||||||
// Since we are mocking components, we must manually define metrics as `analytics.metrics`
|
|
||||||
every { analytics.metrics } returns metrics
|
|
||||||
every { components.core } returns core
|
|
||||||
every { core.sessionManager } returns sessionManager
|
|
||||||
every { sessionManager.selectedSession } returns session
|
|
||||||
|
|
||||||
interactor.onBookmarkPressed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetBookmarkTapped) }
|
|
||||||
assertEquals("mozilla.org", bookmarkedSession?.url)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onReadPressed() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val metrics: MetricController = mockk()
|
|
||||||
val session: Session = mockk()
|
|
||||||
val readerModeController: ReaderModeController = mockk(relaxed = true)
|
|
||||||
val quickActionSheetStore: QuickActionSheetStore = mockk(relaxed = true)
|
|
||||||
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
readerModeController,
|
|
||||||
quickActionSheetStore,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk()
|
|
||||||
)
|
|
||||||
|
|
||||||
every { context.metrics } returns metrics
|
|
||||||
every { context.components.core.sessionManager.selectedSession } returns session
|
|
||||||
every { session.readerMode } returns false
|
|
||||||
every { metrics.track(Event.QuickActionSheetReadTapped) } just Runs
|
|
||||||
|
|
||||||
interactor.onReadPressed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetReadTapped) }
|
|
||||||
verify { readerModeController.showReaderView() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onReadPressedWithActiveReaderMode() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val metrics: MetricController = mockk()
|
|
||||||
val session: Session = mockk()
|
|
||||||
val readerModeController: ReaderModeController = mockk(relaxed = true)
|
|
||||||
val quickActionSheetStore: QuickActionSheetStore = mockk(relaxed = true)
|
|
||||||
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
readerModeController,
|
|
||||||
quickActionSheetStore,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk()
|
|
||||||
)
|
|
||||||
|
|
||||||
every { context.metrics } returns metrics
|
|
||||||
every { context.components.core.sessionManager.selectedSession } returns session
|
|
||||||
every { session.readerMode } returns true
|
|
||||||
every { metrics.track(Event.QuickActionSheetReadTapped) } just Runs
|
|
||||||
|
|
||||||
interactor.onReadPressed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetReadTapped) }
|
|
||||||
verify { readerModeController.hideReaderView() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onAppearancePressed() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val readerModeController: ReaderModeController = mockk(relaxed = true)
|
|
||||||
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
readerModeController,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk()
|
|
||||||
)
|
|
||||||
|
|
||||||
interactor.onAppearancePressed()
|
|
||||||
|
|
||||||
verify { readerModeController.showControls() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onOpenAppLink() {
|
|
||||||
val context: Context = mockk()
|
|
||||||
val session: Session = mockk()
|
|
||||||
val appLinksUseCases: AppLinksUseCases = mockk()
|
|
||||||
|
|
||||||
val interactor = QuickActionInteractor(
|
|
||||||
context,
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
mockk(),
|
|
||||||
appLinksUseCases
|
|
||||||
)
|
|
||||||
|
|
||||||
every { context.components.core.sessionManager.selectedSession } returns session
|
|
||||||
every { session.url } returns "mozilla.org"
|
|
||||||
|
|
||||||
val getAppLinkRedirect: AppLinksUseCases.GetAppLinkRedirect = mockk()
|
|
||||||
val appLinkRedirect: AppLinkRedirect = mockk()
|
|
||||||
val openAppLink: AppLinksUseCases.OpenAppLinkRedirect = mockk(relaxed = true)
|
|
||||||
|
|
||||||
every { appLinksUseCases.appLinkRedirect } returns getAppLinkRedirect
|
|
||||||
every { getAppLinkRedirect.invoke("mozilla.org") } returns appLinkRedirect
|
|
||||||
every { appLinksUseCases.openAppLink } returns openAppLink
|
|
||||||
every { appLinkRedirect.appIntent } returns mockk(relaxed = true)
|
|
||||||
|
|
||||||
interactor.onOpenAppLinkPressed()
|
|
||||||
|
|
||||||
verify { openAppLink.invoke(appLinkRedirect) }
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue