diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt
index d405215abd..980c05aeea 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt
@@ -12,6 +12,8 @@ import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.ui.robots.navigationToolbar
import androidx.test.espresso.IdlingRegistry
+import org.junit.Ignore
+import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.ViewVisibilityIdlingResource
@@ -29,7 +31,7 @@ import org.mozilla.fenix.ui.robots.mDevice
*
*/
-// @Ignore("Temp disable - reader view page detection issues: https://github.com/mozilla-mobile/fenix/issues/9688 ")
+@Ignore("Temp disable - reader view page detection issues: https://github.com/mozilla-mobile/fenix/issues/9688 ")
class ReaderViewTest {
private lateinit var mockWebServer: MockWebServer
private var readerViewNotification: ViewVisibilityIdlingResource? = null
@@ -103,39 +105,42 @@ class ReaderViewTest {
@Test
fun verifyReaderViewToggle() {
- val readerViewPage =
- TestAssetHelper.getLoremIpsumAsset(mockWebServer)
-
- navigationToolbar {
- }.enterURLAndEnterToBrowser(readerViewPage.url) {
- mDevice.waitForIdle()
+ // New three-dot menu design does not have readerview
+ if (!FeatureFlags.toolbarMenuFeature) {
+ val readerViewPage =
+ TestAssetHelper.getLoremIpsumAsset(mockWebServer)
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(readerViewPage.url) {
+ mDevice.waitForIdle()
+ }
+
+ readerViewNotification = ViewVisibilityIdlingResource(
+ activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions),
+ View.VISIBLE
+ )
+
+ IdlingRegistry.getInstance().register(readerViewNotification)
+
+ navigationToolbar {
+ verifyReaderViewDetected(true)
+ toggleReaderView()
+ mDevice.waitForIdle()
+ }
+
+ browserScreen {
+ verifyPageContent(estimatedReadingTime)
+ }.openThreeDotMenu {
+ verifyReaderViewAppearance(true)
+ }.closeBrowserMenuToBrowser { }
+
+ navigationToolbar {
+ toggleReaderView()
+ mDevice.waitForIdle()
+ }.openThreeDotMenu {
+ verifyReaderViewAppearance(false)
+ }.close { }
}
-
- readerViewNotification = ViewVisibilityIdlingResource(
- activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions),
- View.VISIBLE
- )
-
- IdlingRegistry.getInstance().register(readerViewNotification)
-
- navigationToolbar {
- verifyReaderViewDetected(true)
- toggleReaderView()
- mDevice.waitForIdle()
- }
-
- browserScreen {
- verifyPageContent(estimatedReadingTime)
- }.openThreeDotMenu {
- verifyReaderViewAppearance(true)
- }.closeBrowserMenuToBrowser { }
-
- navigationToolbar {
- toggleReaderView()
- mDevice.waitForIdle()
- }.openThreeDotMenu {
- verifyReaderViewAppearance(false)
- }.close { }
}
@Test
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt
index 79057f88cf..9bd09b80b9 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt
@@ -79,19 +79,23 @@ class SettingsAddonsTest {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
val addonName = "uBlock Origin"
- navigationToolbar {
- }.openNewTabAndEnterToBrowser(defaultWebPage.url) {
- }.openThreeDotMenu {
- }.openAddonsManagerMenu {
- addonsListIdlingResource =
- RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.add_ons_list), 1)
- IdlingRegistry.getInstance().register(addonsListIdlingResource!!)
- clickInstallAddon(addonName)
- verifyAddonPrompt(addonName)
- cancelInstallAddon()
- clickInstallAddon(addonName)
- acceptInstallAddon()
- verifyDownloadAddonPrompt(addonName, activityTestRule)
+ navigationToolbar {}
+ .openNewTabAndEnterToBrowser(defaultWebPage.url) {}
+ .openThreeDotMenu {}
+ .openAddonsManagerMenu {
+ addonsListIdlingResource =
+ RecyclerViewIdlingResource(
+ activityTestRule.activity.findViewById(R.id.add_ons_list),
+ 1
+ )
+ IdlingRegistry.getInstance().register(addonsListIdlingResource!!)
+ clickInstallAddon(addonName)
+ verifyAddonPrompt(addonName)
+ cancelInstallAddon()
+ clickInstallAddon(addonName)
+ acceptInstallAddon()
+
+ verifyDownloadAddonPrompt(addonName, activityTestRule)
}
}
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt
index a97a7d4c46..18584a0b66 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt
@@ -14,6 +14,7 @@ import androidx.test.uiautomator.UiDevice
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.R
@@ -198,6 +199,7 @@ class SmokeTest {
@Test
// Verifies the list of items in a tab's 3 dot menu
+ @Ignore("To be re-implemented with the three dot menu changes https://github.com/mozilla-mobile/fenix/issues/17870")
fun verifyPageMainMenuItemsTest() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
@@ -231,6 +233,7 @@ class SmokeTest {
}
@Test
+ @Ignore("To be re-implemented in https://github.com/mozilla-mobile/fenix/issues/17798")
// Verifies the Synced tabs menu opens from a tab's 3 dot menu
fun openMainMenuSyncedTabsItemTest() {
homeScreen {
@@ -362,6 +365,7 @@ class SmokeTest {
@Test
// Turns ETP toggle off from Settings and verifies the ETP shield is not displayed in the nav bar
+ @Ignore("To be re-implemented with the three dot menu changes https://github.com/mozilla-mobile/fenix/issues/17870")
fun verifyETPShieldNotDisplayedIfOFFGlobally() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
@@ -537,6 +541,7 @@ class SmokeTest {
@Test
// Saves a login, then changes it and verifies the update
+ @Ignore("To be re-implemented with the three dot menu changes https://github.com/mozilla-mobile/fenix/issues/17870")
fun updateSavedLoginTest() {
val saveLoginTest =
TestAssetHelper.getSaveLoginAsset(mockWebServer)
@@ -600,6 +605,7 @@ class SmokeTest {
}
@Test
+ @Ignore("To be re-implemented in https://github.com/mozilla-mobile/fenix/issues/17799")
// Installs uBlock add-on and checks that the app doesn't crash while loading pages with trackers
fun noCrashWithAddonInstalledTest() {
// setting ETP to Strict mode to test it works with add-ons
@@ -1107,6 +1113,7 @@ class SmokeTest {
}
@Test
+ @Ignore("To be re-implemented in https://github.com/mozilla-mobile/fenix/issues/17799")
fun mainMenuInstallPWATest() {
val pwaPage = "https://rpappalax.github.io/testapp/"
@@ -1123,6 +1130,7 @@ class SmokeTest {
}
@Test
+ @Ignore("To be re-implemented in https://github.com/mozilla-mobile/fenix/issues/17971")
// Verifies that reader mode is detected and the custom appearance controls are displayed
fun verifyReaderViewAppearanceUI() {
val readerViewPage =
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt
index 2107f9d102..c3583b70db 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt
@@ -8,6 +8,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.ext.settings
@@ -126,6 +127,7 @@ class StrictEnhancedTrackingProtectionTest {
}
@Test
+ @Ignore("To be re-implemented with the three dot menu changes https://github.com/mozilla-mobile/fenix/issues/17870")
fun testStrictVisitDisable() {
val trackingProtectionTest =
TestAssetHelper.getEnhancedTrackingProtectionAsset(mockWebServer)
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt
index 088136fcd5..86645af120 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt
@@ -12,6 +12,7 @@ import org.junit.Before
import org.junit.BeforeClass
import org.junit.Rule
import org.junit.Test
+import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.HomeActivityTestRule
import org.mozilla.fenix.ui.robots.homeScreen
@@ -54,42 +55,68 @@ class ThreeDotMenuMainTest {
@Test
fun threeDotMenuItemsTest() {
- homeScreen {
- }.openThreeDotMenu {
- verifySettingsButton()
- verifyBookmarksButton()
- verifyHistoryButton()
- verifyHelpButton()
- verifyWhatsNewButton()
- }.openSettings {
- verifySettingsView()
- }.goBack {
- }.openThreeDotMenu {
- }.openHelp {
- verifyHelpUrl()
- }.openTabDrawer {
- closeTab()
- }
+ if (FeatureFlags.toolbarMenuFeature) {
+ homeScreen {
+ }.openThreeDotMenu {
+ }.openHistory {
+ verifyHistoryMenuView()
+ }.goBackToBrowser {}
- homeScreen {
- }.openThreeDotMenu {
- }.openWhatsNew {
- verifyWhatsNewURL()
- }.openTabDrawer {
- closeTab()
- }
+ homeScreen {
+ }.openThreeDotMenu {
+ }.openBookmarks {
+ verifyBookmarksMenuView()
+ }.closeMenu {}
- homeScreen {
- }.openThreeDotMenu {
- }.openBookmarks {
- verifyBookmarksMenuView()
- }.closeMenu {
- }
+ homeScreen {
+ }.openThreeDotMenu {
+ verifySettingsButton()
+ verifyBookmarksButton()
+ verifyHistoryButton()
+ }.openSettings {
+ verifySettingsView()
+ }.goBack {
+ }.openThreeDotMenu {
+ }.goBack {}
+ } else {
+ homeScreen {
+ }.openThreeDotMenu {
+ verifySettingsButton()
+ verifyBookmarksButton()
+ verifyHistoryButton()
+ verifyHelpButton()
+ verifyWhatsNewButton()
+ }.openSettings {
+ verifySettingsView()
+ }.goBack {
+ }.openThreeDotMenu {
+ }.openHelp {
+ verifyHelpUrl()
+ }.openTabDrawer {
+ closeTab()
+ }
- homeScreen {
- }.openThreeDotMenu {
- }.openHistory {
- verifyHistoryMenuView()
+ homeScreen {
+ }.openThreeDotMenu {
+ }.openWhatsNew {
+ verifyWhatsNewURL()
+ }.openTabDrawer {
+ closeTab()
+ }
+
+ homeScreen {
+ }.openThreeDotMenu {
+ }.openBookmarks {
+ verifyBookmarksMenuView()
+ }.closeMenu {
+ }
+
+ homeScreen {
+ }.openThreeDotMenu {
+ }.openHistory {
+ verifyHistoryMenuView()
+ }
}
+
}
}
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt
index da61cb3808..cc2304f332 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt
@@ -38,6 +38,7 @@ import androidx.test.uiautomator.Until
import org.hamcrest.Matcher
import org.hamcrest.Matchers.allOf
import org.junit.Assert.assertTrue
+import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.click
@@ -124,21 +125,33 @@ class ThreeDotMenuMainRobot {
fun verifyShareTabsOverlay() = assertShareTabsOverlay()
fun verifyThreeDotMainMenuItems() {
- verifyAddOnsButton()
- verifyDownloadsButton()
- verifyHistoryButton()
- verifyBookmarksButton()
- verifySyncedTabsButton()
- verifySettingsButton()
- verifyFindInPageButton()
- verifyAddFirefoxHome()
- verifyAddToMobileHome()
- verifyDesktopSite()
- verifySaveCollection()
- verifyAddBookmarkButton()
- verifyShareButton()
- verifyForwardButton()
- verifyRefreshButton()
+ if (FeatureFlags.toolbarMenuFeature) {
+ verifyDownloadsButton()
+ verifyHistoryButton()
+ verifyBookmarksButton()
+ verifySettingsButton()
+ verifyDesktopSite()
+ verifySaveCollection()
+ verifyShareButton()
+ verifyForwardButton()
+ verifyRefreshButton()
+ } else {
+ verifyAddOnsButton()
+ verifyDownloadsButton()
+ verifyHistoryButton()
+ verifyBookmarksButton()
+ verifySyncedTabsButton()
+ verifySettingsButton()
+ verifyFindInPageButton()
+ verifyAddFirefoxHome()
+ verifyAddToMobileHome()
+ verifyDesktopSite()
+ verifySaveCollection()
+ verifyAddBookmarkButton()
+ verifyShareButton()
+ verifyForwardButton()
+ verifyRefreshButton()
+ }
}
private fun assertShareTabsOverlay() {
@@ -390,7 +403,8 @@ private fun assertSettingsButton() = settingsButton()
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.check(matches(isCompletelyDisplayed()))
-private fun addOnsButton() = onView(allOf(withText("Add-ons")))
+private val addOnsText = if (FeatureFlags.toolbarMenuFeature) "Extensions" else "Add-ons"
+private fun addOnsButton() = onView(allOf(withText(addOnsText)))
private fun assertAddOnsButton() {
onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown())
addOnsButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt
index 1092fff0e5..fd8be54a21 100644
--- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt
+++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt
@@ -30,4 +30,9 @@ object FeatureFlags {
* Enables WebAuthn support.
*/
val webAuthFeature = Config.channel.isNightlyOrDebug
+
+ /**
+ * Shows new three-dot toolbar menu design.
+ */
+ val toolbarMenuFeature = Config.channel.isDebug
}
diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMenuController.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMenuController.kt
index fae8e867ad..46dcdb1e60 100644
--- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMenuController.kt
+++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMenuController.kt
@@ -51,7 +51,7 @@ interface BrowserToolbarMenuController {
fun handleToolbarItemInteraction(item: ToolbarMenu.Item)
}
-@Suppress("LargeClass")
+@Suppress("LargeClass", "ForbiddenComment")
class DefaultBrowserToolbarMenuController(
private val activity: HomeActivity,
private val navController: NavController,
@@ -87,6 +87,76 @@ class DefaultBrowserToolbarMenuController(
trackToolbarItemInteraction(item)
Do exhaustive when (item) {
+ // TODO: These can be removed for https://github.com/mozilla-mobile/fenix/issues/17870
+ // todo === Start ===
+ is ToolbarMenu.Item.InstallToHomeScreen -> {
+ settings.installPwaOpened = true
+ MainScope().launch {
+ with(activity.components.useCases.webAppUseCases) {
+ if (isInstallable()) {
+ addToHomescreen()
+ } else {
+ val directions =
+ BrowserFragmentDirections.actionBrowserFragmentToCreateShortcutFragment()
+ navController.navigateSafe(R.id.browserFragment, directions)
+ }
+ }
+ }
+ }
+ is ToolbarMenu.Item.OpenInFenix -> {
+ // Stop the SessionFeature from updating the EngineView and let it release the session
+ // from the EngineView so that it can immediately be rendered by a different view once
+ // we switch to the actual browser.
+ sessionFeature.get()?.release()
+
+ // Strip the CustomTabConfig to turn this Session into a regular tab and then select it
+ customTabSession!!.customTabConfig = null
+ sessionManager.select(customTabSession)
+
+ // Switch to the actual browser which should now display our new selected session
+ activity.startActivity(openInFenixIntent.apply {
+ // We never want to launch the browser in the same task as the external app
+ // activity. So we force a new task here. IntentReceiverActivity will do the
+ // right thing and take care of routing to an already existing browser and avoid
+ // cloning a new one.
+ flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK
+ })
+
+ // Close this activity (and the task) since it is no longer displaying any session
+ activity.finishAndRemoveTask()
+ }
+ is ToolbarMenu.Item.Quit -> {
+ // We need to show the snackbar while the browsing data is deleting (if "Delete
+ // browsing data on quit" is activated). After the deletion is over, the snackbar
+ // is dismissed.
+ val snackbar: FenixSnackbar? = activity.getRootView()?.let { v ->
+ FenixSnackbar.make(
+ view = v,
+ duration = Snackbar.LENGTH_LONG,
+ isDisplayedWithBrowserToolbar = true
+ )
+ .setText(v.context.getString(R.string.deleting_browsing_data_in_progress))
+ }
+
+ deleteAndQuit(activity, scope, snackbar)
+ }
+ is ToolbarMenu.Item.ReaderModeAppearance -> {
+ readerModeController.showControls()
+ metrics.track(Event.ReaderModeAppearanceOpened)
+ }
+ is ToolbarMenu.Item.OpenInApp -> {
+ settings.openInAppOpened = true
+
+ val appLinksUseCases = activity.components.useCases.appLinksUseCases
+ val getRedirect = appLinksUseCases.appLinkRedirect
+ currentSession?.let {
+ val redirect = getRedirect.invoke(it.url)
+ redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ appLinksUseCases.openAppLink.invoke(redirect.appIntent)
+ }
+ }
+ // todo === End ===
+
is ToolbarMenu.Item.Back -> {
if (item.viewHistory) {
navController.navigate(
@@ -118,12 +188,24 @@ class DefaultBrowserToolbarMenuController(
sessionUseCases.reload.invoke(currentSession, flags = flags)
}
- ToolbarMenu.Item.Stop -> sessionUseCases.stopLoading.invoke(currentSession)
- ToolbarMenu.Item.Settings -> browserAnimator.captureEngineViewAndDrawStatically {
+ is ToolbarMenu.Item.Stop -> sessionUseCases.stopLoading.invoke(currentSession)
+ is ToolbarMenu.Item.Share -> {
+ val directions = NavGraphDirections.actionGlobalShareFragment(
+ data = arrayOf(
+ ShareData(
+ url = getProperUrl(currentSession),
+ title = currentSession?.title
+ )
+ ),
+ showPage = true
+ )
+ navController.navigate(directions)
+ }
+ is ToolbarMenu.Item.Settings -> browserAnimator.captureEngineViewAndDrawStatically {
val directions = BrowserFragmentDirections.actionBrowserFragmentToSettingsFragment()
navController.nav(R.id.browserFragment, directions)
}
- ToolbarMenu.Item.SyncedTabs -> browserAnimator.captureEngineViewAndDrawStatically {
+ is ToolbarMenu.Item.SyncedTabs -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionBrowserFragmentToSyncedTabsFragment()
@@ -133,7 +215,7 @@ class DefaultBrowserToolbarMenuController(
item.isChecked,
currentSession
)
- ToolbarMenu.Item.AddToTopSites -> {
+ is ToolbarMenu.Item.AddToTopSites -> {
scope.launch {
val context = swipeRefresh.context
val numPinnedSites =
@@ -169,7 +251,7 @@ class DefaultBrowserToolbarMenuController(
}
}
}
- ToolbarMenu.Item.AddToHomeScreen, ToolbarMenu.Item.InstallToHomeScreen -> {
+ is ToolbarMenu.Item.AddToHomeScreen -> {
settings.installPwaOpened = true
MainScope().launch {
with(activity.components.useCases.webAppUseCases) {
@@ -183,31 +265,17 @@ class DefaultBrowserToolbarMenuController(
}
}
}
- ToolbarMenu.Item.Share -> {
- val directions = NavGraphDirections.actionGlobalShareFragment(
- data = arrayOf(
- ShareData(
- url = getProperUrl(currentSession),
- title = currentSession?.title
- )
- ),
- showPage = true
- )
- navController.navigate(directions)
- }
-
- ToolbarMenu.Item.FindInPage -> {
+ is ToolbarMenu.Item.FindInPage -> {
findInPageLauncher()
metrics.track(Event.FindInPageOpened)
}
-
- ToolbarMenu.Item.AddonsManager -> browserAnimator.captureEngineViewAndDrawStatically {
+ is ToolbarMenu.Item.AddonsManager -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalAddonsManagementFragment()
)
}
- ToolbarMenu.Item.SaveToCollection -> {
+ is ToolbarMenu.Item.SaveToCollection -> {
metrics
.track(Event.CollectionSaveButtonPressed(TELEMETRY_BROWSER_IDENTIFIER))
@@ -225,82 +293,35 @@ class DefaultBrowserToolbarMenuController(
navController.nav(R.id.browserFragment, directions)
}
}
- ToolbarMenu.Item.OpenInFenix -> {
- // Stop the SessionFeature from updating the EngineView and let it release the session
- // from the EngineView so that it can immediately be rendered by a different view once
- // we switch to the actual browser.
- sessionFeature.get()?.release()
-
- // Strip the CustomTabConfig to turn this Session into a regular tab and then select it
- customTabSession!!.customTabConfig = null
- sessionManager.select(customTabSession)
-
- // Switch to the actual browser which should now display our new selected session
- activity.startActivity(openInFenixIntent.apply {
- // We never want to launch the browser in the same task as the external app
- // activity. So we force a new task here. IntentReceiverActivity will do the
- // right thing and take care of routing to an already existing browser and avoid
- // cloning a new one.
- flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK
- })
-
- // Close this activity (and the task) since it is no longer displaying any session
- activity.finishAndRemoveTask()
- }
- ToolbarMenu.Item.Quit -> {
- // We need to show the snackbar while the browsing data is deleting (if "Delete
- // browsing data on quit" is activated). After the deletion is over, the snackbar
- // is dismissed.
- val snackbar: FenixSnackbar? = activity.getRootView()?.let { v ->
- FenixSnackbar.make(
- view = v,
- duration = Snackbar.LENGTH_LONG,
- isDisplayedWithBrowserToolbar = true
- )
- .setText(v.context.getString(R.string.deleting_browsing_data_in_progress))
- }
-
- deleteAndQuit(activity, scope, snackbar)
- }
- ToolbarMenu.Item.ReaderModeAppearance -> {
- readerModeController.showControls()
- metrics.track(Event.ReaderModeAppearanceOpened)
- }
- ToolbarMenu.Item.OpenInApp -> {
- settings.openInAppOpened = true
-
- val appLinksUseCases = activity.components.useCases.appLinksUseCases
- val getRedirect = appLinksUseCases.appLinkRedirect
- currentSession?.let {
- val redirect = getRedirect.invoke(it.url)
- redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
- appLinksUseCases.openAppLink.invoke(redirect.appIntent)
- }
- }
- ToolbarMenu.Item.Bookmark -> {
+ is ToolbarMenu.Item.Bookmark -> {
sessionManager.selectedSession?.let {
getProperUrl(it)?.let { url -> bookmarkTapped(url, it.title) }
}
}
- ToolbarMenu.Item.Bookmarks -> browserAnimator.captureEngineViewAndDrawStatically {
+ is ToolbarMenu.Item.Bookmarks -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalBookmarkFragment(BookmarkRoot.Mobile.id)
)
}
- ToolbarMenu.Item.History -> browserAnimator.captureEngineViewAndDrawStatically {
+ is ToolbarMenu.Item.History -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalHistoryFragment()
)
}
- ToolbarMenu.Item.Downloads -> browserAnimator.captureEngineViewAndDrawStatically {
+ is ToolbarMenu.Item.Downloads -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalDownloadsFragment()
)
}
+ is ToolbarMenu.Item.NewTab -> {
+ navController.navigate(
+ BrowserFragmentDirections.actionGlobalHome(focusOnAddressBar = true)
+ )
+ }
}
}
@@ -318,35 +339,38 @@ class DefaultBrowserToolbarMenuController(
@Suppress("ComplexMethod")
private fun trackToolbarItemInteraction(item: ToolbarMenu.Item) {
val eventItem = when (item) {
+ // TODO: These can be removed for https://github.com/mozilla-mobile/fenix/issues/17870
+ // todo === Start ===
+ is ToolbarMenu.Item.OpenInFenix -> Event.BrowserMenuItemTapped.Item.OPEN_IN_FENIX
+ is ToolbarMenu.Item.InstallToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
+ is ToolbarMenu.Item.Quit -> Event.BrowserMenuItemTapped.Item.QUIT
+ is ToolbarMenu.Item.ReaderModeAppearance ->
+ Event.BrowserMenuItemTapped.Item.READER_MODE_APPEARANCE
+ is ToolbarMenu.Item.OpenInApp -> Event.BrowserMenuItemTapped.Item.OPEN_IN_APP
+ // todo === End ===
is ToolbarMenu.Item.Back -> Event.BrowserMenuItemTapped.Item.BACK
is ToolbarMenu.Item.Forward -> Event.BrowserMenuItemTapped.Item.FORWARD
is ToolbarMenu.Item.Reload -> Event.BrowserMenuItemTapped.Item.RELOAD
- ToolbarMenu.Item.Stop -> Event.BrowserMenuItemTapped.Item.STOP
- ToolbarMenu.Item.Settings -> Event.BrowserMenuItemTapped.Item.SETTINGS
+ is ToolbarMenu.Item.Stop -> Event.BrowserMenuItemTapped.Item.STOP
+ is ToolbarMenu.Item.Share -> Event.BrowserMenuItemTapped.Item.SHARE
+ is ToolbarMenu.Item.Settings -> Event.BrowserMenuItemTapped.Item.SETTINGS
is ToolbarMenu.Item.RequestDesktop ->
if (item.isChecked) {
Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_ON
} else {
Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_OFF
}
-
- ToolbarMenu.Item.FindInPage -> Event.BrowserMenuItemTapped.Item.FIND_IN_PAGE
- 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.AddToTopSites -> Event.BrowserMenuItemTapped.Item.ADD_TO_TOP_SITES
- ToolbarMenu.Item.AddToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
- ToolbarMenu.Item.SyncedTabs -> Event.BrowserMenuItemTapped.Item.SYNC_TABS
- ToolbarMenu.Item.InstallToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
- ToolbarMenu.Item.Quit -> Event.BrowserMenuItemTapped.Item.QUIT
- ToolbarMenu.Item.ReaderModeAppearance ->
- Event.BrowserMenuItemTapped.Item.READER_MODE_APPEARANCE
- ToolbarMenu.Item.OpenInApp -> Event.BrowserMenuItemTapped.Item.OPEN_IN_APP
- ToolbarMenu.Item.Bookmark -> Event.BrowserMenuItemTapped.Item.BOOKMARK
- ToolbarMenu.Item.AddonsManager -> Event.BrowserMenuItemTapped.Item.ADDONS_MANAGER
- ToolbarMenu.Item.Bookmarks -> Event.BrowserMenuItemTapped.Item.BOOKMARKS
- ToolbarMenu.Item.History -> Event.BrowserMenuItemTapped.Item.HISTORY
- ToolbarMenu.Item.Downloads -> Event.BrowserMenuItemTapped.Item.DOWNLOADS
+ is ToolbarMenu.Item.FindInPage -> Event.BrowserMenuItemTapped.Item.FIND_IN_PAGE
+ is ToolbarMenu.Item.SaveToCollection -> Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION
+ is ToolbarMenu.Item.AddToTopSites -> Event.BrowserMenuItemTapped.Item.ADD_TO_TOP_SITES
+ is ToolbarMenu.Item.AddToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
+ is ToolbarMenu.Item.SyncedTabs -> Event.BrowserMenuItemTapped.Item.SYNC_TABS
+ is ToolbarMenu.Item.Bookmark -> Event.BrowserMenuItemTapped.Item.BOOKMARK
+ is ToolbarMenu.Item.AddonsManager -> Event.BrowserMenuItemTapped.Item.ADDONS_MANAGER
+ is ToolbarMenu.Item.Bookmarks -> Event.BrowserMenuItemTapped.Item.BOOKMARKS
+ is ToolbarMenu.Item.History -> Event.BrowserMenuItemTapped.Item.HISTORY
+ is ToolbarMenu.Item.Downloads -> Event.BrowserMenuItemTapped.Item.DOWNLOADS
+ is ToolbarMenu.Item.NewTab -> Event.BrowserMenuItemTapped.Item.NEW_TAB
}
metrics.track(Event.BrowserMenuItemTapped(eventItem))
diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt
index 0fc1a35445..ec34aa13b4 100644
--- a/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt
+++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt
@@ -32,6 +32,7 @@ import mozilla.components.feature.webcompat.reporter.WebCompatReporterFeature
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged
+import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
@@ -69,7 +70,12 @@ class DefaultToolbarMenu(
override val menuBuilder by lazy {
WebExtensionBrowserMenuBuilder(
- menuItems,
+ items =
+ if (FeatureFlags.toolbarMenuFeature) {
+ newCoreMenuItems
+ } else {
+ oldCoreMenuItems
+ },
endOfMenuAlwaysVisible = !shouldReverseItems,
store = store,
webExtIconTintColorResource = primaryTextColor(),
@@ -179,7 +185,148 @@ class DefaultToolbarMenu(
} ?: false
// End of predicates //
- private val menuItems by lazy {
+ private val oldCoreMenuItems by lazy {
+ val settings = BrowserMenuHighlightableItem(
+ label = context.getString(R.string.browser_menu_settings),
+ startImageResource = R.drawable.ic_settings,
+ iconTintColorResource = if (hasAccountProblem)
+ ThemeManager.resolveAttribute(R.attr.syncDisconnected, context) else
+ primaryTextColor(),
+ textColorResource = if (hasAccountProblem)
+ ThemeManager.resolveAttribute(R.attr.primaryText, context) else
+ primaryTextColor(),
+ highlight = BrowserMenuHighlight.HighPriority(
+ endImageResource = R.drawable.ic_sync_disconnected,
+ backgroundTint = context.getColorFromAttr(R.attr.syncDisconnectedBackground),
+ canPropagate = false
+ ),
+ isHighlighted = { hasAccountProblem }
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.Settings)
+ }
+
+ val desktopMode = BrowserMenuImageSwitch(
+ imageResource = R.drawable.ic_desktop,
+ label = context.getString(R.string.browser_menu_desktop_site),
+ initialState = {
+ selectedSession?.content?.desktopMode ?: false
+ }
+ ) { checked ->
+ onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
+ }
+
+ val addToTopSites = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_add_to_top_sites),
+ imageResource = R.drawable.ic_top_sites,
+ iconTintColorResource = primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.AddToTopSites)
+ }
+
+ val addToHomescreen = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_add_to_homescreen),
+ imageResource = R.drawable.ic_add_to_homescreen,
+ iconTintColorResource = primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen)
+ }
+
+ val syncedTabs = BrowserMenuImageText(
+ label = context.getString(R.string.synced_tabs),
+ imageResource = R.drawable.ic_synced_tabs,
+ iconTintColorResource = primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.SyncedTabs)
+ }
+
+ val installToHomescreen = BrowserMenuHighlightableItem(
+ label = context.getString(R.string.browser_menu_install_on_homescreen),
+ startImageResource = R.drawable.ic_add_to_homescreen,
+ iconTintColorResource = primaryTextColor(),
+ highlight = BrowserMenuHighlight.LowPriority(
+ label = context.getString(R.string.browser_menu_install_on_homescreen),
+ notificationTint = getColor(context, R.color.whats_new_notification_color)
+ ),
+ isHighlighted = {
+ !context.settings().installPwaOpened
+ }
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.InstallToHomeScreen)
+ }
+
+ val findInPage = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_find_in_page),
+ imageResource = R.drawable.mozac_ic_search,
+ iconTintColorResource = primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
+ }
+
+ val reportSiteIssuePlaceholder = WebExtensionPlaceholderMenuItem(
+ id = WebCompatReporterFeature.WEBCOMPAT_REPORTER_EXTENSION_ID
+ )
+
+ val saveToCollection = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_save_to_collection_2),
+ imageResource = R.drawable.ic_tab_collection,
+ iconTintColorResource = primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)
+ }
+
+ val deleteDataOnQuit = BrowserMenuImageText(
+ label = context.getString(R.string.delete_browsing_data_on_quit_action),
+ imageResource = R.drawable.ic_exit,
+ iconTintColorResource = primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.Quit)
+ }
+
+ val readerAppearance = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_read_appearance),
+ imageResource = R.drawable.ic_readermode_appearance,
+ iconTintColorResource = primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.ReaderModeAppearance)
+ }
+
+ val openInApp = BrowserMenuHighlightableItem(
+ label = context.getString(R.string.browser_menu_open_app_link),
+ startImageResource = R.drawable.ic_open_in_app,
+ iconTintColorResource = primaryTextColor(),
+ highlight = BrowserMenuHighlight.LowPriority(
+ label = context.getString(R.string.browser_menu_open_app_link),
+ notificationTint = getColor(context, R.color.whats_new_notification_color)
+ ),
+ isHighlighted = { !context.settings().openInAppOpened }
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.OpenInApp)
+ }
+
+ val historyItem = BrowserMenuImageText(
+ context.getString(R.string.library_history),
+ R.drawable.ic_history,
+ primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.History)
+ }
+
+ val bookmarksItem = BrowserMenuImageText(
+ context.getString(R.string.library_bookmarks),
+ R.drawable.ic_bookmark_filled,
+ primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.Bookmarks)
+ }
+
+ val downloadsItem = BrowserMenuImageText(
+ context.getString(R.string.library_downloads),
+ R.drawable.ic_download,
+ primaryTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.Downloads)
+ }
+
// Predicates that are called once, during screen init
val shouldShowSaveToCollection = (context.asActivity() as? HomeActivity)
?.browsingModeManager?.mode == BrowsingMode.Normal
@@ -216,151 +363,149 @@ class DefaultToolbarMenu(
}
}
- private val settings = BrowserMenuHighlightableItem(
- label = context.getString(R.string.browser_menu_settings),
- startImageResource = R.drawable.ic_settings,
- iconTintColorResource = if (hasAccountProblem)
- ThemeManager.resolveAttribute(R.attr.syncDisconnected, context) else
- primaryTextColor(),
- textColorResource = if (hasAccountProblem)
- ThemeManager.resolveAttribute(R.attr.primaryText, context) else
- primaryTextColor(),
- highlight = BrowserMenuHighlight.HighPriority(
- endImageResource = R.drawable.ic_sync_disconnected,
- backgroundTint = context.getColorFromAttr(R.attr.syncDisconnectedBackground),
- canPropagate = false
- ),
- isHighlighted = { hasAccountProblem }
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.Settings)
- }
+ private val newCoreMenuItems by lazy {
+ val newTabItem = BrowserMenuImageText(
+ context.getString(R.string.library_new_tab),
+ R.drawable.ic_bookmark_filled,
+ disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.NewTab)
+ }
- private val desktopMode = BrowserMenuImageSwitch(
- imageResource = R.drawable.ic_desktop,
- label = context.getString(R.string.browser_menu_desktop_site),
- initialState = {
- selectedSession?.content?.desktopMode ?: false
+ val bookmarksItem = BrowserMenuImageText(
+ context.getString(R.string.library_bookmarks),
+ R.drawable.ic_bookmark_filled,
+ disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.Bookmarks)
}
- ) { checked ->
- onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
- }
- private val addToTopSites = BrowserMenuImageText(
- label = context.getString(R.string.browser_menu_add_to_top_sites),
- imageResource = R.drawable.ic_top_sites,
- iconTintColorResource = primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.AddToTopSites)
- }
+ val historyItem = BrowserMenuImageText(
+ context.getString(R.string.library_history),
+ R.drawable.ic_history,
+ disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.History)
+ }
- private val addToHomescreen = BrowserMenuImageText(
- label = context.getString(R.string.browser_menu_add_to_homescreen),
- imageResource = R.drawable.ic_add_to_homescreen,
- iconTintColorResource = primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen)
- }
+ val downloadsItem = BrowserMenuImageText(
+ context.getString(R.string.library_downloads),
+ R.drawable.ic_download,
+ disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.Downloads)
+ }
- private val syncedTabs = BrowserMenuImageText(
- label = context.getString(R.string.synced_tabs),
- imageResource = R.drawable.ic_synced_tabs,
- iconTintColorResource = primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.SyncedTabs)
- }
+ val extensionsItem = BrowserMenuImageText(
+ context.getString(R.string.browser_menu_extensions),
+ R.drawable.ic_addons_extensions,
+ disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.AddonsManager)
+ }
- private val installToHomescreen = BrowserMenuHighlightableItem(
- label = context.getString(R.string.browser_menu_install_on_homescreen),
- startImageResource = R.drawable.ic_add_to_homescreen,
- iconTintColorResource = primaryTextColor(),
- highlight = BrowserMenuHighlight.LowPriority(
- label = context.getString(R.string.browser_menu_install_on_homescreen),
- notificationTint = getColor(context, R.color.whats_new_notification_color)
- ),
- isHighlighted = {
- !context.settings().installPwaOpened
+ val syncedTabsItem = BrowserMenuImageText(
+ context.getString(R.string.library_synced_tabs),
+ R.drawable.ic_synced_tabs,
+ disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.SyncedTabs)
}
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.InstallToHomeScreen)
- }
- private val findInPage = BrowserMenuImageText(
- label = context.getString(R.string.browser_menu_find_in_page),
- imageResource = R.drawable.mozac_ic_search,
- iconTintColorResource = primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
- }
+ val findInPageItem = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_find_in_page),
+ imageResource = R.drawable.mozac_ic_search,
+ iconTintColorResource = disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
+ }
- private val reportSiteIssuePlaceholder = WebExtensionPlaceholderMenuItem(
- id = WebCompatReporterFeature.WEBCOMPAT_REPORTER_EXTENSION_ID
- )
+ val desktopSiteItem = BrowserMenuImageSwitch(
+ imageResource = R.drawable.ic_desktop,
+ label = context.getString(R.string.browser_menu_desktop_site),
+ initialState = {
+ selectedSession?.content?.desktopMode ?: false
+ }
+ ) { checked ->
+ onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
+ }
- private val saveToCollection = BrowserMenuImageText(
- label = context.getString(R.string.browser_menu_save_to_collection_2),
- imageResource = R.drawable.ic_tab_collection,
- iconTintColorResource = primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)
- }
+ val addToHomeScreenItem = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_add_to_homescreen),
+ imageResource = R.drawable.ic_add_to_homescreen,
+ iconTintColorResource = disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen)
+ }
- private val deleteDataOnQuit = BrowserMenuImageText(
- label = context.getString(R.string.delete_browsing_data_on_quit_action),
- imageResource = R.drawable.ic_exit,
- iconTintColorResource = primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.Quit)
- }
+ val addToTopSitesItem = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_add_to_top_sites),
+ imageResource = R.drawable.ic_top_sites,
+ iconTintColorResource = disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.AddToTopSites)
+ }
- private val readerAppearance = BrowserMenuImageText(
- label = context.getString(R.string.browser_menu_read_appearance),
- imageResource = R.drawable.ic_readermode_appearance,
- iconTintColorResource = primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.ReaderModeAppearance)
- }
+ val saveToCollectionItem = BrowserMenuImageText(
+ label = context.getString(R.string.browser_menu_save_to_collection_2),
+ imageResource = R.drawable.ic_tab_collection,
+ iconTintColorResource = disabledTextColor()
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)
+ }
- private val openInApp = BrowserMenuHighlightableItem(
- label = context.getString(R.string.browser_menu_open_app_link),
- startImageResource = R.drawable.ic_open_in_app,
- iconTintColorResource = primaryTextColor(),
- highlight = BrowserMenuHighlight.LowPriority(
- label = context.getString(R.string.browser_menu_open_app_link),
- notificationTint = getColor(context, R.color.whats_new_notification_color)
- ),
- isHighlighted = { !context.settings().openInAppOpened }
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.OpenInApp)
- }
+ val settingsItem = BrowserMenuHighlightableItem(
+ label = context.getString(R.string.browser_menu_settings),
+ startImageResource = R.drawable.ic_settings,
+ iconTintColorResource = disabledTextColor(),
+ textColorResource = if (hasAccountProblem)
+ ThemeManager.resolveAttribute(R.attr.primaryText, context) else
+ primaryTextColor(),
+ highlight = BrowserMenuHighlight.HighPriority(
+ endImageResource = R.drawable.ic_sync_disconnected,
+ backgroundTint = context.getColorFromAttr(R.attr.syncDisconnectedBackground),
+ canPropagate = false
+ ),
+ isHighlighted = { hasAccountProblem }
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.Settings)
+ }
- val historyItem = BrowserMenuImageText(
- context.getString(R.string.library_history),
- R.drawable.ic_history,
- primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.History)
- }
+ val syncedTabsInTabsTray = context.components.settings
+ .syncedTabsInTabsTray
- val bookmarksItem = BrowserMenuImageText(
- context.getString(R.string.library_bookmarks),
- R.drawable.ic_bookmark_filled,
- primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.Bookmarks)
- }
+ val menuItems = listOfNotNull(
+ newTabItem,
+ BrowserMenuDivider(),
+ bookmarksItem,
+ historyItem,
+ downloadsItem,
+ extensionsItem,
+ if (syncedTabsInTabsTray) null else syncedTabsItem,
+ BrowserMenuDivider(),
+ findInPageItem,
+ desktopSiteItem,
+ BrowserMenuDivider(),
+ addToHomeScreenItem.apply { visible = ::canAddToHomescreen },
+ addToTopSitesItem,
+ saveToCollectionItem,
+ BrowserMenuDivider(),
+ settingsItem,
+ BrowserMenuDivider(),
+ menuToolbar
+ )
- val downloadsItem = BrowserMenuImageText(
- context.getString(R.string.library_downloads),
- R.drawable.ic_download,
- primaryTextColor()
- ) {
- onItemTapped.invoke(ToolbarMenu.Item.Downloads)
+ menuItems
}
@ColorRes
@VisibleForTesting
internal fun primaryTextColor() = ThemeManager.resolveAttribute(R.attr.primaryText, context)
+ @ColorRes
+ @VisibleForTesting
+ internal fun disabledTextColor() = R.color.toolbar_menu_transparent
+
@VisibleForTesting
internal fun registerForIsBookmarkedUpdates() {
store.flowScoped(lifecycleOwner) { flow ->
diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarMenu.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarMenu.kt
index 27b47c3090..87cb80ae3e 100644
--- a/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarMenu.kt
+++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarMenu.kt
@@ -31,6 +31,7 @@ interface ToolbarMenu {
object Bookmarks : Item()
object History : Item()
object Downloads : Item()
+ object NewTab : Item()
}
val menuBuilder: BrowserMenuBuilder
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 5f2d1b1a91..f8d09ea358 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -422,4 +422,7 @@
#1415141A
+
+
+ @android:color/transparent
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 515b2d760a..e6c09d865a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -128,6 +128,8 @@
Edit bookmark
Add-ons
+
+ Extensions
No add-ons here
@@ -517,6 +519,10 @@
Other Bookmarks
History
+
+ New tab
+
+ Find in page
Synced tabs
diff --git a/app/src/test/java/org/mozilla/fenix/components/toolbar/DefaultBrowserToolbarMenuControllerTest.kt b/app/src/test/java/org/mozilla/fenix/components/toolbar/DefaultBrowserToolbarMenuControllerTest.kt
index 4082077ae6..211cf0fc90 100644
--- a/app/src/test/java/org/mozilla/fenix/components/toolbar/DefaultBrowserToolbarMenuControllerTest.kt
+++ b/app/src/test/java/org/mozilla/fenix/components/toolbar/DefaultBrowserToolbarMenuControllerTest.kt
@@ -45,6 +45,7 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
@@ -64,6 +65,7 @@ import org.mozilla.fenix.utils.Settings
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(FenixRobolectricTestRunner::class)
+@Suppress("ForbiddenComment")
class DefaultBrowserToolbarMenuControllerTest {
@get:Rule
@@ -124,8 +126,121 @@ class DefaultBrowserToolbarMenuControllerTest {
unmockkObject(FenixSnackbar.Companion)
}
+ // TODO: These can be removed for https://github.com/mozilla-mobile/fenix/issues/17870
+ // todo === Start ===
@Test
- fun handleToolbarBackPress() = runBlockingTest {
+ fun handleToolbarBookmarkPressWithReaderModeInactive() = runBlockingTest {
+ if (!FeatureFlags.toolbarMenuFeature) {
+ val item = ToolbarMenu.Item.Bookmark
+
+ val title = "Mozilla"
+ val readerUrl = "moz-extension://1234"
+ val readerTab = createTab(
+ url = readerUrl,
+ readerState = ReaderState(active = false, activeUrl = "https://1234.org"),
+ title = title
+ )
+ browserStore =
+ BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
+ every { currentSession.id } returns readerTab.id
+ every { currentSession.title } returns title
+ every { currentSession.url } returns "https://mozilla.org"
+
+ val controller = createController(scope = this)
+ controller.handleToolbarItemInteraction(item)
+
+ verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BOOKMARK)) }
+ verify { bookmarkTapped("https://mozilla.org", title) }
+ }
+ }
+
+ @Test
+ fun `IF reader mode is active WHEN bookmark menu item is pressed THEN menu item is handled`() = runBlockingTest {
+ if (!FeatureFlags.toolbarMenuFeature) {
+ val item = ToolbarMenu.Item.Bookmark
+ val title = "Mozilla"
+ val readerUrl = "moz-extension://1234"
+ val readerTab = createTab(
+ url = readerUrl,
+ readerState = ReaderState(active = true, activeUrl = "https://mozilla.org"),
+ title = title
+ )
+ browserStore =
+ BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
+ every { currentSession.id } returns readerTab.id
+ every { currentSession.title } returns title
+ every { currentSession.url } returns readerUrl
+
+ val controller = createController(scope = this)
+ controller.handleToolbarItemInteraction(item)
+
+ verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BOOKMARK)) }
+ verify { bookmarkTapped("https://mozilla.org", title) }
+ }
+ }
+
+ @Test
+ fun `WHEN open in Fenix menu item is pressed THEN menu item is handled correctly`() = runBlockingTest {
+ if (!FeatureFlags.toolbarMenuFeature) {
+ val controller = createController(scope = this, customTabSession = currentSession)
+
+ val item = ToolbarMenu.Item.OpenInFenix
+
+ every { currentSession.customTabConfig } returns mockk()
+ every { activity.startActivity(any()) } just Runs
+
+ controller.handleToolbarItemInteraction(item)
+
+ verify { sessionFeature.release() }
+ verify { currentSession.customTabConfig = null }
+ verify { sessionManager.select(currentSession) }
+ verify { activity.startActivity(openInFenixIntent) }
+ verify { activity.finishAndRemoveTask() }
+ }
+ }
+
+ @Test
+ fun `WHEN quit menu item is pressed THEN menu item is handled correctly`() = runBlockingTest {
+ if (!FeatureFlags.toolbarMenuFeature) {
+ val item = ToolbarMenu.Item.Quit
+ val testScope = this
+
+ val controller = createController(scope = testScope)
+
+ controller.handleToolbarItemInteraction(item)
+
+ verify { deleteAndQuit(activity, testScope, null) }
+ }
+ }
+
+ @Test
+ fun handleToolbarOpenInAppPress() = runBlockingTest {
+ if (!FeatureFlags.toolbarMenuFeature) {
+ val item = ToolbarMenu.Item.OpenInApp
+
+ val controller = createController(scope = this)
+
+ controller.handleToolbarItemInteraction(item)
+
+ verify { settings.openInAppOpened = true }
+ }
+ }
+
+ @Test
+ fun `WHEN reader mode menu item is pressed THEN handle appearance change`() = runBlockingTest {
+ val item = ToolbarMenu.Item.ReaderModeAppearance
+
+ val controller = createController(scope = this)
+
+ controller.handleToolbarItemInteraction(item)
+
+ verify { readerModeController.showControls() }
+ verify { metrics.track(Event.ReaderModeAppearanceOpened) }
+ }
+ // todo === End ===
+
+ @Test
+ fun `WHEN backwards nav menu item is pressed THEN the session navigates back with active session`() = runBlockingTest {
val item = ToolbarMenu.Item.Back(false)
val controller = createController(scope = this)
@@ -136,7 +251,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarBackLongPress() = runBlockingTest {
+ fun `WHEN backwards nav menu item is long pressed THEN the session navigates back with no active session`() = runBlockingTest {
val item = ToolbarMenu.Item.Back(true)
val controller = createController(scope = this)
@@ -149,7 +264,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarForwardPress() = runBlockingTest {
+ fun `WHEN forward nav menu item is pressed THEN the session navigates forward to active session`() = runBlockingTest {
val item = ToolbarMenu.Item.Forward(false)
val controller = createController(scope = this)
@@ -160,7 +275,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarForwardLongPress() = runBlockingTest {
+ fun `WHEN forward nav menu item is long pressed THEN the browser navigates forward with no active session`() = runBlockingTest {
val item = ToolbarMenu.Item.Forward(true)
val controller = createController(scope = this)
@@ -173,7 +288,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarReloadPress() = runBlockingTest {
+ fun `WHEN reload nav menu item is pressed THEN the session reloads from cache`() = runBlockingTest {
val item = ToolbarMenu.Item.Reload(false)
val controller = createController(scope = this)
@@ -184,7 +299,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarReloadLongPress() = runBlockingTest {
+ fun `WHEN reload nav menu item is long pressed THEN the session reloads with no cache`() = runBlockingTest {
val item = ToolbarMenu.Item.Reload(true)
val controller = createController(scope = this)
@@ -200,7 +315,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarStopPress() = runBlockingTest {
+ fun `WHEN stop nav menu item is pressed THEN the session stops loading`() = runBlockingTest {
val item = ToolbarMenu.Item.Stop
val controller = createController(scope = this)
@@ -211,7 +326,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarSettingsPress() = runBlockingTest {
+ fun `WHEN settings menu item is pressed THEN menu item is handled`() = runBlockingTest {
val item = ToolbarMenu.Item.Settings
val controller = createController(scope = this)
@@ -224,52 +339,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarBookmarkPressWithReaderModeInactive() = runBlockingTest {
- val item = ToolbarMenu.Item.Bookmark
- val title = "Mozilla"
- val readerUrl = "moz-extension://1234"
- val readerTab = createTab(
- url = readerUrl,
- readerState = ReaderState(active = false, activeUrl = "https://1234.org"),
- title = title
- )
- browserStore =
- BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
- every { currentSession.id } returns readerTab.id
- every { currentSession.title } returns title
- every { currentSession.url } returns "https://mozilla.org"
-
- val controller = createController(scope = this)
- controller.handleToolbarItemInteraction(item)
-
- verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BOOKMARK)) }
- verify { bookmarkTapped("https://mozilla.org", title) }
- }
-
- @Test
- fun handleToolbarBookmarkPressWithReaderModeActive() = runBlockingTest {
- val item = ToolbarMenu.Item.Bookmark
- val title = "Mozilla"
- val readerUrl = "moz-extension://1234"
- val readerTab = createTab(
- url = readerUrl,
- readerState = ReaderState(active = true, activeUrl = "https://mozilla.org"),
- title = title
- )
- browserStore = BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
- every { currentSession.id } returns readerTab.id
- every { currentSession.title } returns title
- every { currentSession.url } returns readerUrl
-
- val controller = createController(scope = this)
- controller.handleToolbarItemInteraction(item)
-
- verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BOOKMARK)) }
- verify { bookmarkTapped("https://mozilla.org", title) }
- }
-
- @Test
- fun handleToolbarBookmarksPress() = runBlockingTest {
+ fun `WHEN bookmark menu item is pressed THEN navigate to bookmarks page`() = runBlockingTest {
val item = ToolbarMenu.Item.Bookmarks
val controller = createController(scope = this)
@@ -282,7 +352,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarHistoryPress() = runBlockingTest {
+ fun `WHEN history menu item is pressed THEN navigate to history page`() = runBlockingTest {
val item = ToolbarMenu.Item.History
val controller = createController(scope = this)
@@ -295,7 +365,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarRequestDesktopOnPress() = runBlockingTest {
+ fun `WHEN request desktop menu item is toggled On THEN desktop site is requested for the session`() = runBlockingTest {
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase =
mockk(relaxed = true)
val item = ToolbarMenu.Item.RequestDesktop(true)
@@ -315,7 +385,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarRequestDesktopOffPress() = runBlockingTest {
+ fun `WHEN request desktop menu item is toggled Off THEN mobile site is requested for the session`() = runBlockingTest {
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase =
mockk(relaxed = true)
val item = ToolbarMenu.Item.RequestDesktop(false)
@@ -335,7 +405,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarAddToTopSitesPressed() = runBlockingTest {
+ fun `WHEN Add To Top Sites menu item is pressed THEN add site AND show snackbar`() = runBlockingTest {
val item = ToolbarMenu.Item.AddToTopSites
val addPinnedSiteUseCase: TopSitesUseCases.AddPinnedSiteUseCase = mockk(relaxed = true)
@@ -353,7 +423,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarAddonsManagerPress() = runBlockingTest {
+ fun `WHEN addon extensions menu item is pressed THEN navigate to addons manager`() = runBlockingTest {
val item = ToolbarMenu.Item.AddonsManager
val controller = createController(scope = this)
@@ -363,7 +433,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarAddToHomeScreenPress() = runBlockingTest {
+ fun `WHEN Add To Home Screen menu item is pressed THEN add site`() = runBlockingTest {
val item = ToolbarMenu.Item.AddToHomeScreen
val controller = createController(scope = this)
@@ -373,7 +443,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarSharePressWithReaderModeInactive() = runBlockingTest {
+ fun `IF reader mode is inactive WHEN share menu item is pressed THEN navigate to share screen`() = runBlockingTest {
val item = ToolbarMenu.Item.Share
val title = "Mozilla"
val readerUrl = "moz-extension://1234"
@@ -404,7 +474,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarSharePressWithReaderModeActive() = runBlockingTest {
+ fun `IF reader mode is active WHEN share menu item is pressed THEN navigate to share screen`() = runBlockingTest {
val item = ToolbarMenu.Item.Share
val title = "Mozilla"
val readerUrl = "moz-extension://1234"
@@ -435,7 +505,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarFindInPagePress() = runBlockingTest {
+ fun `WHEN Find In Page menu item is pressed THEN launch finder`() = runBlockingTest {
val item = ToolbarMenu.Item.FindInPage
val controller = createController(scope = this)
@@ -446,7 +516,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarSaveToCollectionPressWhenAtLeastOneCollectionExists() = runBlockingTest {
+ fun `IF one or more collection exists WHEN Save To Collection menu item is pressed THEN navigate to save collection page`() = runBlockingTest {
val item = ToolbarMenu.Item.SaveToCollection
val cachedTabCollections: List = mockk(relaxed = true)
every { tabCollectionStorage.cachedTabCollections } returns cachedTabCollections
@@ -474,7 +544,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarSaveToCollectionPressWhenNoCollectionsExists() = runBlockingTest {
+ fun `IF no collection exists WHEN Save To Collection menu item is pressed THEN navigate to create collection page`() = runBlockingTest {
val item = ToolbarMenu.Item.SaveToCollection
val cachedTabCollectionsEmpty: List = emptyList()
every { tabCollectionStorage.cachedTabCollections } returns cachedTabCollectionsEmpty
@@ -499,56 +569,22 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
- fun handleToolbarOpenInFenixPress() = runBlockingTest {
- val controller = createController(scope = this, customTabSession = currentSession)
-
- val item = ToolbarMenu.Item.OpenInFenix
-
- every { currentSession.customTabConfig } returns mockk()
- every { activity.startActivity(any()) } just Runs
-
- controller.handleToolbarItemInteraction(item)
-
- verify { sessionFeature.release() }
- verify { currentSession.customTabConfig = null }
- verify { sessionManager.select(currentSession) }
- verify { activity.startActivity(openInFenixIntent) }
- verify { activity.finishAndRemoveTask() }
- }
-
- @Test
- fun handleToolbarQuitPress() = runBlockingTest {
- val item = ToolbarMenu.Item.Quit
- val testScope = this
-
- val controller = createController(scope = testScope)
-
- controller.handleToolbarItemInteraction(item)
-
- verify { deleteAndQuit(activity, testScope, null) }
- }
-
- @Test
- fun handleToolbarReaderModeAppearancePress() = runBlockingTest {
- val item = ToolbarMenu.Item.ReaderModeAppearance
+ fun `WHEN New Tab menu item is pressed THEN navigate to a new tab home`() = runBlockingTest {
+ val item = ToolbarMenu.Item.NewTab
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
- verify { readerModeController.showControls() }
- verify { metrics.track(Event.ReaderModeAppearanceOpened) }
- }
-
- @Test
- fun handleToolbarOpenInAppPress() = runBlockingTest {
- val item = ToolbarMenu.Item.OpenInApp
-
- val controller = createController(scope = this)
-
- controller.handleToolbarItemInteraction(item)
-
- verify { settings.openInAppOpened = true }
+ verify {
+ navController.navigate(
+ directionsEq(
+ NavGraphDirections.actionGlobalHome(
+ focusOnAddressBar = true
+ )
+ )
+ )
+ }
}
private fun createController(