@@ -18,18 +18,17 @@ package com.duckduckgo.app.tabs.ui
1818
1919import android.content.Context
2020import android.content.Intent
21- import android.graphics.Color
2221import android.os.Bundle
23- import android.text.SpannableString
24- import android.text.style.ForegroundColorSpan
2522import android.view.Menu
2623import android.view.MenuItem
24+ import android.view.View
2725import android.widget.TextView
2826import androidx.activity.OnBackPressedCallback
2927import androidx.appcompat.app.AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR
3028import androidx.appcompat.content.res.AppCompatResources
3129import androidx.appcompat.widget.Toolbar
32- import androidx.core.view.MenuCompat
30+ import androidx.core.content.ContextCompat
31+ import androidx.core.view.isVisible
3332import androidx.lifecycle.Lifecycle
3433import androidx.lifecycle.flowWithLifecycle
3534import androidx.lifecycle.lifecycleScope
@@ -39,6 +38,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
3938import androidx.recyclerview.widget.RecyclerView
4039import com.duckduckgo.anvil.annotations.InjectWith
4140import com.duckduckgo.app.browser.R
41+ import com.duckduckgo.app.browser.databinding.ActivityTabSwitcherBinding
42+ import com.duckduckgo.app.browser.databinding.PopupTabsMenuBinding
4243import com.duckduckgo.app.browser.favicon.FaviconManager
4344import com.duckduckgo.app.browser.tabpreview.WebViewPreviewPersister
4445import com.duckduckgo.app.di.AppCoroutineScope
@@ -59,26 +60,28 @@ import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.Command.Close
5960import com.duckduckgo.app.tabs.ui.TabSwitcherViewModel.Command.CloseAllTabsRequest
6061import com.duckduckgo.appbuildconfig.api.AppBuildConfig
6162import com.duckduckgo.common.ui.DuckDuckGoActivity
63+ import com.duckduckgo.common.ui.menu.PopupMenu
6264import com.duckduckgo.common.ui.view.button.ButtonType.DESTRUCTIVE
6365import com.duckduckgo.common.ui.view.button.ButtonType.GHOST_ALT
6466import com.duckduckgo.common.ui.view.dialog.TextAlertDialogBuilder
6567import com.duckduckgo.common.ui.view.gone
6668import com.duckduckgo.common.ui.view.hide
6769import com.duckduckgo.common.ui.view.show
70+ import com.duckduckgo.common.ui.viewbinding.viewBinding
6871import com.duckduckgo.common.utils.DispatcherProvider
6972import com.duckduckgo.di.scopes.ActivityScope
7073import com.duckduckgo.duckchat.api.DuckChat
7174import com.duckduckgo.duckchat.impl.DuckChatPixelName
7275import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
7376import com.google.android.material.snackbar.BaseTransientBottomBar
7477import com.google.android.material.snackbar.Snackbar
75- import javax.inject.Inject
76- import kotlin.coroutines.CoroutineContext
7778import kotlinx.coroutines.CoroutineScope
7879import kotlinx.coroutines.SupervisorJob
7980import kotlinx.coroutines.flow.collectLatest
8081import kotlinx.coroutines.flow.filterNotNull
8182import kotlinx.coroutines.launch
83+ import javax.inject.Inject
84+ import kotlin.coroutines.CoroutineContext
8285
8386@InjectWith(ActivityScope ::class )
8487class TabSwitcherActivity : DuckDuckGoActivity (), TabSwitcherListener, CoroutineScope {
@@ -144,17 +147,21 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine
144147 private lateinit var toolbar: Toolbar
145148 private lateinit var tabsFab: ExtendedFloatingActionButton
146149
150+ private var popupMenuItem: MenuItem ? = null
147151 private var layoutTypeMenuItem: MenuItem ? = null
148152 private var layoutType: LayoutType ? = null
149153
154+ private val binding: ActivityTabSwitcherBinding by viewBinding()
155+ private val popupMenu by lazy {
156+ PopupMenu (layoutInflater, R .layout.popup_tabs_menu)
157+ }
158+
150159 override fun onCreate (savedInstanceState : Bundle ? ) {
151160 super .onCreate(savedInstanceState)
152- setContentView(R .layout.activity_tab_switcher )
161+ setContentView(binding.root )
153162
154163 firstTimeLoadingTabsList = savedInstanceState?.getBoolean(KEY_FIRST_TIME_LOADING ) ? : true
155164
156- tabsFab = findViewById(R .id.tabsFab)
157-
158165 extractIntentExtras()
159166 configureViewReferences()
160167 setupToolbar(toolbar)
@@ -165,6 +172,7 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine
165172 }
166173
167174 private fun configureFab () {
175+ tabsFab = binding.tabsFab
168176 if (tabManagerFeatureFlags.multiSelection().isEnabled()) {
169177 tabsFab.show()
170178 tabsFab.setOnClickListener {
@@ -377,24 +385,21 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine
377385
378386 override fun onCreateOptionsMenu (menu : Menu ): Boolean {
379387 if (tabManagerFeatureFlags.multiSelection().isEnabled()) {
388+ menuInflater.inflate(R .menu.menu_tab_switcher_activity_with_selection, menu)
389+ popupMenuItem = menu.findItem(R .id.popupMenuItem)
390+
380391 val mode = viewModel.viewState.value.mode
381392 when (mode) {
382393 TabSwitcherViewModel .ViewState .Mode .Normal -> {
383394 createNormalModeMenu(menu)
384395 }
385396 is TabSwitcherViewModel .ViewState .Mode .Selection -> {
386- if (mode.selectedTabs.isNotEmpty()) {
387- createSelectionModeMenu(menu, mode.selectedTabs.size)
388- } else {
389- createEmptySelectionModeMenu(menu)
390- }
397+ createSelectionModeMenu(menu, mode.selectedTabs.size)
391398 }
392399 }
393-
394- MenuCompat .setGroupDividerEnabled(menu, true )
395400 } else {
396401 menuInflater.inflate(R .menu.menu_tab_switcher_activity, menu)
397- layoutTypeMenuItem = menu.findItem(R .id.layoutType )
402+ layoutTypeMenuItem = menu.findItem(R .id.layoutTypeMenuItem )
398403
399404 when (layoutType) {
400405 LayoutType .GRID -> showListLayoutButton()
@@ -407,54 +412,86 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine
407412 }
408413
409414 private fun createSelectionModeMenu (menu : Menu , numSelectedTabs : Int ) {
410- menuInflater.inflate (R .menu.menu_tab_switcher_selection_mode, menu)
411- menu.findItem(R .id.shareSelectedLinks).title = resources.getQuantityString( R .plurals.shareLinksMenuItem, numSelectedTabs, numSelectedTabs)
412- menu.findItem( R .id.shareSelectedLinksIcon).title = resources.getQuantityString(
413- R .plurals.shareLinksMenuItem,
414- numSelectedTabs,
415- numSelectedTabs,
416- )
417- menu.findItem( R .id.bookmarkSelectedTabs).title = resources.getQuantityString( R .plurals.bookmarkTabsMenuItem, numSelectedTabs, numSelectedTabs)
418- menu.findItem( R .id.bookmarkSelectedTabsIcon). title = resources.getQuantityString(
419- R .plurals.bookmarkTabsMenuItem,
420- numSelectedTabs,
421- numSelectedTabs,
422- )
423- menu.findItem( R .id.closeSelectedTabs).title = resources.getQuantityString( R .plurals.closeTabsMenuItem, numSelectedTabs, numSelectedTabs )
424- menu.findItem( R .id.closeSelectedTabs).colorRed()
425- menu.findItem (R .id.closeOtherTabs).colorRed( )
426- }
415+ menu.findItem (R .id.layoutTypeMenuItem).isVisible = false
416+ menu.findItem(R .id.fireMenuItem).isVisible = false
417+
418+ menu.findItem( R .id.bookmarkMenuItem). apply {
419+ if ( numSelectedTabs == 0 ) {
420+ isEnabled = false
421+ iconTintList = ContextCompat .getColorStateList( this @TabSwitcherActivity, com.duckduckgo.mobile.android. R .color.disabledColor )
422+ }
423+ title = resources.getQuantityString(R .plurals.bookmarkTabsMenuItem, numSelectedTabs, numSelectedTabs)
424+ }
425+ menu.findItem( R .id.shareLinkMenuItem). apply {
426+ if ( numSelectedTabs == 0 ) {
427+ isEnabled = false
428+ iconTintList = ContextCompat .getColorStateList( this @TabSwitcherActivity, com.duckduckgo.mobile.android. R .color.disabledColor )
429+ }
430+ title = resources.getQuantityString (R .plurals.shareLinksMenuItem, numSelectedTabs, numSelectedTabs )
431+ }
427432
428- private fun createEmptySelectionModeMenu (menu : Menu ) {
429- menuInflater.inflate(R .menu.menu_tab_switcher_selection_mode_no_selection, menu)
430- menu.findItem(R .id.closeAllTabs).colorRed()
433+ val popupBinding = PopupTabsMenuBinding .bind(popupMenu.contentView)
434+
435+ popupBinding.newTabMenuItem.isVisible = false
436+ popupBinding.selectAllMenuItem.isVisible = true
437+ popupBinding.selectionActionsDivider.isVisible = numSelectedTabs > 0
438+ popupBinding.shareSelectedLinksMenuItem.isVisible = numSelectedTabs > 0
439+ popupBinding.bookmarkSelectedTabsMenuItem.isVisible = numSelectedTabs > 0
440+ popupBinding.selectTabsDivider.isVisible = false
441+ popupBinding.selectTabsMenuItem.isVisible = false
442+ popupBinding.closeOtherTabsMenuItem.isVisible = numSelectedTabs > 0
443+ popupBinding.closeSelectedTabsMenuItem.isVisible = numSelectedTabs > 0
444+ popupBinding.closeAllTabsMenuItem.isVisible = numSelectedTabs == 0
445+
446+ popupBinding.shareSelectedLinksMenuItem.apply {
447+ setPrimaryText(resources.getQuantityString(R .plurals.shareLinksMenuItem, numSelectedTabs, numSelectedTabs))
448+ }
449+ popupBinding.bookmarkSelectedTabsMenuItem.apply {
450+ setPrimaryText(resources.getQuantityString(R .plurals.bookmarkTabsMenuItem, numSelectedTabs, numSelectedTabs))
451+ }
452+ popupBinding.closeSelectedTabsMenuItem.apply {
453+ setPrimaryText(resources.getQuantityString(R .plurals.closeTabsMenuItem, numSelectedTabs, numSelectedTabs))
454+ }
431455 }
432456
433457 private fun createNormalModeMenu (menu : Menu ) {
434- menuInflater.inflate(R .menu.menu_tab_switcher_normal_mode, menu)
435- layoutTypeMenuItem = menu.findItem(R .id.layoutType)
458+ layoutTypeMenuItem = menu.findItem(R .id.layoutTypeMenuItem)
436459
437460 when (layoutType) {
438461 LayoutType .GRID -> showListLayoutButton()
439462 LayoutType .LIST -> showGridLayoutButton()
440463 null -> layoutTypeMenuItem?.isVisible = false
441464 }
442465
443- menu.findItem(R .id.shareSelectedLinks).title = resources.getQuantityString( R .plurals.shareLinksMenuItem, 1 )
444- menu.findItem(R .id.bookmarkSelectedTabs).title = resources.getQuantityString( R .plurals.bookmarkTabsMenuItem, 1 )
445- menu.findItem( R .id.closeAllTabs).colorRed()
446- }
466+ menu.findItem(R .id.bookmarkMenuItem).isVisible = false
467+ menu.findItem(R .id.shareLinkMenuItem).isVisible = false
468+
469+ val popupBinding = PopupTabsMenuBinding .bind(popupMenu.contentView)
447470
448- private fun MenuItem.colorRed () {
449- val text = SpannableString (title)
450- text.setSpan(ForegroundColorSpan (Color .RED ), 0 , text.length, 0 )
451- title = text
471+ popupBinding.newTabMenuItem.isVisible = true
472+ popupBinding.selectAllMenuItem.isVisible = false
473+ popupBinding.selectionActionsDivider.isVisible = true
474+ popupBinding.shareSelectedLinksMenuItem.isVisible = true
475+ popupBinding.bookmarkSelectedTabsMenuItem.isVisible = true
476+ popupBinding.selectTabsDivider.isVisible = true
477+ popupBinding.selectTabsMenuItem.isVisible = true
478+ popupBinding.closeSelectedTabsMenuItem.isVisible = false
479+ popupBinding.closeOtherTabsMenuItem.isVisible = false
480+ popupBinding.closeAllTabsMenuItem.isVisible = true
481+
482+ popupBinding.shareSelectedLinksMenuItem.apply {
483+ setPrimaryText(resources.getQuantityString(R .plurals.shareLinksMenuItem, 1 ))
484+ }
485+ popupBinding.bookmarkSelectedTabsMenuItem.apply {
486+ setPrimaryText(resources.getQuantityString(R .plurals.bookmarkTabsMenuItem, 1 ))
487+ }
452488 }
453489
454490 override fun onOptionsItemSelected (item : MenuItem ): Boolean {
455491 when (item.itemId) {
456- R .id.layoutType -> onLayoutTypeToggled()
457- R .id.fire -> onFire()
492+ R .id.layoutTypeMenuItem -> onLayoutTypeToggled()
493+ R .id.fireMenuItem -> onFire()
494+ R .id.popupMenuItem -> showPopupMenu(item.itemId)
458495 R .id.newTab -> onNewTabRequested(fromOverflowMenu = false )
459496 R .id.newTabOverflow -> onNewTabRequested(fromOverflowMenu = true )
460497 R .id.duckChat -> {
@@ -473,6 +510,11 @@ class TabSwitcherActivity : DuckDuckGoActivity(), TabSwitcherListener, Coroutine
473510 return super .onOptionsItemSelected(item)
474511 }
475512
513+ private fun showPopupMenu (itemId : Int ) {
514+ val anchorView = findViewById<View >(itemId)
515+ popupMenu.show(binding.root, anchorView)
516+ }
517+
476518 override fun onPrepareOptionsMenu (menu : Menu ? ): Boolean {
477519 val closeAllTabsMenuItem = menu?.findItem(R .id.closeAllTabs)
478520 closeAllTabsMenuItem?.isVisible = viewModel.tabSwitcherItems.value?.isNotEmpty() == true
0 commit comments