diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTray.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTray.kt index 7dc9986183..5d8200687d 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTray.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTray.kt @@ -29,6 +29,7 @@ import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.rememberPagerState import mozilla.components.browser.state.selector.normalTabs +import mozilla.components.browser.state.selector.privateTabs import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.ContentState import mozilla.components.browser.state.state.TabSessionState @@ -75,6 +76,11 @@ import mozilla.components.browser.storage.sync.Tab as SyncTab * the multi select banner. * @param onShareSelectedTabsClick Invoked when the user clicks on the share button from the * multi select banner. + * @param onShareAllTabsClick Invoked when the user clicks on the share all tabs banner menu item. + * @param onTabSettingsClick Invoked when the user clicks on the tab settings banner menu item. + * @param onRecentlyClosedClick Invoked when the user clicks on the recently closed banner menu item. + * @param onAccountSettingsClick Invoked when the user clicks on the account settings banner menu item. + * @param onDeleteAllTabsClick Invoked when the user clicks on the close all tabs banner menu item. */ @OptIn(ExperimentalPagerApi::class) @Suppress("LongMethod", "LongParameterList", "ComplexMethod") @@ -102,9 +108,16 @@ fun TabsTray( onSyncedTabClick: (SyncTab) -> Unit, onSaveToCollectionClick: () -> Unit, onShareSelectedTabsClick: () -> Unit, + onShareAllTabsClick: () -> Unit, + onTabSettingsClick: () -> Unit, + onRecentlyClosedClick: () -> Unit, + onAccountSettingsClick: () -> Unit, + onDeleteAllTabsClick: () -> Unit, ) { val normalTabCount = browserStore .observeAsComposableState { state -> state.normalTabs.size }.value ?: 0 + val privateTabCount = browserStore + .observeAsComposableState { state -> state.privateTabs.size }.value ?: 0 val multiselectMode = tabsTrayStore .observeAsComposableState { state -> state.mode }.value ?: TabsTrayState.Mode.Normal val selectedPage = tabsTrayStore @@ -141,11 +154,18 @@ fun TabsTray( selectMode = multiselectMode, selectedPage = selectedPage, normalTabCount = normalTabCount, + privateTabCount = privateTabCount, isInDebugMode = isInDebugMode, onTabPageIndicatorClicked = onTabPageClick, onExitSelectModeClick = { tabsTrayStore.dispatch(TabsTrayAction.ExitSelectMode) }, onSaveToCollectionClick = onSaveToCollectionClick, onShareSelectedTabsClick = onShareSelectedTabsClick, + onEnterMultiselectModeClick = { tabsTrayStore.dispatch(TabsTrayAction.EnterSelectMode) }, + onShareAllTabsClick = onShareAllTabsClick, + onTabSettingsClick = onTabSettingsClick, + onRecentlyClosedClick = onRecentlyClosedClick, + onAccountSettingsClick = onAccountSettingsClick, + onDeleteAllTabsClick = onDeleteAllTabsClick, ) } @@ -500,6 +520,11 @@ private fun TabsTrayPreviewRoot( onSyncedTabClick = {}, onSaveToCollectionClick = {}, onShareSelectedTabsClick = {}, + onShareAllTabsClick = {}, + onTabSettingsClick = {}, + onRecentlyClosedClick = {}, + onAccountSettingsClick = {}, + onDeleteAllTabsClick = {}, ) } } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayBanner.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayBanner.kt index cf38655f42..90fd51cea5 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayBanner.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayBanner.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -59,6 +60,7 @@ private val ICON_SIZE = 24.dp * @param selectMode Current [TabsTrayState.Mode] used in the tabs tray. * @param selectedPage The active [Page] of the Tabs Tray. * @param normalTabCount The total amount of normal browsing tabs currently open. + * @param privateTabCount The number of private browsing tabs currently open. * @param isInDebugMode True for debug variant or if secret menu is enabled for this session. * @param onTabPageIndicatorClicked Invoked when the user clicks on a tab page indicator. * @param onExitSelectModeClick Invoked when the user clicks on exit select mode button from the @@ -66,6 +68,12 @@ private val ICON_SIZE = 24.dp * @param onSaveToCollectionClick Invoked when the user clicks on the save to collection button from * the multi select banner. * @param onShareSelectedTabsClick Invoked when the user clicks on the share button from the multi select banner. + * @param onEnterMultiselectModeClick Invoked when the user clicks on the enter multiselect mode menu item. + * @param onShareAllTabsClick Invoked when the user clicks on the share menu item. + * @param onTabSettingsClick Invoked when the user clicks on the tab settings menu item. + * @param onRecentlyClosedClick Invoked when the user clicks on the recently closed tabs menu item. + * @param onAccountSettingsClick Invoked when the user clicks on the account settings menu item. + * @param onDeleteAllTabsClick Invoked when user interacts with the close all tabs menu item. */ @Suppress("LongParameterList") @Composable @@ -73,11 +81,18 @@ fun TabsTrayBanner( selectMode: TabsTrayState.Mode, selectedPage: Page, normalTabCount: Int, + privateTabCount: Int, isInDebugMode: Boolean, onTabPageIndicatorClicked: (Page) -> Unit, onExitSelectModeClick: () -> Unit, onSaveToCollectionClick: () -> Unit, onShareSelectedTabsClick: () -> Unit, + onEnterMultiselectModeClick: () -> Unit, + onShareAllTabsClick: () -> Unit, + onTabSettingsClick: () -> Unit, + onRecentlyClosedClick: () -> Unit, + onAccountSettingsClick: () -> Unit, + onDeleteAllTabsClick: () -> Unit, ) { if (selectMode is TabsTrayState.Mode.Select) { MultiSelectBanner( @@ -92,19 +107,34 @@ fun TabsTrayBanner( onTabPageIndicatorClicked = onTabPageIndicatorClicked, selectedPage = selectedPage, normalTabCount = normalTabCount, + privateTabCount = privateTabCount, + onEnterMultiselectModeClick = onEnterMultiselectModeClick, + onShareAllTabsClick = onShareAllTabsClick, + onTabSettingsClick = onTabSettingsClick, + onRecentlyClosedClick = onRecentlyClosedClick, + onAccountSettingsClick = onAccountSettingsClick, + onDeleteAllTabsClick = onDeleteAllTabsClick, ) } } -@Suppress("LongMethod") +@Suppress("LongMethod", "LongParameterList") @Composable private fun SingleSelectBanner( selectedPage: Page, normalTabCount: Int, + privateTabCount: Int, onTabPageIndicatorClicked: (Page) -> Unit, + onEnterMultiselectModeClick: () -> Unit, + onShareAllTabsClick: () -> Unit, + onTabSettingsClick: () -> Unit, + onRecentlyClosedClick: () -> Unit, + onAccountSettingsClick: () -> Unit, + onDeleteAllTabsClick: () -> Unit, ) { val selectedColor = FirefoxTheme.colors.iconActive val inactiveColor = FirefoxTheme.colors.iconPrimaryInactive + var showMenu by remember { mutableStateOf(false) } Column { Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.bottom_sheet_handle_top_margin))) @@ -174,9 +204,25 @@ private fun SingleSelectBanner( Spacer(modifier = Modifier.weight(1.0f)) IconButton( - onClick = {}, + onClick = { showMenu = true }, modifier = Modifier.align(Alignment.CenterVertically), ) { + DropdownMenu( + menuItems = generateSingleSelectBannerMenuItems( + selectedPage, + normalTabCount, + privateTabCount, + onTabSettingsClick, + onRecentlyClosedClick, + onEnterMultiselectModeClick, + onShareAllTabsClick, + onDeleteAllTabsClick, + onAccountSettingsClick, + ), + showMenu = showMenu, + offset = DpOffset(x = 0.dp, y = -ICON_SIZE), + onDismissRequest = { showMenu = false }, + ) Icon( painter = painterResource(R.drawable.ic_menu), contentDescription = stringResource(id = R.string.open_tabs_menu), @@ -187,6 +233,79 @@ private fun SingleSelectBanner( } } +@Suppress("LongParameterList") +@Composable +private fun generateSingleSelectBannerMenuItems( + selectedPage: Page, + normalTabCount: Int, + privateTabCount: Int, + onTabSettingsClick: () -> Unit, + onRecentlyClosedClick: () -> Unit, + onEnterMultiselectModeClick: () -> Unit, + onShareAllTabsClick: () -> Unit, + onDeleteAllTabsClick: () -> Unit, + onAccountSettingsClick: () -> Unit, +): List { + val tabSettingsItem = MenuItem( + stringResource(id = R.string.tab_tray_menu_tab_settings), + colorResource(id = R.color.fx_mobile_text_color_primary), + onTabSettingsClick, + ) + val recentlyClosedTabsItem = MenuItem( + stringResource(id = R.string.tab_tray_menu_recently_closed), + colorResource(id = R.color.fx_mobile_text_color_primary), + onRecentlyClosedClick, + ) + val enterSelectModeItem = MenuItem( + stringResource(id = R.string.tabs_tray_select_tabs), + colorResource(id = R.color.fx_mobile_text_color_primary), + onEnterMultiselectModeClick, + ) + val shareAllTabsItem = MenuItem( + stringResource(id = R.string.tab_tray_menu_item_share), + colorResource(id = R.color.fx_mobile_text_color_primary), + onShareAllTabsClick, + ) + val deleteAllTabsItem = MenuItem( + stringResource(id = R.string.tab_tray_menu_item_close), + colorResource(id = R.color.fx_mobile_text_color_primary), + onDeleteAllTabsClick, + ) + val accountSettingsItem = MenuItem( + stringResource(id = R.string.tab_tray_menu_account_settings), + colorResource(id = R.color.fx_mobile_text_color_primary), + onAccountSettingsClick, + ) + return when { + selectedPage == Page.NormalTabs && normalTabCount == 0 || + selectedPage == Page.PrivateTabs && privateTabCount == 0 -> listOf( + tabSettingsItem, + recentlyClosedTabsItem, + ) + + selectedPage == Page.NormalTabs -> listOf( + enterSelectModeItem, + shareAllTabsItem, + tabSettingsItem, + recentlyClosedTabsItem, + deleteAllTabsItem, + ) + + selectedPage == Page.PrivateTabs -> listOf( + tabSettingsItem, + recentlyClosedTabsItem, + deleteAllTabsItem, + ) + + selectedPage == Page.SyncedTabs -> listOf( + accountSettingsItem, + recentlyClosedTabsItem, + ) + + else -> emptyList() + } +} + @Composable private fun NormalTabsTabIcon(normalTabCount: Int) { val normalTabCountText: String @@ -375,6 +494,7 @@ private fun TabsTrayBannerPreviewRoot( selectMode = selectModeState, selectedPage = selectedPageState, normalTabCount = normalTabCount, + privateTabCount = 10, isInDebugMode = true, onTabPageIndicatorClicked = { page -> selectedPageState = page @@ -382,6 +502,12 @@ private fun TabsTrayBannerPreviewRoot( onExitSelectModeClick = { selectModeState = TabsTrayState.Mode.Normal }, onSaveToCollectionClick = {}, onShareSelectedTabsClick = {}, + onEnterMultiselectModeClick = {}, + onShareAllTabsClick = {}, + onTabSettingsClick = {}, + onRecentlyClosedClick = {}, + onAccountSettingsClick = {}, + onDeleteAllTabsClick = {}, ) } } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt index 9a01ae9fba..ae0da6c548 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt @@ -260,6 +260,21 @@ class TabsTrayFragment : AppCompatDialogFragment() { onSyncedTabClick = tabsTrayInteractor::onSyncedTabClicked, onSaveToCollectionClick = tabsTrayInteractor::onAddSelectedTabsToCollectionClicked, onShareSelectedTabsClick = tabsTrayInteractor::onShareSelectedTabs, + onShareAllTabsClick = { + TabsTray.shareAllTabs.record(NoExtras()) + navigationInteractor.onShareTabsOfTypeClicked( + private = tabsTrayStore.state.selectedPage == Page.PrivateTabs, + ) + }, + onTabSettingsClick = navigationInteractor::onTabSettingsClicked, + onRecentlyClosedClick = navigationInteractor::onOpenRecentlyClosedClicked, + onAccountSettingsClick = navigationInteractor::onAccountSettingsClicked, + onDeleteAllTabsClick = { + TabsTray.closeAllTabs.record(NoExtras()) + navigationInteractor.onCloseAllTabsClicked( + private = tabsTrayStore.state.selectedPage == Page.PrivateTabs, + ) + }, ) } }