Loading app/metrics.yaml +1 −2 Original line number Original line Diff line number Diff line Loading @@ -2200,8 +2200,7 @@ tabs_tray: save_to_collection: save_to_collection: type: event type: event description: | description: | A user tapped the save to collection button in the A user tapped the save to collection button in the tabs tray three dot menu within the tabs tray bugs: bugs: - https://github.com/mozilla-mobile/fenix/issues/11273 - https://github.com/mozilla-mobile/fenix/issues/11273 data_reviews: data_reviews: Loading app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +2 −2 Original line number Original line Diff line number Diff line Loading @@ -85,7 +85,7 @@ class TabbedBrowsingTest { }.openTabsListThreeDotMenu { }.openTabsListThreeDotMenu { verifyCloseAllTabsButton() verifyCloseAllTabsButton() verifyShareTabButton() verifyShareTabButton() verifySaveCollection() verifySelectTabs() } } } } Loading Loading @@ -127,7 +127,7 @@ class TabbedBrowsingTest { }.openTabsListThreeDotMenu { }.openTabsListThreeDotMenu { verifyCloseAllTabsButton() verifyCloseAllTabsButton() verifyShareTabButton() verifyShareTabButton() verifySaveCollection() verifySelectTabs() }.closeAllTabs { }.closeAllTabs { verifyNoTabsOpened() verifyNoTabsOpened() } } Loading app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt +5 −0 Original line number Original line Diff line number Diff line Loading @@ -69,6 +69,7 @@ class ThreeDotMenuMainRobot { fun verifyShareTabButton() = assertShareTabButton() fun verifyShareTabButton() = assertShareTabButton() fun verifySaveCollection() = assertSaveCollectionButton() fun verifySaveCollection() = assertSaveCollectionButton() fun verifySelectTabs() = assertSelectTabsButton() fun clickBrowserViewSaveCollectionButton() { fun clickBrowserViewSaveCollectionButton() { browserViewSaveCollectionButton().click() browserViewSaveCollectionButton().click() Loading Loading @@ -430,6 +431,10 @@ private fun saveCollectionButton() = onView(allOf(withText("Save to collection") private fun assertSaveCollectionButton() = saveCollectionButton() private fun assertSaveCollectionButton() = saveCollectionButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun selectTabsButton() = onView(allOf(withText("Select tabs"))).inRoot(RootMatchers.isPlatformPopup()) private fun assertSelectTabsButton() = selectTabsButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun addNewCollectionButton() = onView(allOf(withText("Add new collection"))) private fun addNewCollectionButton() = onView(allOf(withText("Add new collection"))) private fun assertaddNewCollectionButton() = addNewCollectionButton() private fun assertaddNewCollectionButton() = addNewCollectionButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) Loading app/src/main/java/org/mozilla/fenix/tabtray/MultiselectSelectionMenu.kt +0 −4 Original line number Original line Diff line number Diff line Loading @@ -8,8 +8,6 @@ import android.content.Context import mozilla.components.browser.menu.BrowserMenuBuilder import mozilla.components.browser.menu.BrowserMenuBuilder import mozilla.components.browser.menu.item.SimpleBrowserMenuItem import mozilla.components.browser.menu.item.SimpleBrowserMenuItem import org.mozilla.fenix.R import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components class MultiselectSelectionMenu( class MultiselectSelectionMenu( private val context: Context, private val context: Context, Loading @@ -28,7 +26,6 @@ class MultiselectSelectionMenu( context.getString(R.string.tab_tray_multiselect_menu_item_bookmark), context.getString(R.string.tab_tray_multiselect_menu_item_bookmark), textColorResource = R.color.primary_text_normal_theme textColorResource = R.color.primary_text_normal_theme ) { ) { context.components.analytics.metrics.track(Event.TabsTraySaveToCollectionPressed) onItemTapped.invoke(Item.BookmarkTabs) onItemTapped.invoke(Item.BookmarkTabs) }, }, Loading @@ -36,7 +33,6 @@ class MultiselectSelectionMenu( context.getString(R.string.tab_tray_multiselect_menu_item_close), context.getString(R.string.tab_tray_multiselect_menu_item_close), textColorResource = R.color.primary_text_normal_theme textColorResource = R.color.primary_text_normal_theme ) { ) { context.components.analytics.metrics.track(Event.TabsTrayShareAllTabsPressed) onItemTapped.invoke(Item.DeleteTabs) onItemTapped.invoke(Item.DeleteTabs) } } ) ) Loading app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt +20 −7 Original line number Original line Diff line number Diff line Loading @@ -6,7 +6,6 @@ package org.mozilla.fenix.tabtray import androidx.navigation.NavController import androidx.navigation.NavController import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.launch import mozilla.appservices.places.BookmarkRoot import mozilla.appservices.places.BookmarkRoot Loading @@ -14,6 +13,7 @@ import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.SessionManager import mozilla.components.browser.state.selector.getNormalOrPrivateTabs import mozilla.components.browser.state.selector.getNormalOrPrivateTabs import mozilla.components.browser.state.selector.normalTabs import mozilla.components.browser.state.selector.normalTabs import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.base.profiler.Profiler import mozilla.components.concept.base.profiler.Profiler import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.concept.engine.prompt.ShareData Loading @@ -25,6 +25,8 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.components.TabCollectionStorage import org.mozilla.fenix.components.TabCollectionStorage import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.home.HomeFragment import org.mozilla.fenix.home.HomeFragment import mozilla.components.browser.storage.sync.Tab as SyncTab import mozilla.components.browser.storage.sync.Tab as SyncTab Loading Loading @@ -58,19 +60,27 @@ interface TabTrayController { /** /** * Default behavior of [TabTrayController]. Other implementations are possible. * Default behavior of [TabTrayController]. Other implementations are possible. * * * @param activity [Activity] the current activity. * @param profiler [Profiler] used for profiling. * @param profiler [Profiler] used for profiling. * @param sessionManager [HomeActivity] used for retrieving a list of sessions. * @param sessionManager [HomeActivity] used for retrieving a list of sessions. * @param browserStore [BrowserStore] holds the global [BrowserState]. * @param browsingModeManager [HomeActivity] used for registering browsing mode. * @param browsingModeManager [HomeActivity] used for registering browsing mode. * @param navController [NavController] used for navigation. * @param tabCollectionStorage [TabCollectionStorage] storage for saving collections. * @param ioScope [CoroutineScope] with an IO dispatcher used for structured concurrency. * @param metrics reference to the configured [MetricController] to record telemetry events. * @param tabsUseCases [TabsUseCases] use cases related to the tabs feature. * @param navController - [NavController] used for navigation. * @param dismissTabTray callback allowing to request this entire Fragment to be dismissed. * @param dismissTabTray callback allowing to request this entire Fragment to be dismissed. * @param tabTrayDialogFragmentStore [TabTrayDialogFragmentStore] holding the State for all Views displayed * in this Controller's Fragment. * @param dismissTabTrayAndNavigateHome callback allowing showing an undo snackbar after tab deletion. * @param dismissTabTrayAndNavigateHome callback allowing showing an undo snackbar after tab deletion. * @param selectTabUseCase [TabsUseCases.SelectTabUseCase] callback allowing for selecting a tab. * @param registerCollectionStorageObserver callback allowing for registering the [TabCollectionStorage.Observer] * @param registerCollectionStorageObserver callback allowing for registering the [TabCollectionStorage.Observer] * when needed. * when needed. * @param tabTrayDialogFragmentStore [TabTrayDialogFragmentStore] holding the State for all Views displayed * in this Controller's Fragment. * @param selectTabUseCase [TabsUseCases.SelectTabUseCase] callback allowing for selecting a tab. * @param showChooseCollectionDialog callback allowing saving a list of sessions to an existing collection. * @param showChooseCollectionDialog callback allowing saving a list of sessions to an existing collection. * @param showAddNewCollectionDialog callback allowing for saving a list of sessions to a new collection. * @param showAddNewCollectionDialog callback allowing for saving a list of sessions to a new collection. * @param showUndoSnackbarForTabs callback allowing for showing an undo snackbar for removed tabs. * @param showBookmarksSnackbar callback allowing for showing a snackbar with action to view bookmarks. */ */ @Suppress("TooManyFunctions") @Suppress("TooManyFunctions") class DefaultTabTrayController( class DefaultTabTrayController( Loading @@ -81,7 +91,8 @@ class DefaultTabTrayController( private val browsingModeManager: BrowsingModeManager, private val browsingModeManager: BrowsingModeManager, private val tabCollectionStorage: TabCollectionStorage, private val tabCollectionStorage: TabCollectionStorage, private val bookmarksStorage: BookmarksStorage, private val bookmarksStorage: BookmarksStorage, private val scope: CoroutineScope, private val ioScope: CoroutineScope, private val metrics: MetricController, private val tabsUseCases: TabsUseCases, private val tabsUseCases: TabsUseCases, private val navController: NavController, private val navController: NavController, private val dismissTabTray: () -> Unit, private val dismissTabTray: () -> Unit, Loading Loading @@ -115,6 +126,8 @@ class DefaultTabTrayController( } } override fun handleSaveToCollectionClicked(selectedTabs: Set<Tab>) { override fun handleSaveToCollectionClicked(selectedTabs: Set<Tab>) { metrics.track(Event.TabsTraySaveToCollectionPressed) val sessionList = selectedTabs.map { val sessionList = selectedTabs.map { sessionManager.findSessionById(it.id) ?: return sessionManager.findSessionById(it.id) ?: return } } Loading Loading @@ -155,7 +168,7 @@ class DefaultTabTrayController( override fun handleBookmarkSelectedTabs(selectedTabs: Set<Tab>) { override fun handleBookmarkSelectedTabs(selectedTabs: Set<Tab>) { selectedTabs.forEach { selectedTabs.forEach { scope.launch(IO) { ioScope.launch { val shouldAddBookmark = bookmarksStorage.getBookmarksWithUrl(it.url) val shouldAddBookmark = bookmarksStorage.getBookmarksWithUrl(it.url) .firstOrNull { it.url == it.url } == null .firstOrNull { it.url == it.url } == null if (shouldAddBookmark) { if (shouldAddBookmark) { Loading Loading
app/metrics.yaml +1 −2 Original line number Original line Diff line number Diff line Loading @@ -2200,8 +2200,7 @@ tabs_tray: save_to_collection: save_to_collection: type: event type: event description: | description: | A user tapped the save to collection button in the A user tapped the save to collection button in the tabs tray three dot menu within the tabs tray bugs: bugs: - https://github.com/mozilla-mobile/fenix/issues/11273 - https://github.com/mozilla-mobile/fenix/issues/11273 data_reviews: data_reviews: Loading
app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +2 −2 Original line number Original line Diff line number Diff line Loading @@ -85,7 +85,7 @@ class TabbedBrowsingTest { }.openTabsListThreeDotMenu { }.openTabsListThreeDotMenu { verifyCloseAllTabsButton() verifyCloseAllTabsButton() verifyShareTabButton() verifyShareTabButton() verifySaveCollection() verifySelectTabs() } } } } Loading Loading @@ -127,7 +127,7 @@ class TabbedBrowsingTest { }.openTabsListThreeDotMenu { }.openTabsListThreeDotMenu { verifyCloseAllTabsButton() verifyCloseAllTabsButton() verifyShareTabButton() verifyShareTabButton() verifySaveCollection() verifySelectTabs() }.closeAllTabs { }.closeAllTabs { verifyNoTabsOpened() verifyNoTabsOpened() } } Loading
app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt +5 −0 Original line number Original line Diff line number Diff line Loading @@ -69,6 +69,7 @@ class ThreeDotMenuMainRobot { fun verifyShareTabButton() = assertShareTabButton() fun verifyShareTabButton() = assertShareTabButton() fun verifySaveCollection() = assertSaveCollectionButton() fun verifySaveCollection() = assertSaveCollectionButton() fun verifySelectTabs() = assertSelectTabsButton() fun clickBrowserViewSaveCollectionButton() { fun clickBrowserViewSaveCollectionButton() { browserViewSaveCollectionButton().click() browserViewSaveCollectionButton().click() Loading Loading @@ -430,6 +431,10 @@ private fun saveCollectionButton() = onView(allOf(withText("Save to collection") private fun assertSaveCollectionButton() = saveCollectionButton() private fun assertSaveCollectionButton() = saveCollectionButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun selectTabsButton() = onView(allOf(withText("Select tabs"))).inRoot(RootMatchers.isPlatformPopup()) private fun assertSelectTabsButton() = selectTabsButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun addNewCollectionButton() = onView(allOf(withText("Add new collection"))) private fun addNewCollectionButton() = onView(allOf(withText("Add new collection"))) private fun assertaddNewCollectionButton() = addNewCollectionButton() private fun assertaddNewCollectionButton() = addNewCollectionButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) Loading
app/src/main/java/org/mozilla/fenix/tabtray/MultiselectSelectionMenu.kt +0 −4 Original line number Original line Diff line number Diff line Loading @@ -8,8 +8,6 @@ import android.content.Context import mozilla.components.browser.menu.BrowserMenuBuilder import mozilla.components.browser.menu.BrowserMenuBuilder import mozilla.components.browser.menu.item.SimpleBrowserMenuItem import mozilla.components.browser.menu.item.SimpleBrowserMenuItem import org.mozilla.fenix.R import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components class MultiselectSelectionMenu( class MultiselectSelectionMenu( private val context: Context, private val context: Context, Loading @@ -28,7 +26,6 @@ class MultiselectSelectionMenu( context.getString(R.string.tab_tray_multiselect_menu_item_bookmark), context.getString(R.string.tab_tray_multiselect_menu_item_bookmark), textColorResource = R.color.primary_text_normal_theme textColorResource = R.color.primary_text_normal_theme ) { ) { context.components.analytics.metrics.track(Event.TabsTraySaveToCollectionPressed) onItemTapped.invoke(Item.BookmarkTabs) onItemTapped.invoke(Item.BookmarkTabs) }, }, Loading @@ -36,7 +33,6 @@ class MultiselectSelectionMenu( context.getString(R.string.tab_tray_multiselect_menu_item_close), context.getString(R.string.tab_tray_multiselect_menu_item_close), textColorResource = R.color.primary_text_normal_theme textColorResource = R.color.primary_text_normal_theme ) { ) { context.components.analytics.metrics.track(Event.TabsTrayShareAllTabsPressed) onItemTapped.invoke(Item.DeleteTabs) onItemTapped.invoke(Item.DeleteTabs) } } ) ) Loading
app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt +20 −7 Original line number Original line Diff line number Diff line Loading @@ -6,7 +6,6 @@ package org.mozilla.fenix.tabtray import androidx.navigation.NavController import androidx.navigation.NavController import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.launch import mozilla.appservices.places.BookmarkRoot import mozilla.appservices.places.BookmarkRoot Loading @@ -14,6 +13,7 @@ import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.SessionManager import mozilla.components.browser.state.selector.getNormalOrPrivateTabs import mozilla.components.browser.state.selector.getNormalOrPrivateTabs import mozilla.components.browser.state.selector.normalTabs import mozilla.components.browser.state.selector.normalTabs import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.base.profiler.Profiler import mozilla.components.concept.base.profiler.Profiler import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.concept.engine.prompt.ShareData Loading @@ -25,6 +25,8 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.components.TabCollectionStorage import org.mozilla.fenix.components.TabCollectionStorage import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.home.HomeFragment import org.mozilla.fenix.home.HomeFragment import mozilla.components.browser.storage.sync.Tab as SyncTab import mozilla.components.browser.storage.sync.Tab as SyncTab Loading Loading @@ -58,19 +60,27 @@ interface TabTrayController { /** /** * Default behavior of [TabTrayController]. Other implementations are possible. * Default behavior of [TabTrayController]. Other implementations are possible. * * * @param activity [Activity] the current activity. * @param profiler [Profiler] used for profiling. * @param profiler [Profiler] used for profiling. * @param sessionManager [HomeActivity] used for retrieving a list of sessions. * @param sessionManager [HomeActivity] used for retrieving a list of sessions. * @param browserStore [BrowserStore] holds the global [BrowserState]. * @param browsingModeManager [HomeActivity] used for registering browsing mode. * @param browsingModeManager [HomeActivity] used for registering browsing mode. * @param navController [NavController] used for navigation. * @param tabCollectionStorage [TabCollectionStorage] storage for saving collections. * @param ioScope [CoroutineScope] with an IO dispatcher used for structured concurrency. * @param metrics reference to the configured [MetricController] to record telemetry events. * @param tabsUseCases [TabsUseCases] use cases related to the tabs feature. * @param navController - [NavController] used for navigation. * @param dismissTabTray callback allowing to request this entire Fragment to be dismissed. * @param dismissTabTray callback allowing to request this entire Fragment to be dismissed. * @param tabTrayDialogFragmentStore [TabTrayDialogFragmentStore] holding the State for all Views displayed * in this Controller's Fragment. * @param dismissTabTrayAndNavigateHome callback allowing showing an undo snackbar after tab deletion. * @param dismissTabTrayAndNavigateHome callback allowing showing an undo snackbar after tab deletion. * @param selectTabUseCase [TabsUseCases.SelectTabUseCase] callback allowing for selecting a tab. * @param registerCollectionStorageObserver callback allowing for registering the [TabCollectionStorage.Observer] * @param registerCollectionStorageObserver callback allowing for registering the [TabCollectionStorage.Observer] * when needed. * when needed. * @param tabTrayDialogFragmentStore [TabTrayDialogFragmentStore] holding the State for all Views displayed * in this Controller's Fragment. * @param selectTabUseCase [TabsUseCases.SelectTabUseCase] callback allowing for selecting a tab. * @param showChooseCollectionDialog callback allowing saving a list of sessions to an existing collection. * @param showChooseCollectionDialog callback allowing saving a list of sessions to an existing collection. * @param showAddNewCollectionDialog callback allowing for saving a list of sessions to a new collection. * @param showAddNewCollectionDialog callback allowing for saving a list of sessions to a new collection. * @param showUndoSnackbarForTabs callback allowing for showing an undo snackbar for removed tabs. * @param showBookmarksSnackbar callback allowing for showing a snackbar with action to view bookmarks. */ */ @Suppress("TooManyFunctions") @Suppress("TooManyFunctions") class DefaultTabTrayController( class DefaultTabTrayController( Loading @@ -81,7 +91,8 @@ class DefaultTabTrayController( private val browsingModeManager: BrowsingModeManager, private val browsingModeManager: BrowsingModeManager, private val tabCollectionStorage: TabCollectionStorage, private val tabCollectionStorage: TabCollectionStorage, private val bookmarksStorage: BookmarksStorage, private val bookmarksStorage: BookmarksStorage, private val scope: CoroutineScope, private val ioScope: CoroutineScope, private val metrics: MetricController, private val tabsUseCases: TabsUseCases, private val tabsUseCases: TabsUseCases, private val navController: NavController, private val navController: NavController, private val dismissTabTray: () -> Unit, private val dismissTabTray: () -> Unit, Loading Loading @@ -115,6 +126,8 @@ class DefaultTabTrayController( } } override fun handleSaveToCollectionClicked(selectedTabs: Set<Tab>) { override fun handleSaveToCollectionClicked(selectedTabs: Set<Tab>) { metrics.track(Event.TabsTraySaveToCollectionPressed) val sessionList = selectedTabs.map { val sessionList = selectedTabs.map { sessionManager.findSessionById(it.id) ?: return sessionManager.findSessionById(it.id) ?: return } } Loading Loading @@ -155,7 +168,7 @@ class DefaultTabTrayController( override fun handleBookmarkSelectedTabs(selectedTabs: Set<Tab>) { override fun handleBookmarkSelectedTabs(selectedTabs: Set<Tab>) { selectedTabs.forEach { selectedTabs.forEach { scope.launch(IO) { ioScope.launch { val shouldAddBookmark = bookmarksStorage.getBookmarksWithUrl(it.url) val shouldAddBookmark = bookmarksStorage.getBookmarksWithUrl(it.url) .firstOrNull { it.url == it.url } == null .firstOrNull { it.url == it.url } == null if (shouldAddBookmark) { if (shouldAddBookmark) { Loading