From dd1260d5e179c558d75fa0d4fbf680b581c26110 Mon Sep 17 00:00:00 2001 From: 0nko Date: Thu, 10 Jul 2025 21:52:45 +0200 Subject: [PATCH 1/5] Remove the FABs --- .../app/tabs/ui/TabSwitcherActivity.kt | 11 ++++++-- .../app/tabs/ui/TabSwitcherViewModel.kt | 28 ++++++++----------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt index 4c937bc4efda..51470bb35b8a 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt @@ -239,7 +239,11 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine configureViewReferences() setupToolbar(toolbar) configureRecycler() - configureFabs() + + if (!viewModel.isNewDesignEnabled) { + configureFabs() + } + configureObservers() configureOnBackPressedListener() @@ -306,7 +310,10 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine tabsRecycler.setHasFixedSize(true) if (tabManagerFeatureFlags.multiSelection().isEnabled()) { - handleFabStateUpdates() + if (viewModel.isNewDesignEnabled) { + handleFabStateUpdates() + } + handleSelectionModeCancellation() } diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt index d3ca3c7a5a05..8c4a6a9c0670 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt @@ -56,7 +56,6 @@ import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode.Normal import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode.Selection import com.duckduckgo.app.trackerdetection.api.WebTrackersBlockedAppRepository -import com.duckduckgo.common.ui.experiments.visual.store.ExperimentalThemingDataStore import com.duckduckgo.common.ui.tabs.SwipingTabsFeatureProvider import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.common.utils.SingleLiveEvent @@ -101,7 +100,6 @@ class TabSwitcherViewModel @Inject constructor( private val tabSwitcherDataStore: TabSwitcherDataStore, private val faviconManager: FaviconManager, private val savedSitesRepository: SavedSitesRepository, - experimentalThemingDataStore: ExperimentalThemingDataStore, ) : ViewModel() { val activeTab = tabRepository.liveSelectedTab @@ -126,21 +124,23 @@ class TabSwitcherViewModel @Inject constructor( val tabSwitcherItemsLiveData: LiveData> = tabSwitcherItemsFlow.asLiveData() - private val _selectionViewState = MutableStateFlow(SelectionViewState()) + val isNewDesignEnabled: Boolean by lazy { + tabManagerFeatureFlags.newToolbarFeature().isEnabled() + } + + private val _selectionViewState = MutableStateFlow(SelectionViewState(isNewToolbarEnabled = isNewDesignEnabled)) val selectionViewState = combine( _selectionViewState, tabSwitcherItemsFlow, tabRepository.tabSwitcherData, - experimentalThemingDataStore.isSingleOmnibarEnabled, duckAiFeatureState.showPopupMenuShortcut, - ) { viewState, tabSwitcherItems, tabSwitcherData, isSingleOmnibarEnabled, showInBrowserMenu -> + ) { viewState, tabSwitcherItems, tabSwitcherData, showInBrowserMenu -> viewState.copy( tabSwitcherItems = tabSwitcherItems, layoutType = tabSwitcherData.layoutType, - isNewVisualDesignEnabled = isSingleOmnibarEnabled, isDuckChatEnabled = showInBrowserMenu, ) - }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SelectionViewState()) + }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SelectionViewState(isNewToolbarEnabled = isNewDesignEnabled)) val layoutType = tabRepository.tabSwitcherData .map { it.layoutType } @@ -166,10 +166,6 @@ class TabSwitcherViewModel @Inject constructor( private val selectionMode: Selection get() = requireNotNull(selectionViewState.value.mode as Selection) - val isNewDesignEnabled: Boolean by lazy { - tabManagerFeatureFlags.newToolbarFeature().isEnabled() - } - sealed class Command { data object Close : Command() data class CloseAndShowUndoMessage(val deletedTabIds: List) : Command() @@ -641,8 +637,8 @@ class TabSwitcherViewModel @Inject constructor( val tabSwitcherItems: List = emptyList(), val mode: Mode = Normal, val layoutType: LayoutType? = null, - val isNewVisualDesignEnabled: Boolean = false, val isDuckChatEnabled: Boolean = false, + val isNewToolbarEnabled: Boolean = false, ) { val tabs: List = tabSwitcherItems.filterIsInstance() val numSelectedTabs: Int = (mode as? Selection)?.selectedTabs?.size ?: 0 @@ -653,7 +649,7 @@ class TabSwitcherViewModel @Inject constructor( DynamicInterface( isFireButtonVisible = true, isNewTabVisible = true, - isDuckChatVisible = !isNewVisualDesignEnabled && isDuckChatEnabled, + isDuckChatVisible = isDuckChatEnabled, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -666,8 +662,8 @@ class TabSwitcherViewModel @Inject constructor( isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, isMoreMenuItemEnabled = !isThereOnlyNewTabPage, - isMainFabVisible = true, - isAIFabVisible = isNewVisualDesignEnabled && isDuckChatEnabled, + isMainFabVisible = !isNewToolbarEnabled, + isAIFabVisible = isDuckChatEnabled && !isNewToolbarEnabled, mainFabType = FabType.NEW_TAB, backButtonType = ARROW, layoutButtonType = when (layoutType) { @@ -700,7 +696,7 @@ class TabSwitcherViewModel @Inject constructor( isCloseAllTabsDividerVisible = isSomethingSelected, isCloseAllTabsVisible = false, isMoreMenuItemEnabled = true, - isMainFabVisible = isSomethingSelected, + isMainFabVisible = isSomethingSelected && !isNewToolbarEnabled, isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = CLOSE, From 345dc43424dd5774e38caaeaf70f8b52868a5168 Mon Sep 17 00:00:00 2001 From: 0nko Date: Thu, 10 Jul 2025 21:55:05 +0200 Subject: [PATCH 2/5] Make the single omnibar a requirement for the new design --- .../java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt index 8c4a6a9c0670..d8e15f6ab1ff 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt @@ -56,6 +56,7 @@ import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode.Normal import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode.Selection import com.duckduckgo.app.trackerdetection.api.WebTrackersBlockedAppRepository +import com.duckduckgo.common.ui.experiments.visual.store.ExperimentalThemingDataStore import com.duckduckgo.common.ui.tabs.SwipingTabsFeatureProvider import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.common.utils.SingleLiveEvent @@ -100,6 +101,7 @@ class TabSwitcherViewModel @Inject constructor( private val tabSwitcherDataStore: TabSwitcherDataStore, private val faviconManager: FaviconManager, private val savedSitesRepository: SavedSitesRepository, + experimentalThemingDataStore: ExperimentalThemingDataStore, ) : ViewModel() { val activeTab = tabRepository.liveSelectedTab @@ -125,7 +127,7 @@ class TabSwitcherViewModel @Inject constructor( val tabSwitcherItemsLiveData: LiveData> = tabSwitcherItemsFlow.asLiveData() val isNewDesignEnabled: Boolean by lazy { - tabManagerFeatureFlags.newToolbarFeature().isEnabled() + tabManagerFeatureFlags.newToolbarFeature().isEnabled() && experimentalThemingDataStore.isSingleOmnibarEnabled.value } private val _selectionViewState = MutableStateFlow(SelectionViewState(isNewToolbarEnabled = isNewDesignEnabled)) From 9444a5a14400f565dd265f66c3cfbe258d074686 Mon Sep 17 00:00:00 2001 From: 0nko Date: Fri, 11 Jul 2025 20:09:53 +0200 Subject: [PATCH 3/5] Update the tab manager menu and button items --- .../app/tabs/ui/TabSwitcherActivity.kt | 33 ++--- .../app/tabs/ui/TabSwitcherMenuExt.kt | 20 +-- .../app/tabs/ui/TabSwitcherViewModel.kt | 89 +++++++++----- app/src/main/res/layout/popup_tabs_menu.xml | 4 +- .../res/menu/menu_tab_switcher_activity.xml | 32 +---- ...u_tab_switcher_activity_with_selection.xml | 19 ++- .../app/tabs/ui/TabSwitcherViewModelTest.kt | 116 +++++++++--------- 7 files changed, 157 insertions(+), 156 deletions(-) diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt index 51470bb35b8a..bd1ecc2002ba 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt @@ -96,7 +96,6 @@ import com.duckduckgo.common.ui.view.toPx import com.duckduckgo.common.ui.viewbinding.viewBinding import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.ActivityScope -import com.duckduckgo.duckchat.api.DuckAiFeatureState import com.duckduckgo.duckchat.api.DuckChat import java.util.ArrayList import javax.inject.Inject @@ -157,9 +156,6 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine @Inject lateinit var duckChat: DuckChat - @Inject - lateinit var duckAiFeatureState: DuckAiFeatureState - @Inject lateinit var tabSwitcherAnimationFeature: TabSwitcherAnimationFeature @@ -658,7 +654,7 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine ) } else { menuInflater.inflate(R.menu.menu_tab_switcher_activity, menu) - layoutTypeMenuItem = menu.findItem(R.id.layoutTypeMenuItem) + layoutTypeMenuItem = menu.findItem(R.id.layoutTypeToolbarButton) when (viewModel.layoutType.value) { LayoutType.GRID -> showListLayoutButton() @@ -672,7 +668,7 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine private fun initMenuClickListeners() { popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.newTabMenuItem)) { onNewTabRequested(fromOverflowMenu = true) } - popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.duckChatMenuItem)) { viewModel.onDuckChatMenuClicked() } + popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.duckAIMenuItem)) { viewModel.onDuckAIMenuClicked() } popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.selectAllMenuItem)) { viewModel.onSelectAllTabs() } popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.deselectAllMenuItem)) { viewModel.onDeselectAllTabs() } popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.shareSelectedLinksMenuItem)) { viewModel.onShareSelectedTabs() } @@ -689,17 +685,11 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.layoutTypeMenuItem -> onLayoutTypeToggled() - R.id.fireMenuItem -> onFire() - R.id.popupMenuItem -> showPopupMenu(item.itemId) - R.id.newTab -> onNewTabRequested(fromOverflowMenu = false) - R.id.newTabOverflow -> onNewTabRequested(fromOverflowMenu = true) - R.id.duckChat -> { - viewModel.onDuckChatMenuClicked() - } - R.id.closeAllTabs -> closeAllTabs() - R.id.downloads -> showDownloads() - R.id.settings -> showSettings() + R.id.layoutTypeToolbarButton -> onLayoutTypeToggled() + R.id.fireToolbarButton -> onFireButtonClicked() + R.id.popupMenuToolbarButton -> showPopupMenu(item.itemId) + R.id.newTabToolbarButton -> onNewTabRequested(fromOverflowMenu = false) + R.id.duckAIToolbarButton -> viewModel.onDuckAIMenuClicked() android.R.id.home -> { viewModel.onUpButtonPressed() return true @@ -714,13 +704,6 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine viewModel.onMenuOpened() } - override fun onPrepareOptionsMenu(menu: Menu?): Boolean { - val duckChatMenuItem = menu?.findItem(R.id.duckChat) - duckChatMenuItem?.isVisible = duckAiFeatureState.showPopupMenuShortcut.value - - return super.onPrepareOptionsMenu(menu) - } - override fun onMenuOpened(featureId: Int, menu: Menu): Boolean { if (featureId == FEATURE_SUPPORT_ACTION_BAR) { viewModel.onMenuOpened() @@ -728,7 +711,7 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine return super.onMenuOpened(featureId, menu) } - private fun onFire() { + private fun onFireButtonClicked() { pixel.fire(AppPixelName.FORGET_ALL_PRESSED_TABSWITCHING) val dialog = FireDialog( context = this, diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt index cc1ca3d8a11d..1ce067a9e81c 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt @@ -27,9 +27,9 @@ import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.BackBu import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.BackButtonType.CLOSE import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.DynamicInterface import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.FabType -import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.LayoutButtonType.GRID -import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.LayoutButtonType.HIDDEN -import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.LayoutButtonType.LIST +import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.LayoutMode.GRID +import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.LayoutMode.HIDDEN +import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.LayoutMode.LIST import com.duckduckgo.mobile.android.R as commonR import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton @@ -43,8 +43,8 @@ fun Menu.createDynamicInterface( toolbar: Toolbar, dynamicMenu: DynamicInterface, ) { - popupMenu.newTabMenuItem.isVisible = dynamicMenu.isNewTabVisible - popupMenu.duckChatMenuItem.isVisible = dynamicMenu.isDuckChatVisible + popupMenu.newTabMenuItem.isVisible = dynamicMenu.isNewTabMenuVisible + popupMenu.duckAIMenuItem.isVisible = dynamicMenu.isDuckAIMenuVisible popupMenu.selectAllMenuItem.isVisible = dynamicMenu.isSelectAllVisible popupMenu.deselectAllMenuItem.isVisible = dynamicMenu.isDeselectAllVisible popupMenu.selectionActionsDivider.isVisible = dynamicMenu.isSelectionActionsDividerVisible @@ -98,8 +98,8 @@ fun Menu.createDynamicInterface( CLOSE -> AppCompatResources.getDrawable(toolbar.context, commonR.drawable.ic_close_24) } - findItem(R.id.layoutTypeMenuItem).apply { - when (dynamicMenu.layoutButtonType) { + findItem(R.id.layoutTypeToolbarButton).apply { + when (dynamicMenu.layoutButtonMode) { GRID -> { setIcon(com.duckduckgo.mobile.android.R.drawable.ic_view_grid_24) title = toolbar.resources.getString(R.string.tabSwitcherGridViewMenu) @@ -114,8 +114,10 @@ fun Menu.createDynamicInterface( } } - findItem(R.id.popupMenuItem).isEnabled = dynamicMenu.isMoreMenuItemEnabled - findItem(R.id.fireMenuItem).isVisible = dynamicMenu.isFireButtonVisible + findItem(R.id.popupMenuToolbarButton).isEnabled = dynamicMenu.isMenuButtonEnabled + findItem(R.id.fireToolbarButton).isVisible = dynamicMenu.isFireButtonVisible + findItem(R.id.duckAIToolbarButton).isVisible = dynamicMenu.isDuckAIButtonVisible + findItem(R.id.newTabToolbarButton).isVisible = dynamicMenu.isNewTabButtonVisible val bottomPadding = if (dynamicMenu.isAIFabVisible) { tabsRecycler.context.resources.getDimension(R.dimen.recyclerViewTwoFabsBottomPadding) diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt index d8e15f6ab1ff..97009a46606f 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt @@ -49,8 +49,6 @@ import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.Command.ShareLink import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.Command.ShareLinks import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.Command.ShowAnimatedTileDismissalDialog import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.Command.ShowUndoBookmarkMessage -import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.BackButtonType.ARROW -import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.BackButtonType.CLOSE import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.FabType import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode.Normal @@ -67,6 +65,7 @@ import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName import com.duckduckgo.savedsites.api.SavedSitesRepository import com.duckduckgo.savedsites.api.models.SavedSite.Bookmark import javax.inject.Inject +import kotlin.Boolean import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -140,7 +139,7 @@ class TabSwitcherViewModel @Inject constructor( viewState.copy( tabSwitcherItems = tabSwitcherItems, layoutType = tabSwitcherData.layoutType, - isDuckChatEnabled = showInBrowserMenu, + isDuckAIButtonVisible = showInBrowserMenu, ) }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SelectionViewState(isNewToolbarEnabled = isNewDesignEnabled)) @@ -171,11 +170,19 @@ class TabSwitcherViewModel @Inject constructor( sealed class Command { data object Close : Command() data class CloseAndShowUndoMessage(val deletedTabIds: List) : Command() - data class CloseTabsRequest(val tabIds: List, val isClosingOtherTabs: Boolean = false) : Command() + data class CloseTabsRequest( + val tabIds: List, + val isClosingOtherTabs: Boolean = false, + ) : Command() + data class CloseAllTabsRequest(val numTabs: Int) : Command() data object ShowAnimatedTileDismissalDialog : Command() data object DismissAnimatedTileDismissalDialog : Command() - data class ShareLink(val link: String, val title: String) : Command() + data class ShareLink( + val link: String, + val title: String, + ) : Command() + data class ShareLinks(val links: List) : Command() data class BookmarkTabsRequest(val tabIds: List) : Command() data class ShowUndoBookmarkMessage(val numBookmarks: Int) : Command() @@ -391,7 +398,10 @@ class TabSwitcherViewModel @Inject constructor( onCloseTabsConfirmed(tabs.map { it.id }) } - fun onTabCloseInNormalModeRequested(tab: Tab, swipeGestureUsed: Boolean = false) { + fun onTabCloseInNormalModeRequested( + tab: Tab, + swipeGestureUsed: Boolean = false, + ) { viewModelScope.launch { if (tabs.size == 1) { if (tabManagerFeatureFlags.multiSelection().isEnabled()) { @@ -414,7 +424,10 @@ class TabSwitcherViewModel @Inject constructor( } } - private suspend fun markTabAsDeletable(tab: Tab, swipeGestureUsed: Boolean) { + private suspend fun markTabAsDeletable( + tab: Tab, + swipeGestureUsed: Boolean, + ) { tabRepository.markDeletable(tab.tabEntity) if (swipeGestureUsed) { pixel.fire(AppPixelName.TAB_MANAGER_CLOSE_TAB_SWIPED) @@ -500,7 +513,10 @@ class TabSwitcherViewModel @Inject constructor( pixel.fire(AppPixelName.TAB_MANAGER_MENU_SETTINGS_PRESSED) } - fun onTabMoved(fromIndex: Int, toIndex: Int) { + fun onTabMoved( + fromIndex: Int, + toIndex: Int, + ) { viewModelScope.launch(dispatcherProvider.io()) { tabRepository.updateTabPosition(fromIndex, toIndex) } @@ -520,10 +536,12 @@ class TabSwitcherViewModel @Inject constructor( pixel.fire(TAB_MANAGER_LIST_VIEW_BUTTON_CLICKED) tabRepository.setTabLayoutType(LIST) } + LIST -> { pixel.fire(TAB_MANAGER_GRID_VIEW_BUTTON_CLICKED) tabRepository.setTabLayoutType(GRID) } + else -> Unit } } @@ -560,7 +578,7 @@ class TabSwitcherViewModel @Inject constructor( } } - fun onDuckChatMenuClicked() { + fun onDuckAIMenuClicked() { viewModelScope.launch { val params = duckChat.createWasUsedBeforePixelParams() pixel.fire(DuckChatPixelName.DUCK_CHAT_OPEN_NEW_TAB_MENU, parameters = params) @@ -639,7 +657,7 @@ class TabSwitcherViewModel @Inject constructor( val tabSwitcherItems: List = emptyList(), val mode: Mode = Normal, val layoutType: LayoutType? = null, - val isDuckChatEnabled: Boolean = false, + val isDuckAIButtonVisible: Boolean = false, val isNewToolbarEnabled: Boolean = false, ) { val tabs: List = tabSwitcherItems.filterIsInstance() @@ -650,8 +668,10 @@ class TabSwitcherViewModel @Inject constructor( val isThereOnlyNewTabPage = tabs.size == 1 && tabs.first().isNewTabPage DynamicInterface( isFireButtonVisible = true, - isNewTabVisible = true, - isDuckChatVisible = isDuckChatEnabled, + isNewTabButtonVisible = isNewToolbarEnabled, + isNewTabMenuVisible = !isNewToolbarEnabled, + isDuckAIButtonVisible = isDuckAIButtonVisible && isNewToolbarEnabled, + isDuckAIMenuVisible = isDuckAIButtonVisible && !isNewToolbarEnabled, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -663,15 +683,20 @@ class TabSwitcherViewModel @Inject constructor( isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, - isMoreMenuItemEnabled = !isThereOnlyNewTabPage, + isMenuButtonEnabled = !isThereOnlyNewTabPage, isMainFabVisible = !isNewToolbarEnabled, - isAIFabVisible = isDuckChatEnabled && !isNewToolbarEnabled, + isAIFabVisible = isDuckAIButtonVisible && !isNewToolbarEnabled, mainFabType = FabType.NEW_TAB, - backButtonType = ARROW, - layoutButtonType = when (layoutType) { - GRID -> LayoutButtonType.LIST - LIST -> LayoutButtonType.GRID - else -> LayoutButtonType.HIDDEN + backButtonType = BackButtonType.ARROW, + layoutButtonMode = when { + layoutType == GRID && !isNewToolbarEnabled -> LayoutMode.LIST + layoutType == LIST && !isNewToolbarEnabled -> LayoutMode.GRID + else -> LayoutMode.HIDDEN + }, + layoutMenuMode = when { + layoutType == GRID && isNewToolbarEnabled -> LayoutMode.LIST + layoutType == LIST && isNewToolbarEnabled -> LayoutMode.GRID + else -> LayoutMode.HIDDEN }, ) } @@ -684,8 +709,10 @@ class TabSwitcherViewModel @Inject constructor( val isSelectionActionable = isSomethingSelected && !isNtpTheOnlySelectedTab DynamicInterface( isFireButtonVisible = false, - isNewTabVisible = false, - isDuckChatVisible = false, + isNewTabButtonVisible = false, + isNewTabMenuVisible = false, + isDuckAIButtonVisible = false, + isDuckAIMenuVisible = false, isSelectAllVisible = !areAllTabsSelected, isDeselectAllVisible = areAllTabsSelected, isSelectionActionsDividerVisible = isSelectionActionable, @@ -697,20 +724,23 @@ class TabSwitcherViewModel @Inject constructor( isCloseOtherTabsVisible = isSomethingSelected && !areAllTabsSelected, isCloseAllTabsDividerVisible = isSomethingSelected, isCloseAllTabsVisible = false, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = isSomethingSelected && !isNewToolbarEnabled, isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, - backButtonType = CLOSE, - layoutButtonType = LayoutButtonType.HIDDEN, + backButtonType = BackButtonType.CLOSE, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) } } data class DynamicInterface( val isFireButtonVisible: Boolean, - val isNewTabVisible: Boolean, - val isDuckChatVisible: Boolean, + val isNewTabButtonVisible: Boolean, + val isNewTabMenuVisible: Boolean, + val isDuckAIButtonVisible: Boolean, + val isDuckAIMenuVisible: Boolean, val isSelectAllVisible: Boolean, val isDeselectAllVisible: Boolean, val isSelectionActionsDividerVisible: Boolean, @@ -722,12 +752,13 @@ class TabSwitcherViewModel @Inject constructor( val isCloseOtherTabsVisible: Boolean, val isCloseAllTabsDividerVisible: Boolean, val isCloseAllTabsVisible: Boolean, - val isMoreMenuItemEnabled: Boolean, + val isMenuButtonEnabled: Boolean, val isMainFabVisible: Boolean, val isAIFabVisible: Boolean, val mainFabType: FabType, val backButtonType: BackButtonType, - val layoutButtonType: LayoutButtonType, + val layoutButtonMode: LayoutMode, + val layoutMenuMode: LayoutMode, ) enum class FabType { @@ -740,7 +771,7 @@ class TabSwitcherViewModel @Inject constructor( CLOSE, } - enum class LayoutButtonType { + enum class LayoutMode { GRID, LIST, HIDDEN, diff --git a/app/src/main/res/layout/popup_tabs_menu.xml b/app/src/main/res/layout/popup_tabs_menu.xml index 90274ba41395..0e1a586106c6 100644 --- a/app/src/main/res/layout/popup_tabs_menu.xml +++ b/app/src/main/res/layout/popup_tabs_menu.xml @@ -28,7 +28,7 @@ app:primaryText="@string/newTabMenuItem" /> @@ -74,7 +74,7 @@ app:primaryText="@string/selectTabsMenuItem" /> diff --git a/app/src/main/res/menu/menu_tab_switcher_activity.xml b/app/src/main/res/menu/menu_tab_switcher_activity.xml index 929ce0d21869..1252ee770351 100644 --- a/app/src/main/res/menu/menu_tab_switcher_activity.xml +++ b/app/src/main/res/menu/menu_tab_switcher_activity.xml @@ -20,47 +20,21 @@ tools:ignore="AlwaysShowAction"> - - - - - - - - - - diff --git a/app/src/main/res/menu/menu_tab_switcher_activity_with_selection.xml b/app/src/main/res/menu/menu_tab_switcher_activity_with_selection.xml index 8f82e2f8719b..cdc1c8e31faf 100644 --- a/app/src/main/res/menu/menu_tab_switcher_activity_with_selection.xml +++ b/app/src/main/res/menu/menu_tab_switcher_activity_with_selection.xml @@ -20,20 +20,31 @@ tools:ignore="AlwaysShowAction"> + + + + diff --git a/app/src/test/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModelTest.kt b/app/src/test/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModelTest.kt index 49ede60f8df1..d991aafe657c 100644 --- a/app/src/test/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModelTest.kt +++ b/app/src/test/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModelTest.kt @@ -54,7 +54,7 @@ import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.BackButtonType import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.DynamicInterface import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.FabType -import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.LayoutButtonType +import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.LayoutMode import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode.Normal import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.SelectionViewState.Mode.Selection import com.duckduckgo.app.trackerdetection.api.WebTrackersBlockedAppRepository @@ -842,7 +842,7 @@ class TabSwitcherViewModelTest { fun `when Duck Chat menu item clicked and it wasn't used before then open Duck Chat and send a pixel`() = runTest { whenever(duckChatMock.wasOpenedBefore()).thenReturn(false) - testee.onDuckChatMenuClicked() + testee.onDuckAIMenuClicked() verify(mockPixel).fire(DuckChatPixelName.DUCK_CHAT_OPEN_NEW_TAB_MENU, mapOf("was_used_before" to "0")) verify(duckChatMock).openDuckChat() @@ -852,7 +852,7 @@ class TabSwitcherViewModelTest { fun `when Duck Chat menu item clicked and it was used before then open Duck Chat and send a pixel`() = runTest { whenever(duckChatMock.wasOpenedBefore()).thenReturn(true) - testee.onDuckChatMenuClicked() + testee.onDuckAIMenuClicked() verify(mockPixel).fire(DuckChatPixelName.DUCK_CHAT_OPEN_NEW_TAB_MENU, mapOf("was_used_before" to "1")) verify(duckChatMock).openDuckChat() @@ -880,11 +880,11 @@ class TabSwitcherViewModelTest { @Test fun whenNormalModeAndNoTabsThenVerifyDynamicInterface() { - val viewState = SelectionViewState(tabSwitcherItems = emptyList(), mode = Normal, layoutType = null, isDuckChatEnabled = true) + val viewState = SelectionViewState(tabSwitcherItems = emptyList(), mode = Normal, layoutType = null, isDuckAIButtonVisible = true) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabVisible = true, - isDuckChatVisible = true, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = true, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -896,12 +896,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -909,11 +909,11 @@ class TabSwitcherViewModelTest { @Test fun whenNormalModeAndOneNewTabPageThenVerifyDynamicInterface() { val tabItems = listOf(NormalTab(TabEntity("1"), true)) - val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Normal, layoutType = null, isDuckChatEnabled = true) + val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Normal, layoutType = null, isDuckAIButtonVisible = true) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabVisible = true, - isDuckChatVisible = true, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = true, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -925,12 +925,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, - isMoreMenuItemEnabled = false, + isMenuButtonEnabled = false, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -943,12 +943,12 @@ class TabSwitcherViewModelTest { mode = Normal, layoutType = null, isNewVisualDesignEnabled = true, - isDuckChatEnabled = true, + isDuckAIButtonVisible = true, ) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabVisible = true, - isDuckChatVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -960,12 +960,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = true, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -978,12 +978,12 @@ class TabSwitcherViewModelTest { mode = Normal, layoutType = null, isNewVisualDesignEnabled = true, - isDuckChatEnabled = false, + isDuckAIButtonVisible = false, ) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabVisible = true, - isDuckChatVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -995,12 +995,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1013,12 +1013,12 @@ class TabSwitcherViewModelTest { mode = Normal, layoutType = null, isNewVisualDesignEnabled = false, - isDuckChatEnabled = false, + isDuckAIButtonVisible = false, ) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabVisible = true, - isDuckChatVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -1030,12 +1030,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1043,11 +1043,11 @@ class TabSwitcherViewModelTest { @Test fun whenNormalModeAndMultipleTabsAndLayoutIsGridThenVerifyDynamicInterface() { val tabItems = listOf(NormalTab(TabEntity("1"), true), NormalTab(TabEntity("2"), false)) - val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Normal, layoutType = GRID, isDuckChatEnabled = true) + val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Normal, layoutType = GRID, isDuckAIButtonVisible = true) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabVisible = true, - isDuckChatVisible = true, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = true, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -1059,12 +1059,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutButtonType = LayoutButtonType.LIST, + layoutMode = LayoutMode.LIST, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1077,12 +1077,12 @@ class TabSwitcherViewModelTest { mode = Normal, layoutType = LIST, isNewVisualDesignEnabled = true, - isDuckChatEnabled = true, + isDuckAIButtonVisible = true, ) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabVisible = true, - isDuckChatVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -1094,12 +1094,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = true, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = true, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutButtonType = LayoutButtonType.GRID, + layoutMode = LayoutMode.GRID, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1113,8 +1113,8 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(emptyList()), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, - isNewTabVisible = false, - isDuckChatVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, isSelectAllVisible = true, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -1126,12 +1126,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = false, isCloseAllTabsVisible = false, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = false, isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1145,8 +1145,8 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(listOf("1")), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, - isNewTabVisible = false, - isDuckChatVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, isSelectAllVisible = true, isDeselectAllVisible = false, isSelectionActionsDividerVisible = true, @@ -1158,12 +1158,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = true, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = false, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1177,8 +1177,8 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(listOf("1")), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, - isNewTabVisible = false, - isDuckChatVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, isSelectAllVisible = true, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -1190,12 +1190,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = true, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = false, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1210,8 +1210,8 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(listOf("1", "2")), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, - isNewTabVisible = false, - isDuckChatVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, isSelectAllVisible = true, isDeselectAllVisible = false, isSelectionActionsDividerVisible = true, @@ -1223,12 +1223,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = true, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = false, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1242,8 +1242,8 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(listOf("1", "2")), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, - isNewTabVisible = false, - isDuckChatVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = true, isSelectionActionsDividerVisible = true, @@ -1255,12 +1255,12 @@ class TabSwitcherViewModelTest { isCloseOtherTabsVisible = false, isCloseAllTabsDividerVisible = true, isCloseAllTabsVisible = false, - isMoreMenuItemEnabled = true, + isMenuButtonEnabled = true, isMainFabVisible = true, isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutButtonType = LayoutButtonType.HIDDEN, + layoutMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } From ef736960fbbba27241efe650f180f481839df179 Mon Sep 17 00:00:00 2001 From: 0nko Date: Mon, 14 Jul 2025 11:00:06 +0200 Subject: [PATCH 4/5] Remove the Duck.ai menu item --- .../java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt | 5 ++--- .../java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt | 1 - .../com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt | 7 ++----- app/src/main/res/layout/popup_tabs_menu.xml | 6 ------ 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt index bd1ecc2002ba..a82a48900904 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt @@ -256,7 +256,7 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine } binding.aiChatFab.setOnClickListener { - viewModel.onDuckChatFabClicked() + viewModel.onDuckAIFabClicked() } } @@ -668,7 +668,6 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine private fun initMenuClickListeners() { popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.newTabMenuItem)) { onNewTabRequested(fromOverflowMenu = true) } - popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.duckAIMenuItem)) { viewModel.onDuckAIMenuClicked() } popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.selectAllMenuItem)) { viewModel.onSelectAllTabs() } popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.deselectAllMenuItem)) { viewModel.onDeselectAllTabs() } popupMenu.onMenuItemClicked(popupMenu.contentView.findViewById(R.id.shareSelectedLinksMenuItem)) { viewModel.onShareSelectedTabs() } @@ -689,7 +688,7 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine R.id.fireToolbarButton -> onFireButtonClicked() R.id.popupMenuToolbarButton -> showPopupMenu(item.itemId) R.id.newTabToolbarButton -> onNewTabRequested(fromOverflowMenu = false) - R.id.duckAIToolbarButton -> viewModel.onDuckAIMenuClicked() + R.id.duckAIToolbarButton -> viewModel.onDuckAIButtonClicked() android.R.id.home -> { viewModel.onUpButtonPressed() return true diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt index 1ce067a9e81c..b3844fe8075e 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherMenuExt.kt @@ -44,7 +44,6 @@ fun Menu.createDynamicInterface( dynamicMenu: DynamicInterface, ) { popupMenu.newTabMenuItem.isVisible = dynamicMenu.isNewTabMenuVisible - popupMenu.duckAIMenuItem.isVisible = dynamicMenu.isDuckAIMenuVisible popupMenu.selectAllMenuItem.isVisible = dynamicMenu.isSelectAllVisible popupMenu.deselectAllMenuItem.isVisible = dynamicMenu.isDeselectAllVisible popupMenu.selectionActionsDivider.isVisible = dynamicMenu.isSelectionActionsDividerVisible diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt index 97009a46606f..73c7cfe1b49c 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModel.kt @@ -569,7 +569,7 @@ class TabSwitcherViewModel @Inject constructor( return@withContext null } - fun onDuckChatFabClicked() { + fun onDuckAIFabClicked() { viewModelScope.launch { val params = duckChat.createWasUsedBeforePixelParams() pixel.fire(DuckChatPixelName.DUCK_CHAT_OPEN_TAB_SWITCHER_FAB, parameters = params) @@ -578,7 +578,7 @@ class TabSwitcherViewModel @Inject constructor( } } - fun onDuckAIMenuClicked() { + fun onDuckAIButtonClicked() { viewModelScope.launch { val params = duckChat.createWasUsedBeforePixelParams() pixel.fire(DuckChatPixelName.DUCK_CHAT_OPEN_NEW_TAB_MENU, parameters = params) @@ -671,7 +671,6 @@ class TabSwitcherViewModel @Inject constructor( isNewTabButtonVisible = isNewToolbarEnabled, isNewTabMenuVisible = !isNewToolbarEnabled, isDuckAIButtonVisible = isDuckAIButtonVisible && isNewToolbarEnabled, - isDuckAIMenuVisible = isDuckAIButtonVisible && !isNewToolbarEnabled, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -712,7 +711,6 @@ class TabSwitcherViewModel @Inject constructor( isNewTabButtonVisible = false, isNewTabMenuVisible = false, isDuckAIButtonVisible = false, - isDuckAIMenuVisible = false, isSelectAllVisible = !areAllTabsSelected, isDeselectAllVisible = areAllTabsSelected, isSelectionActionsDividerVisible = isSelectionActionable, @@ -740,7 +738,6 @@ class TabSwitcherViewModel @Inject constructor( val isNewTabButtonVisible: Boolean, val isNewTabMenuVisible: Boolean, val isDuckAIButtonVisible: Boolean, - val isDuckAIMenuVisible: Boolean, val isSelectAllVisible: Boolean, val isDeselectAllVisible: Boolean, val isSelectionActionsDividerVisible: Boolean, diff --git a/app/src/main/res/layout/popup_tabs_menu.xml b/app/src/main/res/layout/popup_tabs_menu.xml index 0e1a586106c6..3f47f8d4553a 100644 --- a/app/src/main/res/layout/popup_tabs_menu.xml +++ b/app/src/main/res/layout/popup_tabs_menu.xml @@ -27,12 +27,6 @@ android:layout_height="wrap_content" app:primaryText="@string/newTabMenuItem" /> - - Date: Mon, 14 Jul 2025 11:01:13 +0200 Subject: [PATCH 5/5] Update existing tests and add new onse for dynamic menu --- .../app/tabs/ui/TabSwitcherViewModelTest.kt | 542 ++++++++++++++++-- 1 file changed, 509 insertions(+), 33 deletions(-) diff --git a/app/src/test/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModelTest.kt b/app/src/test/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModelTest.kt index d991aafe657c..32ef21a9c764 100644 --- a/app/src/test/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModelTest.kt +++ b/app/src/test/java/com/duckduckgo/app/tabs/ui/TabSwitcherViewModelTest.kt @@ -189,6 +189,7 @@ class TabSwitcherViewModelTest { swipingTabsFeature.self().setRawStoredState(State(enable = false)) tabManagerFeatureFlags.multiSelection().setRawStoredState(State(enable = false)) + tabManagerFeatureFlags.newToolbarFeature().setRawStoredState(State(enable = false)) swipingTabsFeature.enabledForUsers().setRawStoredState(State(enable = true)) whenever(mockTabSwitcherPrefsDataStore.isAnimationTileDismissed()).thenReturn(flowOf(false)) @@ -842,7 +843,7 @@ class TabSwitcherViewModelTest { fun `when Duck Chat menu item clicked and it wasn't used before then open Duck Chat and send a pixel`() = runTest { whenever(duckChatMock.wasOpenedBefore()).thenReturn(false) - testee.onDuckAIMenuClicked() + testee.onDuckAIButtonClicked() verify(mockPixel).fire(DuckChatPixelName.DUCK_CHAT_OPEN_NEW_TAB_MENU, mapOf("was_used_before" to "0")) verify(duckChatMock).openDuckChat() @@ -852,7 +853,7 @@ class TabSwitcherViewModelTest { fun `when Duck Chat menu item clicked and it was used before then open Duck Chat and send a pixel`() = runTest { whenever(duckChatMock.wasOpenedBefore()).thenReturn(true) - testee.onDuckAIMenuClicked() + testee.onDuckAIButtonClicked() verify(mockPixel).fire(DuckChatPixelName.DUCK_CHAT_OPEN_NEW_TAB_MENU, mapOf("was_used_before" to "1")) verify(duckChatMock).openDuckChat() @@ -862,7 +863,7 @@ class TabSwitcherViewModelTest { fun `when Duck Chat fab clicked and it wasn't used before then open Duck Chat and send a pixel`() = runTest { whenever(duckChatMock.wasOpenedBefore()).thenReturn(false) - testee.onDuckChatFabClicked() + testee.onDuckAIFabClicked() verify(mockPixel).fire(DuckChatPixelName.DUCK_CHAT_OPEN_TAB_SWITCHER_FAB, mapOf("was_used_before" to "0")) verify(duckChatMock).openDuckChat() @@ -872,7 +873,7 @@ class TabSwitcherViewModelTest { fun `when Duck Chat fab clicked and it was used before then open Duck Chat and send a pixel`() = runTest { whenever(duckChatMock.wasOpenedBefore()).thenReturn(true) - testee.onDuckChatFabClicked() + testee.onDuckAIFabClicked() verify(mockPixel).fire(DuckChatPixelName.DUCK_CHAT_OPEN_TAB_SWITCHER_FAB, mapOf("was_used_before" to "1")) verify(duckChatMock).openDuckChat() @@ -883,8 +884,9 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = emptyList(), mode = Normal, layoutType = null, isDuckAIButtonVisible = true) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabButtonVisible = true, - isDuckAIButtonVisible = true, + isNewTabMenuVisible = true, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -898,10 +900,11 @@ class TabSwitcherViewModelTest { isCloseAllTabsVisible = true, isMenuButtonEnabled = true, isMainFabVisible = true, - isAIFabVisible = false, + isAIFabVisible = true, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -912,8 +915,9 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Normal, layoutType = null, isDuckAIButtonVisible = true) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabButtonVisible = true, - isDuckAIButtonVisible = true, + isNewTabMenuVisible = true, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -927,10 +931,11 @@ class TabSwitcherViewModelTest { isCloseAllTabsVisible = true, isMenuButtonEnabled = false, isMainFabVisible = true, - isAIFabVisible = false, + isAIFabVisible = true, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -942,12 +947,12 @@ class TabSwitcherViewModelTest { tabSwitcherItems = tabItems, mode = Normal, layoutType = null, - isNewVisualDesignEnabled = true, isDuckAIButtonVisible = true, ) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabButtonVisible = true, + isNewTabMenuVisible = true, + isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, @@ -965,7 +970,8 @@ class TabSwitcherViewModelTest { isAIFabVisible = true, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -977,12 +983,12 @@ class TabSwitcherViewModelTest { tabSwitcherItems = tabItems, mode = Normal, layoutType = null, - isNewVisualDesignEnabled = true, isDuckAIButtonVisible = false, ) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabButtonVisible = true, + isNewTabMenuVisible = true, + isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, @@ -1000,7 +1006,8 @@ class TabSwitcherViewModelTest { isAIFabVisible = false, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1012,12 +1019,12 @@ class TabSwitcherViewModelTest { tabSwitcherItems = tabItems, mode = Normal, layoutType = null, - isNewVisualDesignEnabled = false, isDuckAIButtonVisible = false, ) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabButtonVisible = true, + isNewTabMenuVisible = true, + isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, @@ -1035,7 +1042,8 @@ class TabSwitcherViewModelTest { isAIFabVisible = false, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1046,8 +1054,9 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Normal, layoutType = GRID, isDuckAIButtonVisible = true) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabButtonVisible = true, - isDuckAIButtonVisible = true, + isNewTabMenuVisible = true, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, isSelectionActionsDividerVisible = false, @@ -1061,10 +1070,11 @@ class TabSwitcherViewModelTest { isCloseAllTabsVisible = true, isMenuButtonEnabled = true, isMainFabVisible = true, - isAIFabVisible = false, + isAIFabVisible = true, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutMode = LayoutMode.LIST, + layoutButtonMode = LayoutMode.LIST, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1076,12 +1086,12 @@ class TabSwitcherViewModelTest { tabSwitcherItems = tabItems, mode = Normal, layoutType = LIST, - isNewVisualDesignEnabled = true, isDuckAIButtonVisible = true, ) val expected = DynamicInterface( isFireButtonVisible = true, - isNewTabButtonVisible = true, + isNewTabMenuVisible = true, + isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = false, isDeselectAllVisible = false, @@ -1099,7 +1109,8 @@ class TabSwitcherViewModelTest { isAIFabVisible = true, mainFabType = FabType.NEW_TAB, backButtonType = BackButtonType.ARROW, - layoutMode = LayoutMode.GRID, + layoutButtonMode = LayoutMode.GRID, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1113,6 +1124,7 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(emptyList()), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, + isNewTabMenuVisible = false, isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = true, @@ -1131,7 +1143,8 @@ class TabSwitcherViewModelTest { isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1145,6 +1158,7 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(listOf("1")), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, + isNewTabMenuVisible = false, isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = true, @@ -1163,7 +1177,8 @@ class TabSwitcherViewModelTest { isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1177,6 +1192,7 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(listOf("1")), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, + isNewTabMenuVisible = false, isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = true, @@ -1195,7 +1211,8 @@ class TabSwitcherViewModelTest { isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1210,6 +1227,7 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(listOf("1", "2")), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, + isNewTabMenuVisible = false, isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = true, @@ -1228,7 +1246,8 @@ class TabSwitcherViewModelTest { isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) } @@ -1242,6 +1261,7 @@ class TabSwitcherViewModelTest { val viewState = SelectionViewState(tabSwitcherItems = tabItems, mode = Selection(listOf("1", "2")), layoutType = null) val expected = DynamicInterface( isFireButtonVisible = false, + isNewTabMenuVisible = false, isNewTabButtonVisible = false, isDuckAIButtonVisible = false, isSelectAllVisible = false, @@ -1260,7 +1280,463 @@ class TabSwitcherViewModelTest { isAIFabVisible = false, mainFabType = FabType.CLOSE_TABS, backButtonType = BackButtonType.CLOSE, - layoutMode = LayoutMode.HIDDEN, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + // ----- + + @Test + fun whenNormalModeAndNoTabsAndNewToolbarEnabledThenVerifyDynamicInterface() { + val viewState = SelectionViewState( + tabSwitcherItems = emptyList(), + mode = Normal, + layoutType = null, + isDuckAIButtonVisible = true, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = true, + isNewTabMenuVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = true, + isSelectAllVisible = false, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = true, + isSelectTabsVisible = true, + isCloseSelectedTabsVisible = false, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = true, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.NEW_TAB, + backButtonType = BackButtonType.ARROW, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenNormalModeAndOneNewTabPageAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf(NormalTab(TabEntity("1"), true)) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Normal, + layoutType = null, + isDuckAIButtonVisible = true, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = true, + isNewTabMenuVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = true, + isSelectAllVisible = false, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = true, + isSelectTabsVisible = true, + isCloseSelectedTabsVisible = false, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = true, + isMenuButtonEnabled = false, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.NEW_TAB, + backButtonType = BackButtonType.ARROW, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenNormalModeAndMultipleTabsAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf(NormalTab(TabEntity("1"), true), NormalTab(TabEntity("2"), false)) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Normal, + layoutType = null, + isDuckAIButtonVisible = true, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = true, + isNewTabMenuVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = true, + isSelectAllVisible = false, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = true, + isSelectTabsVisible = true, + isCloseSelectedTabsVisible = false, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = true, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.NEW_TAB, + backButtonType = BackButtonType.ARROW, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenNormalModeAndNewVisualDesignEnabledAndDuckChatDisabledAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf(NormalTab(TabEntity("1"), true), NormalTab(TabEntity("2"), false)) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Normal, + layoutType = null, + isDuckAIButtonVisible = false, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = true, + isNewTabMenuVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = false, + isSelectAllVisible = false, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = true, + isSelectTabsVisible = true, + isCloseSelectedTabsVisible = false, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = true, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.NEW_TAB, + backButtonType = BackButtonType.ARROW, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenNormalModeAndNewVisualDesignDisabledAndDuckChatDisabledAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf(NormalTab(TabEntity("1"), true), NormalTab(TabEntity("2"), false)) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Normal, + layoutType = null, + isDuckAIButtonVisible = false, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = true, + isNewTabMenuVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = false, + isSelectAllVisible = false, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = true, + isSelectTabsVisible = true, + isCloseSelectedTabsVisible = false, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = true, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.NEW_TAB, + backButtonType = BackButtonType.ARROW, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenNormalModeAndMultipleTabsAndLayoutIsGridAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf(NormalTab(TabEntity("1"), true), NormalTab(TabEntity("2"), false)) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Normal, + layoutType = GRID, + isDuckAIButtonVisible = true, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = true, + isNewTabMenuVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = true, + isSelectAllVisible = false, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = true, + isSelectTabsVisible = true, + isCloseSelectedTabsVisible = false, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = true, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.NEW_TAB, + backButtonType = BackButtonType.ARROW, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.LIST, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenNormalModeAndMultipleTabsAndLayoutIsListAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf(NormalTab(TabEntity("1", "http://cnn.com"), true), NormalTab(TabEntity("2"), false)) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Normal, + layoutType = LIST, + isDuckAIButtonVisible = true, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = true, + isNewTabMenuVisible = false, + isNewTabButtonVisible = true, + isDuckAIButtonVisible = true, + isSelectAllVisible = false, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = true, + isSelectTabsVisible = true, + isCloseSelectedTabsVisible = false, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = true, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.NEW_TAB, + backButtonType = BackButtonType.ARROW, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.GRID, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenSelectionModeAndNoTabsSelectedAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf( + SelectableTab(TabEntity("1", "http://cnn.com"), false), + SelectableTab(TabEntity("2"), false), + ) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Selection(emptyList()), + layoutType = null, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = false, + isNewTabMenuVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, + isSelectAllVisible = true, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = false, + isSelectTabsVisible = false, + isCloseSelectedTabsVisible = false, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = false, + isCloseAllTabsVisible = false, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.CLOSE_TABS, + backButtonType = BackButtonType.CLOSE, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenSelectionModeAndOneTabSelectedAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf( + SelectableTab(TabEntity("1", "http://cnn.com"), true), + SelectableTab(TabEntity("2"), false), + ) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Selection(listOf("1")), + layoutType = null, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = false, + isNewTabMenuVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, + isSelectAllVisible = true, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = true, + isShareSelectedLinksVisible = true, + isBookmarkSelectedTabsVisible = true, + isSelectTabsDividerVisible = false, + isSelectTabsVisible = false, + isCloseSelectedTabsVisible = true, + isCloseOtherTabsVisible = true, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = false, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.CLOSE_TABS, + backButtonType = BackButtonType.CLOSE, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenSelectionModeAndOneNewTabPageSelectedAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf( + SelectableTab(TabEntity("1"), true), + SelectableTab(TabEntity("2", url = "cnn.com"), false), + ) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Selection(listOf("1")), + layoutType = null, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = false, + isNewTabMenuVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, + isSelectAllVisible = true, + isDeselectAllVisible = false, + isSelectionActionsDividerVisible = false, + isShareSelectedLinksVisible = false, + isBookmarkSelectedTabsVisible = false, + isSelectTabsDividerVisible = false, + isSelectTabsVisible = false, + isCloseSelectedTabsVisible = true, + isCloseOtherTabsVisible = true, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = false, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.CLOSE_TABS, + backButtonType = BackButtonType.CLOSE, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenSelectionModeAndMultipleTabsSelectedAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf( + SelectableTab(TabEntity("1", "http://cnn.com"), true), + SelectableTab(TabEntity("2"), true), + ) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Selection(listOf("1", "2")), + layoutType = null, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = false, + isNewTabMenuVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, + isSelectAllVisible = false, + isDeselectAllVisible = true, + isSelectionActionsDividerVisible = true, + isShareSelectedLinksVisible = true, + isBookmarkSelectedTabsVisible = true, + isSelectTabsDividerVisible = false, + isSelectTabsVisible = false, + isCloseSelectedTabsVisible = true, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = false, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.CLOSE_TABS, + backButtonType = BackButtonType.CLOSE, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, + ) + assertEquals(expected, viewState.dynamicInterface) + } + + @Test + fun whenSelectionModeAndAllTabsSelectedAndNewToolbarEnabledThenVerifyDynamicInterface() { + val tabItems = listOf( + SelectableTab(TabEntity("1", "http://cnn.com"), true), + SelectableTab(TabEntity("2"), true), + ) + val viewState = SelectionViewState( + tabSwitcherItems = tabItems, + mode = Selection(listOf("1", "2")), + layoutType = null, + isNewToolbarEnabled = true, + ) + val expected = DynamicInterface( + isFireButtonVisible = false, + isNewTabMenuVisible = false, + isNewTabButtonVisible = false, + isDuckAIButtonVisible = false, + isSelectAllVisible = false, + isDeselectAllVisible = true, + isSelectionActionsDividerVisible = true, + isShareSelectedLinksVisible = true, + isBookmarkSelectedTabsVisible = true, + isSelectTabsDividerVisible = false, + isSelectTabsVisible = false, + isCloseSelectedTabsVisible = true, + isCloseOtherTabsVisible = false, + isCloseAllTabsDividerVisible = true, + isCloseAllTabsVisible = false, + isMenuButtonEnabled = true, + isMainFabVisible = false, + isAIFabVisible = false, + mainFabType = FabType.CLOSE_TABS, + backButtonType = BackButtonType.CLOSE, + layoutButtonMode = LayoutMode.HIDDEN, + layoutMenuMode = LayoutMode.HIDDEN, ) assertEquals(expected, viewState.dynamicInterface) }