|
|
|
/* 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.lifecycle.LifecycleCoroutineScope
|
|
|
|
import androidx.navigation.NavController
|
|
|
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
|
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
|
|
import kotlinx.coroutines.MainScope
|
|
|
|
import kotlinx.coroutines.ObsoleteCoroutinesApi
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import mozilla.components.browser.session.Session
|
|
|
|
import mozilla.components.concept.engine.EngineView
|
|
|
|
import org.mozilla.fenix.NavGraphDirections
|
|
|
|
import org.mozilla.fenix.R
|
|
|
|
import org.mozilla.fenix.browser.BrowserFragment
|
|
|
|
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
|
|
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
|
|
|
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
|
|
|
|
import org.mozilla.fenix.collections.CreateCollectionViewModel
|
|
|
|
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.utils.deleteAndQuit
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An interface that handles the view manipulation of the BrowserToolbar, triggered by the Interactor
|
|
|
|
*/
|
|
|
|
interface BrowserToolbarController {
|
|
|
|
fun handleToolbarPaste(text: String)
|
|
|
|
fun handleToolbarPasteAndGo(text: String)
|
|
|
|
fun handleToolbarItemInteraction(item: ToolbarMenu.Item)
|
|
|
|
fun handleToolbarClick()
|
|
|
|
}
|
|
|
|
|
|
|
|
class DefaultBrowserToolbarController(
|
|
|
|
private val context: Context,
|
|
|
|
private val navController: NavController,
|
|
|
|
private val browsingModeManager: BrowsingModeManager,
|
|
|
|
private val findInPageLauncher: () -> Unit,
|
|
|
|
private val engineView: EngineView,
|
|
|
|
private val customTabSession: Session?,
|
|
|
|
private val viewModel: CreateCollectionViewModel,
|
|
|
|
private val getSupportUrl: () -> String,
|
|
|
|
private val openInFenixIntent: Intent,
|
|
|
|
private val bottomSheetBehavior: QuickActionSheetBehavior<NestedScrollView>,
|
|
|
|
private val scope: LifecycleCoroutineScope
|
|
|
|
) : BrowserToolbarController {
|
|
|
|
|
|
|
|
override fun handleToolbarPaste(text: String) {
|
|
|
|
navController.nav(
|
|
|
|
R.id.browserFragment,
|
|
|
|
BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(
|
|
|
|
sessionId = customTabSession?.id ?: context.components.core.sessionManager.selectedSession?.id,
|
|
|
|
pastedText = text
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleToolbarPasteAndGo(text: String) {
|
|
|
|
context.components.core.sessionManager.selectedSession?.searchTerms = ""
|
|
|
|
context.components.useCases.sessionUseCases.loadUrl(text)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleToolbarClick() {
|
|
|
|
context.components.analytics.metrics.track(
|
|
|
|
Event.SearchBarTapped(Event.SearchBarTapped.Source.BROWSER)
|
|
|
|
)
|
|
|
|
navController.nav(
|
|
|
|
R.id.browserFragment,
|
|
|
|
BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(
|
|
|
|
customTabSession?.id ?: context.components.core.sessionManager.selectedSession?.id
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
@ExperimentalCoroutinesApi
|
|
|
|
@ObsoleteCoroutinesApi
|
|
|
|
@SuppressWarnings("ComplexMethod", "LongMethod")
|
|
|
|
override fun handleToolbarItemInteraction(item: ToolbarMenu.Item) {
|
|
|
|
val sessionUseCases = context.components.useCases.sessionUseCases
|
|
|
|
trackToolbarItemInteraction(item)
|
|
|
|
val currentSession = customTabSession ?: context.components.core.sessionManager.selectedSession
|
|
|
|
|
|
|
|
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.AddToHomeScreen -> {
|
|
|
|
MainScope().launch {
|
|
|
|
with(context.components.useCases.webAppUseCases) {
|
|
|
|
if (isInstallable()) {
|
|
|
|
addToHomescreen()
|
|
|
|
} else {
|
|
|
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateShortcutFragment()
|
|
|
|
navController.navigate(directions)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ToolbarMenu.Item.Share -> {
|
|
|
|
val currentUrl = currentSession?.url
|
|
|
|
currentUrl?.apply {
|
|
|
|
val directions = NavGraphDirections.actionGlobalShareFragment(this)
|
|
|
|
navController.navigate(directions)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ToolbarMenu.Item.NewTab -> {
|
|
|
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(
|
|
|
|
sessionId = null
|
|
|
|
)
|
|
|
|
navController.nav(R.id.browserFragment, directions)
|
|
|
|
browsingModeManager.mode = BrowsingMode.Normal
|
|
|
|
}
|
|
|
|
ToolbarMenu.Item.NewPrivateTab -> {
|
|
|
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(
|
|
|
|
sessionId = null
|
|
|
|
)
|
|
|
|
navController.nav(R.id.browserFragment, directions)
|
|
|
|
browsingModeManager.mode = BrowsingMode.Private
|
|
|
|
}
|
|
|
|
ToolbarMenu.Item.FindInPage -> {
|
|
|
|
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
|
|
|
findInPageLauncher()
|
|
|
|
context.components.analytics.metrics.track(Event.FindInPageOpened)
|
|
|
|
}
|
|
|
|
ToolbarMenu.Item.ReportIssue -> {
|
|
|
|
val currentUrl = currentSession?.url
|
|
|
|
currentUrl?.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(getSupportUrl())
|
|
|
|
}
|
|
|
|
ToolbarMenu.Item.SaveToCollection -> {
|
|
|
|
context.components.analytics.metrics
|
|
|
|
.track(Event.CollectionSaveButtonPressed(TELEMETRY_BROWSER_IDENTIFIER))
|
|
|
|
|
|
|
|
currentSession?.toTab(context)?.let { currentSessionAsTab ->
|
|
|
|
viewModel.saveTabToCollection(
|
|
|
|
tabs = listOf(currentSessionAsTab),
|
|
|
|
selectedTab = currentSessionAsTab,
|
|
|
|
cachedTabCollections = context.components.core.tabCollectionStorage.cachedTabCollections
|
|
|
|
)
|
|
|
|
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
|
|
|
|
customTabSession!!.customTabConfig = null
|
|
|
|
context.components.core.sessionManager.select(customTabSession)
|
|
|
|
|
|
|
|
// Switch to the actual browser which should now display our new selected session
|
|
|
|
context.startActivity(openInFenixIntent)
|
|
|
|
|
|
|
|
// Close this activity since it is no longer displaying any session
|
|
|
|
(context as Activity).finish()
|
|
|
|
}
|
|
|
|
ToolbarMenu.Item.Quit -> context.deleteAndQuit(scope)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@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
|
|
|
|
ToolbarMenu.Item.AddToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
|
|
|
|
ToolbarMenu.Item.Quit -> Event.BrowserMenuItemTapped.Item.QUIT
|
|
|
|
}
|
|
|
|
|
|
|
|
context.components.analytics.metrics.track(Event.BrowserMenuItemTapped(eventItem))
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
internal const val TELEMETRY_BROWSER_IDENTIFIER = "browserMenu"
|
|
|
|
}
|
|
|
|
}
|