|
|
|
/* 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.home.sessioncontrol
|
|
|
|
|
|
|
|
import android.annotation.SuppressLint
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.widget.EditText
|
|
|
|
import androidx.annotation.VisibleForTesting
|
|
|
|
import androidx.appcompat.app.AlertDialog
|
|
|
|
import androidx.navigation.NavController
|
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import mozilla.components.browser.state.search.SearchEngine
|
|
|
|
import mozilla.components.browser.state.selector.getNormalOrPrivateTabs
|
|
|
|
import mozilla.components.browser.state.state.availableSearchEngines
|
|
|
|
import mozilla.components.browser.state.state.searchEngines
|
|
|
|
import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine
|
|
|
|
import mozilla.components.browser.state.store.BrowserStore
|
|
|
|
import mozilla.components.concept.engine.Engine
|
|
|
|
import mozilla.components.concept.engine.prompt.ShareData
|
|
|
|
import mozilla.components.feature.session.SessionUseCases
|
|
|
|
import mozilla.components.feature.tab.collections.TabCollection
|
|
|
|
import mozilla.components.feature.tab.collections.ext.invoke
|
|
|
|
import mozilla.components.feature.tabs.TabsUseCases
|
|
|
|
import mozilla.components.feature.top.sites.TopSite
|
|
|
|
import mozilla.components.support.ktx.android.view.showKeyboard
|
|
|
|
import mozilla.components.support.ktx.kotlin.isUrl
|
|
|
|
import mozilla.telemetry.glean.private.NoExtras
|
|
|
|
import org.mozilla.fenix.BrowserDirection
|
|
|
|
import org.mozilla.fenix.FeatureFlags
|
|
|
|
import org.mozilla.fenix.GleanMetrics.Collections
|
|
|
|
import org.mozilla.fenix.GleanMetrics.Events
|
|
|
|
import org.mozilla.fenix.GleanMetrics.HomeScreen
|
|
|
|
import org.mozilla.fenix.GleanMetrics.Pings
|
|
|
|
import org.mozilla.fenix.GleanMetrics.Pocket
|
|
|
|
import org.mozilla.fenix.GleanMetrics.RecentBookmarks
|
|
|
|
import org.mozilla.fenix.GleanMetrics.RecentTabs
|
|
|
|
import org.mozilla.fenix.GleanMetrics.TopSites
|
|
|
|
import org.mozilla.fenix.HomeActivity
|
|
|
|
import org.mozilla.fenix.R
|
|
|
|
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
|
|
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
|
|
|
import org.mozilla.fenix.collections.SaveCollectionStep
|
|
|
|
import org.mozilla.fenix.components.AppStore
|
|
|
|
import org.mozilla.fenix.components.TabCollectionStorage
|
|
|
|
import org.mozilla.fenix.components.appstate.AppAction
|
|
|
|
import org.mozilla.fenix.components.appstate.AppState
|
|
|
|
import org.mozilla.fenix.components.metrics.MetricsUtils
|
|
|
|
import org.mozilla.fenix.ext.components
|
|
|
|
import org.mozilla.fenix.ext.nav
|
|
|
|
import org.mozilla.fenix.ext.settings
|
|
|
|
import org.mozilla.fenix.gleanplumb.Message
|
|
|
|
import org.mozilla.fenix.gleanplumb.MessageController
|
|
|
|
import org.mozilla.fenix.home.HomeFragment
|
|
|
|
import org.mozilla.fenix.home.HomeFragmentDirections
|
|
|
|
import org.mozilla.fenix.home.Mode
|
|
|
|
import org.mozilla.fenix.settings.SupportUtils
|
|
|
|
import org.mozilla.fenix.settings.SupportUtils.SumoTopic.PRIVATE_BROWSING_MYTHS
|
|
|
|
import org.mozilla.fenix.utils.Settings
|
|
|
|
import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [HomeFragment] controller. An interface that handles the view manipulation of the Tabs triggered
|
|
|
|
* by the Interactor.
|
|
|
|
*/
|
|
|
|
@Suppress("TooManyFunctions")
|
|
|
|
interface SessionControlController {
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onCollectionAddTabTapped]
|
|
|
|
*/
|
|
|
|
fun handleCollectionAddTabTapped(collection: TabCollection)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onCollectionOpenTabClicked]
|
|
|
|
*/
|
|
|
|
fun handleCollectionOpenTabClicked(tab: ComponentTab)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onCollectionOpenTabsTapped]
|
|
|
|
*/
|
|
|
|
fun handleCollectionOpenTabsTapped(collection: TabCollection)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onCollectionRemoveTab]
|
|
|
|
*/
|
|
|
|
fun handleCollectionRemoveTab(collection: TabCollection, tab: ComponentTab, wasSwiped: Boolean)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onCollectionShareTabsClicked]
|
|
|
|
*/
|
|
|
|
fun handleCollectionShareTabsClicked(collection: TabCollection)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onDeleteCollectionTapped]
|
|
|
|
*/
|
|
|
|
fun handleDeleteCollectionTapped(collection: TabCollection)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [TopSiteInteractor.onOpenInPrivateTabClicked]
|
|
|
|
*/
|
|
|
|
fun handleOpenInPrivateTabClicked(topSite: TopSite)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [TabSessionInteractor.onPrivateBrowsingLearnMoreClicked]
|
|
|
|
*/
|
|
|
|
fun handlePrivateBrowsingLearnMoreClicked()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [TopSiteInteractor.onRenameTopSiteClicked]
|
|
|
|
*/
|
|
|
|
fun handleRenameTopSiteClicked(topSite: TopSite)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [TopSiteInteractor.onRemoveTopSiteClicked]
|
|
|
|
*/
|
|
|
|
fun handleRemoveTopSiteClicked(topSite: TopSite)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onRenameCollectionTapped]
|
|
|
|
*/
|
|
|
|
fun handleRenameCollectionTapped(collection: TabCollection)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [TopSiteInteractor.onSelectTopSite]
|
|
|
|
*/
|
|
|
|
fun handleSelectTopSite(topSite: TopSite, position: Int)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [TopSiteInteractor.onSettingsClicked]
|
|
|
|
*/
|
|
|
|
fun handleTopSiteSettingsClicked()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [TopSiteInteractor.onSponsorPrivacyClicked]
|
|
|
|
*/
|
|
|
|
fun handleSponsorPrivacyClicked()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [OnboardingInteractor.onStartBrowsingClicked]
|
|
|
|
*/
|
|
|
|
fun handleStartBrowsingClicked()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [OnboardingInteractor.onReadPrivacyNoticeClicked]
|
|
|
|
*/
|
|
|
|
fun handleReadPrivacyNoticeClicked()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onToggleCollectionExpanded]
|
|
|
|
*/
|
|
|
|
fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [ToolbarInteractor.onPasteAndGo]
|
|
|
|
*/
|
|
|
|
fun handlePasteAndGo(clipboardText: String)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [ToolbarInteractor.onPaste]
|
|
|
|
*/
|
|
|
|
fun handlePaste(clipboardText: String)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onAddTabsToCollectionTapped]
|
|
|
|
*/
|
|
|
|
fun handleCreateCollection()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onRemoveCollectionsPlaceholder]
|
|
|
|
*/
|
|
|
|
fun handleRemoveCollectionsPlaceholder()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CollectionInteractor.onCollectionMenuOpened] and [TopSiteInteractor.onTopSiteMenuOpened]
|
|
|
|
*/
|
|
|
|
fun handleMenuOpened()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [MessageCardInteractor.onMessageClicked]
|
|
|
|
*/
|
|
|
|
fun handleMessageClicked(message: Message)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [MessageCardInteractor.onMessageClosedClicked]
|
|
|
|
*/
|
|
|
|
fun handleMessageClosed(message: Message)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [MessageCardInteractor.onMessageDisplayed]
|
|
|
|
*/
|
|
|
|
fun handleMessageDisplayed(message: Message)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [TabSessionInteractor.onPrivateModeButtonClicked]
|
|
|
|
*/
|
|
|
|
fun handlePrivateModeButtonClicked(newMode: BrowsingMode, userHasBeenOnboarded: Boolean)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [CustomizeHomeIteractor.openCustomizeHomePage]
|
|
|
|
*/
|
|
|
|
fun handleCustomizeHomeTapped()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [OnboardingInteractor.showOnboardingDialog]
|
|
|
|
*/
|
|
|
|
fun handleShowOnboardingDialog()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see [SessionControlInteractor.reportSessionMetrics]
|
|
|
|
*/
|
|
|
|
fun handleReportSessionMetrics(state: AppState)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Suppress("TooManyFunctions", "LargeClass", "LongParameterList")
|
|
|
|
class DefaultSessionControlController(
|
|
|
|
private val activity: HomeActivity,
|
|
|
|
private val settings: Settings,
|
|
|
|
private val engine: Engine,
|
|
|
|
private val messageController: MessageController,
|
|
|
|
private val store: BrowserStore,
|
|
|
|
private val tabCollectionStorage: TabCollectionStorage,
|
|
|
|
private val addTabUseCase: TabsUseCases.AddNewTabUseCase,
|
|
|
|
private val restoreUseCase: TabsUseCases.RestoreUseCase,
|
|
|
|
private val reloadUrlUseCase: SessionUseCases.ReloadUrlUseCase,
|
|
|
|
private val selectTabUseCase: TabsUseCases.SelectTabUseCase,
|
|
|
|
private val appStore: AppStore,
|
|
|
|
private val navController: NavController,
|
|
|
|
private val viewLifecycleScope: CoroutineScope,
|
|
|
|
private val hideOnboarding: () -> Unit,
|
|
|
|
private val registerCollectionStorageObserver: () -> Unit,
|
|
|
|
private val removeCollectionWithUndo: (tabCollection: TabCollection) -> Unit,
|
|
|
|
private val showTabTray: () -> Unit
|
|
|
|
) : SessionControlController {
|
|
|
|
|
|
|
|
override fun handleCollectionAddTabTapped(collection: TabCollection) {
|
|
|
|
Collections.addTabButton.record(NoExtras())
|
|
|
|
showCollectionCreationFragment(
|
|
|
|
step = SaveCollectionStep.SelectTabs,
|
|
|
|
selectedTabCollectionId = collection.id
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleMenuOpened() {
|
|
|
|
dismissSearchDialogIfDisplayed()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleCollectionOpenTabClicked(tab: ComponentTab) {
|
|
|
|
dismissSearchDialogIfDisplayed()
|
|
|
|
|
|
|
|
restoreUseCase.invoke(
|
|
|
|
activity,
|
|
|
|
engine,
|
|
|
|
tab,
|
|
|
|
onTabRestored = {
|
|
|
|
activity.openToBrowser(BrowserDirection.FromHome)
|
|
|
|
selectTabUseCase.invoke(it)
|
|
|
|
reloadUrlUseCase.invoke(it)
|
|
|
|
},
|
|
|
|
onFailure = {
|
|
|
|
activity.openToBrowserAndLoad(
|
|
|
|
searchTermOrURL = tab.url,
|
|
|
|
newTab = true,
|
|
|
|
from = BrowserDirection.FromHome
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
Collections.tabRestored.record(NoExtras())
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleCollectionOpenTabsTapped(collection: TabCollection) {
|
|
|
|
restoreUseCase.invoke(
|
|
|
|
activity,
|
|
|
|
engine,
|
|
|
|
collection,
|
|
|
|
onFailure = { url ->
|
|
|
|
addTabUseCase.invoke(url)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
showTabTray()
|
|
|
|
Collections.allTabsRestored.record(NoExtras())
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleCollectionRemoveTab(
|
|
|
|
collection: TabCollection,
|
|
|
|
tab: ComponentTab,
|
|
|
|
wasSwiped: Boolean
|
|
|
|
) {
|
|
|
|
Collections.tabRemoved.record(NoExtras())
|
|
|
|
|
|
|
|
if (collection.tabs.size == 1) {
|
|
|
|
removeCollectionWithUndo(collection)
|
|
|
|
} else {
|
|
|
|
viewLifecycleScope.launch {
|
|
|
|
tabCollectionStorage.removeTabFromCollection(collection, tab)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleCollectionShareTabsClicked(collection: TabCollection) {
|
|
|
|
dismissSearchDialogIfDisplayed()
|
|
|
|
showShareFragment(
|
|
|
|
collection.title,
|
|
|
|
collection.tabs.map { ShareData(url = it.url, title = it.title) }
|
|
|
|
)
|
|
|
|
Collections.shared.record(NoExtras())
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleDeleteCollectionTapped(collection: TabCollection) {
|
|
|
|
removeCollectionWithUndo(collection)
|
|
|
|
Collections.removed.record(NoExtras())
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleOpenInPrivateTabClicked(topSite: TopSite) {
|
|
|
|
if (topSite is TopSite.Provided) {
|
|
|
|
TopSites.openContileInPrivateTab.record(NoExtras())
|
|
|
|
} else {
|
|
|
|
TopSites.openInPrivateTab.record(NoExtras())
|
|
|
|
}
|
|
|
|
with(activity) {
|
|
|
|
browsingModeManager.mode = BrowsingMode.Private
|
|
|
|
openToBrowserAndLoad(
|
|
|
|
searchTermOrURL = topSite.url,
|
|
|
|
newTab = true,
|
|
|
|
from = BrowserDirection.FromHome
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handlePrivateBrowsingLearnMoreClicked() {
|
|
|
|
dismissSearchDialogIfDisplayed()
|
|
|
|
activity.openToBrowserAndLoad(
|
|
|
|
searchTermOrURL = SupportUtils.getGenericSumoURLForTopic(PRIVATE_BROWSING_MYTHS),
|
|
|
|
newTab = true,
|
|
|
|
from = BrowserDirection.FromHome
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressLint("InflateParams")
|
|
|
|
override fun handleRenameTopSiteClicked(topSite: TopSite) {
|
|
|
|
activity.let {
|
|
|
|
val customLayout =
|
|
|
|
LayoutInflater.from(it).inflate(R.layout.top_sites_rename_dialog, null)
|
|
|
|
val topSiteLabelEditText: EditText =
|
|
|
|
customLayout.findViewById(R.id.top_site_title)
|
|
|
|
topSiteLabelEditText.setText(topSite.title)
|
|
|
|
|
|
|
|
AlertDialog.Builder(it).apply {
|
|
|
|
setTitle(R.string.rename_top_site)
|
|
|
|
setView(customLayout)
|
|
|
|
setPositiveButton(R.string.top_sites_rename_dialog_ok) { dialog, _ ->
|
|
|
|
viewLifecycleScope.launch(Dispatchers.IO) {
|
|
|
|
with(activity.components.useCases.topSitesUseCase) {
|
|
|
|
updateTopSites(
|
|
|
|
topSite,
|
|
|
|
topSiteLabelEditText.text.toString(),
|
|
|
|
topSite.url
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dialog.dismiss()
|
|
|
|
}
|
|
|
|
setNegativeButton(R.string.top_sites_rename_dialog_cancel) { dialog, _ ->
|
|
|
|
dialog.cancel()
|
|
|
|
}
|
|
|
|
}.show().also {
|
|
|
|
topSiteLabelEditText.setSelection(0, topSiteLabelEditText.text.length)
|
|
|
|
topSiteLabelEditText.showKeyboard()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleRemoveTopSiteClicked(topSite: TopSite) {
|
|
|
|
TopSites.remove.record(NoExtras())
|
|
|
|
when (topSite.url) {
|
|
|
|
SupportUtils.POCKET_TRENDING_URL -> Pocket.pocketTopSiteRemoved.record(NoExtras())
|
|
|
|
SupportUtils.GOOGLE_URL -> TopSites.googleTopSiteRemoved.record(NoExtras())
|
|
|
|
SupportUtils.BAIDU_URL -> TopSites.baiduTopSiteRemoved.record(NoExtras())
|
|
|
|
}
|
|
|
|
|
|
|
|
viewLifecycleScope.launch(Dispatchers.IO) {
|
|
|
|
with(activity.components.useCases.topSitesUseCase) {
|
|
|
|
removeTopSites(topSite)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleRenameCollectionTapped(collection: TabCollection) {
|
|
|
|
showCollectionCreationFragment(
|
|
|
|
step = SaveCollectionStep.RenameCollection,
|
|
|
|
selectedTabCollectionId = collection.id
|
|
|
|
)
|
|
|
|
Collections.renameButton.record(NoExtras())
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleSelectTopSite(topSite: TopSite, position: Int) {
|
|
|
|
dismissSearchDialogIfDisplayed()
|
|
|
|
|
|
|
|
TopSites.openInNewTab.record(NoExtras())
|
|
|
|
|
|
|
|
when (topSite) {
|
|
|
|
is TopSite.Default -> TopSites.openDefault.record(NoExtras())
|
|
|
|
is TopSite.Frecent -> TopSites.openFrecency.record(NoExtras())
|
|
|
|
is TopSite.Pinned -> TopSites.openPinned.record(NoExtras())
|
|
|
|
is TopSite.Provided -> TopSites.openContileTopSite.record(NoExtras()).also {
|
|
|
|
submitTopSitesImpressionPing(topSite, position)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
when (topSite.url) {
|
|
|
|
SupportUtils.GOOGLE_URL -> TopSites.openGoogleSearchAttribution.record(NoExtras())
|
|
|
|
SupportUtils.BAIDU_URL -> TopSites.openBaiduSearchAttribution.record(NoExtras())
|
|
|
|
SupportUtils.POCKET_TRENDING_URL -> Pocket.pocketTopSiteClicked.record(NoExtras())
|
|
|
|
}
|
|
|
|
|
|
|
|
val availableEngines: List<SearchEngine> = getAvailableSearchEngines()
|
|
|
|
val searchAccessPoint = MetricsUtils.Source.TOPSITE
|
|
|
|
|
|
|
|
availableEngines.firstOrNull { engine ->
|
|
|
|
engine.resultUrls.firstOrNull { it.contains(topSite.url) } != null
|
|
|
|
}?.let { searchEngine ->
|
|
|
|
MetricsUtils.recordSearchMetrics(
|
|
|
|
searchEngine,
|
|
|
|
searchEngine == store.state.search.selectedOrDefaultSearchEngine,
|
|
|
|
searchAccessPoint
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
val tabId = addTabUseCase.invoke(
|
|
|
|
url = appendSearchAttributionToUrlIfNeeded(topSite.url),
|
|
|
|
selectTab = true,
|
|
|
|
startLoading = true
|
|
|
|
)
|
|
|
|
|
|
|
|
if (settings.openNextTabInDesktopMode) {
|
|
|
|
activity.handleRequestDesktopMode(tabId)
|
|
|
|
}
|
|
|
|
activity.openToBrowser(BrowserDirection.FromHome)
|
|
|
|
}
|
|
|
|
|
|
|
|
@VisibleForTesting
|
|
|
|
internal fun submitTopSitesImpressionPing(topSite: TopSite.Provided, position: Int) {
|
|
|
|
TopSites.contileClick.record(
|
|
|
|
TopSites.ContileClickExtra(
|
|
|
|
position = position + 1,
|
|
|
|
source = "newtab"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
topSite.id?.let { TopSites.contileTileId.set(it) }
|
|
|
|
topSite.title?.let { TopSites.contileAdvertiser.set(it.lowercase()) }
|
|
|
|
TopSites.contileReportingUrl.set(topSite.clickUrl)
|
|
|
|
Pings.topsitesImpression.submit()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleTopSiteSettingsClicked() {
|
|
|
|
TopSites.contileSettings.record(NoExtras())
|
|
|
|
navController.nav(
|
|
|
|
R.id.homeFragment,
|
|
|
|
HomeFragmentDirections.actionGlobalHomeSettingsFragment()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleSponsorPrivacyClicked() {
|
|
|
|
TopSites.contileSponsorsAndPrivacy.record(NoExtras())
|
|
|
|
activity.openToBrowserAndLoad(
|
|
|
|
searchTermOrURL = SupportUtils.getGenericSumoURLForTopic(SupportUtils.SumoTopic.SPONSOR_PRIVACY),
|
|
|
|
newTab = true,
|
|
|
|
from = BrowserDirection.FromHome
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
@VisibleForTesting
|
|
|
|
internal fun getAvailableSearchEngines() =
|
|
|
|
activity.components.core.store.state.search.searchEngines +
|
|
|
|
activity.components.core.store.state.search.availableSearchEngines
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Append a search attribution query to any provided search engine URL based on the
|
|
|
|
* user's current region.
|
|
|
|
*/
|
|
|
|
private fun appendSearchAttributionToUrlIfNeeded(url: String): String {
|
|
|
|
if (url == SupportUtils.GOOGLE_URL) {
|
|
|
|
store.state.search.region?.let { region ->
|
|
|
|
return when (region.current) {
|
|
|
|
"US" -> SupportUtils.GOOGLE_US_URL
|
|
|
|
else -> SupportUtils.GOOGLE_XX_URL
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return url
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun dismissSearchDialogIfDisplayed() {
|
|
|
|
if (navController.currentDestination?.id == R.id.searchDialogFragment) {
|
|
|
|
navController.navigateUp()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleStartBrowsingClicked() {
|
|
|
|
hideOnboarding()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleCustomizeHomeTapped() {
|
|
|
|
val directions = HomeFragmentDirections.actionGlobalHomeSettingsFragment()
|
|
|
|
navController.nav(navController.currentDestination?.id, directions)
|
|
|
|
HomeScreen.customizeHomeClicked.record(NoExtras())
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleShowOnboardingDialog() {
|
|
|
|
if (FeatureFlags.showHomeOnboarding) {
|
|
|
|
navController.nav(
|
|
|
|
R.id.homeFragment,
|
|
|
|
HomeFragmentDirections.actionGlobalHomeOnboardingDialog()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleReadPrivacyNoticeClicked() {
|
|
|
|
activity.openToBrowserAndLoad(
|
|
|
|
searchTermOrURL = SupportUtils.getMozillaPageUrl(SupportUtils.MozillaPage.PRIVATE_NOTICE),
|
|
|
|
newTab = true,
|
|
|
|
from = BrowserDirection.FromHome
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean) {
|
|
|
|
appStore.dispatch(AppAction.CollectionExpanded(collection, expand))
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun showTabTrayCollectionCreation() {
|
|
|
|
val directions = HomeFragmentDirections.actionGlobalTabsTrayFragment(
|
|
|
|
enterMultiselect = true
|
|
|
|
)
|
|
|
|
navController.nav(R.id.homeFragment, directions)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun showCollectionCreationFragment(
|
|
|
|
step: SaveCollectionStep,
|
|
|
|
selectedTabIds: Array<String>? = null,
|
|
|
|
selectedTabCollectionId: Long? = null
|
|
|
|
) {
|
|
|
|
if (navController.currentDestination?.id == R.id.collectionCreationFragment) return
|
|
|
|
|
|
|
|
// Only register the observer right before moving to collection creation
|
|
|
|
registerCollectionStorageObserver()
|
|
|
|
|
|
|
|
val tabIds = store.state
|
|
|
|
.getNormalOrPrivateTabs(private = activity.browsingModeManager.mode.isPrivate)
|
|
|
|
.map { session -> session.id }
|
|
|
|
.toList()
|
|
|
|
.toTypedArray()
|
|
|
|
val directions = HomeFragmentDirections.actionGlobalCollectionCreationFragment(
|
|
|
|
tabIds = tabIds,
|
|
|
|
saveCollectionStep = step,
|
|
|
|
selectedTabIds = selectedTabIds,
|
|
|
|
selectedTabCollectionId = selectedTabCollectionId ?: -1
|
|
|
|
)
|
|
|
|
navController.nav(R.id.homeFragment, directions)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleCreateCollection() {
|
|
|
|
showTabTrayCollectionCreation()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleRemoveCollectionsPlaceholder() {
|
|
|
|
settings.showCollectionsPlaceholderOnHome = false
|
|
|
|
appStore.dispatch(AppAction.RemoveCollectionsPlaceholder)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun showShareFragment(shareSubject: String, data: List<ShareData>) {
|
|
|
|
val directions = HomeFragmentDirections.actionGlobalShareFragment(
|
|
|
|
shareSubject = shareSubject,
|
|
|
|
data = data.toTypedArray()
|
|
|
|
)
|
|
|
|
navController.nav(R.id.homeFragment, directions)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handlePasteAndGo(clipboardText: String) {
|
|
|
|
val searchEngine = store.state.search.selectedOrDefaultSearchEngine
|
|
|
|
|
|
|
|
activity.openToBrowserAndLoad(
|
|
|
|
searchTermOrURL = clipboardText,
|
|
|
|
newTab = true,
|
|
|
|
from = BrowserDirection.FromHome,
|
|
|
|
engine = searchEngine
|
|
|
|
)
|
|
|
|
|
|
|
|
if (clipboardText.isUrl() || searchEngine == null) {
|
|
|
|
Events.enteredUrl.record(Events.EnteredUrlExtra(autocomplete = false))
|
|
|
|
} else {
|
|
|
|
val searchAccessPoint = MetricsUtils.Source.ACTION
|
|
|
|
MetricsUtils.recordSearchMetrics(
|
|
|
|
searchEngine,
|
|
|
|
searchEngine == store.state.search.selectedOrDefaultSearchEngine,
|
|
|
|
searchAccessPoint
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handlePaste(clipboardText: String) {
|
|
|
|
val directions = HomeFragmentDirections.actionGlobalSearchDialog(
|
|
|
|
sessionId = null,
|
|
|
|
pastedText = clipboardText
|
|
|
|
)
|
|
|
|
navController.nav(R.id.homeFragment, directions)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleMessageClicked(message: Message) {
|
|
|
|
messageController.onMessagePressed(message)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleMessageClosed(message: Message) {
|
|
|
|
messageController.onMessageDismissed(message)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleMessageDisplayed(message: Message) {
|
|
|
|
messageController.onMessageDisplayed(message)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handlePrivateModeButtonClicked(
|
|
|
|
newMode: BrowsingMode,
|
|
|
|
userHasBeenOnboarded: Boolean
|
|
|
|
) {
|
|
|
|
if (newMode == BrowsingMode.Private) {
|
|
|
|
activity.settings().incrementNumTimesPrivateModeOpened()
|
|
|
|
}
|
|
|
|
|
|
|
|
if (userHasBeenOnboarded) {
|
|
|
|
appStore.dispatch(
|
|
|
|
AppAction.ModeChange(Mode.fromBrowsingMode(newMode))
|
|
|
|
)
|
|
|
|
|
|
|
|
if (navController.currentDestination?.id == R.id.searchDialogFragment) {
|
|
|
|
navController.navigate(
|
|
|
|
BrowserFragmentDirections.actionGlobalSearchDialog(
|
|
|
|
sessionId = null
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleReportSessionMetrics(state: AppState) {
|
|
|
|
if (state.recentTabs.isEmpty()) {
|
|
|
|
RecentTabs.sectionVisible.set(false)
|
|
|
|
} else {
|
|
|
|
RecentTabs.sectionVisible.set(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
RecentBookmarks.recentBookmarksCount.set(state.recentBookmarks.size.toLong())
|
|
|
|
}
|
|
|
|
}
|