From 701bfd97a201a9cf79c7c302497f702b19d5a588 Mon Sep 17 00:00:00 2001 From: Alexandru2909 Date: Thu, 30 Mar 2023 15:04:20 +0300 Subject: [PATCH] Bug 1816567 - Create a top-level DropdownMenu composable --- .../org/mozilla/fenix/compose/DropdownMenu.kt | 100 +++++++++ .../fenix/home/collections/Collection.kt | 8 +- .../fenix/home/collections/CollectionMenu.kt | 210 ------------------ .../home/collections/CollectionViewHolder.kt | 58 +++++ .../recentbookmarks/view/RecentBookmarks.kt | 62 +----- .../recentsyncedtabs/view/RecentSyncedTab.kt | 59 +---- .../fenix/home/recenttabs/view/RecentTabs.kt | 68 +----- .../home/recentvisits/view/RecentlyVisited.kt | 78 ++----- 8 files changed, 204 insertions(+), 439 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/compose/DropdownMenu.kt delete mode 100644 app/src/main/java/org/mozilla/fenix/home/collections/CollectionMenu.kt diff --git a/app/src/main/java/org/mozilla/fenix/compose/DropdownMenu.kt b/app/src/main/java/org/mozilla/fenix/compose/DropdownMenu.kt new file mode 100644 index 0000000000..171f138925 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/compose/DropdownMenu.kt @@ -0,0 +1,100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.compose + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.unit.dp +import org.mozilla.fenix.compose.annotation.LightDarkPreview +import org.mozilla.fenix.theme.FirefoxTheme + +/** + * Popup action dropdown menu. + * + * @param menuItems List of items to be displayed in the menu. + * @param showMenu Whether or not the menu is currently displayed to the user. + * @param onDismissRequest Invoked when user dismisses the menu or on orientation changes. + * @param modifier Modifier to be applied to the menu. + */ +@Composable +fun DropdownMenu( + menuItems: List, + showMenu: Boolean, + onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, +) { + DisposableEffect(LocalConfiguration.current.orientation) { + onDispose { onDismissRequest() } + } + + MaterialTheme(shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(2.dp))) { + DropdownMenu( + expanded = showMenu && menuItems.isNotEmpty(), + onDismissRequest = { onDismissRequest() }, + modifier = Modifier + .background(color = FirefoxTheme.colors.layer2) + .then(modifier), + ) { + for (item in menuItems) { + DropdownMenuItem( + onClick = { + onDismissRequest() + item.onClick() + }, + ) { + Text( + text = item.title, + color = item.color ?: FirefoxTheme.colors.textPrimary, + maxLines = 1, + style = FirefoxTheme.typography.subtitle1, + modifier = Modifier + .fillMaxHeight() + .align(Alignment.CenterVertically), + ) + } + } + } + } +} + +/** + * Represents a text item from the dropdown menu. + * + * @property title Text the item should display. + * @property color Color used to display the text. + * @property onClick Callback to be called when the item is clicked. + */ +data class MenuItem( + val title: String, + val color: Color? = null, + val onClick: () -> Unit, +) + +@LightDarkPreview +@Composable +private fun DropdownMenuPreview() { + FirefoxTheme { + DropdownMenu( + listOf( + MenuItem("Rename") {}, + MenuItem("Share") {}, + MenuItem("Remove", FirefoxTheme.colors.textWarning) {}, + ), + true, + {}, + ) + } +} diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt b/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt index 89ecc645cd..955fe76e8f 100644 --- a/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt +++ b/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt @@ -38,6 +38,8 @@ import mozilla.components.feature.tab.collections.TabCollection import org.mozilla.fenix.R import org.mozilla.fenix.R.drawable import org.mozilla.fenix.R.string +import org.mozilla.fenix.compose.DropdownMenu +import org.mozilla.fenix.compose.MenuItem import org.mozilla.fenix.compose.list.ExpandableListHeader import org.mozilla.fenix.ext.getIconColor import org.mozilla.fenix.theme.FirefoxTheme @@ -59,7 +61,7 @@ private val expandedCollectionShape = RoundedCornerShape(topStart = 8.dp, topEnd * * @param collection [TabCollection] to display. * @param expanded Whether the collection is expanded to show it's containing tabs or not. - * @param menuItems List of [CollectionMenuItem] to be shown in a menu. + * @param menuItems List of [MenuItem] to be shown in a menu. * @param onToggleCollectionExpanded Invoked when the user clicks on the collection. * @param onCollectionShareTabsClicked Invoked when the user clicks to share the collection. */ @@ -68,7 +70,7 @@ private val expandedCollectionShape = RoundedCornerShape(topStart = 8.dp, topEnd fun Collection( collection: TabCollection, expanded: Boolean, - menuItems: List, + menuItems: List, onToggleCollectionExpanded: (TabCollection, Boolean) -> Unit, onCollectionShareTabsClicked: (TabCollection) -> Unit, ) { @@ -139,7 +141,7 @@ fun Collection( tint = FirefoxTheme.colors.iconPrimary, ) - CollectionMenu( + DropdownMenu( showMenu = isMenuExpanded, menuItems = menuItems, onDismissRequest = { isMenuExpanded = false }, diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/CollectionMenu.kt b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionMenu.kt deleted file mode 100644 index 8ef3258111..0000000000 --- a/app/src/main/java/org/mozilla/fenix/home/collections/CollectionMenu.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.fenix.home.collections - -import android.content.Context -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.DropdownMenu -import androidx.compose.material.DropdownMenuItem -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.Immutable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import mozilla.components.browser.state.selector.normalTabs -import mozilla.components.browser.state.state.recover.RecoverableTab -import mozilla.components.concept.engine.Engine -import mozilla.components.feature.tab.collections.Tab -import mozilla.components.feature.tab.collections.TabCollection -import org.mozilla.fenix.R.string -import org.mozilla.fenix.compose.inComposePreview -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.theme.FirefoxTheme -import org.mozilla.fenix.theme.Theme - -/** - * Menu shown for a [org.mozilla.fenix.home.collections.Collection]. - * - * @see [DropdownMenu] - * - * @param showMenu Whether this is currently open and visible to the user. - * @param menuItems List of options shown. - * @param onDismissRequest Called when the user chooses a menu option or requests to dismiss the menu. - */ -@Composable -fun CollectionMenu( - showMenu: Boolean, - menuItems: List, - onDismissRequest: () -> Unit, -) { - DisposableEffect(LocalConfiguration.current.orientation) { - onDispose { onDismissRequest() } - } - - // DropdownMenu uses the medium shape from MaterialTheme. - // Override it's corner radius to be the same 8.dp as in mozac_browser_menu_corner_radius - MaterialTheme(shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(8.dp))) { - DropdownMenu( - expanded = showMenu, - onDismissRequest = { onDismissRequest() }, - modifier = Modifier - .background(color = FirefoxTheme.colors.layer2), - ) { - for (item in menuItems) { - DropdownMenuItem( - onClick = { - onDismissRequest() - item.onClick() - }, - ) { - Text( - text = item.title, - color = item.color, - maxLines = 1, - modifier = Modifier - .fillMaxHeight() - .align(Alignment.CenterVertically), - ) - } - } - } - } -} - -/** - * A menu item for collections. - * - * @property title The menu item title. - * @property color The color that should be set for the title. - * @property onClick Invoked when the user clicks on the menu item. - */ -@Immutable -data class CollectionMenuItem( - val title: String, - val color: Color, - val onClick: () -> Unit, -) - -/** - * Constructs and returns the default list of menu options for a [TabCollection]. - * - * @param collection [TabCollection] for which the menu will be shown. - * Might serve as an argument for the callbacks for when the user interacts with certain menu options. - * @param onOpenTabsTapped Invoked when the user chooses to open the tabs from [collection]. - * @param onRenameCollectionTapped Invoked when the user chooses to rename the [collection]. - * @param onAddTabTapped Invoked when the user chooses to add tabs to [collection]. - * @param onDeleteCollectionTapped Invoked when the user chooses to delete [collection]. - */ -@Composable -fun getMenuItems( - collection: TabCollection, - onOpenTabsTapped: (TabCollection) -> Unit, - onRenameCollectionTapped: (TabCollection) -> Unit, - onAddTabTapped: (TabCollection) -> Unit, - onDeleteCollectionTapped: (TabCollection) -> Unit, -): List { - return listOfNotNull( - CollectionMenuItem( - title = stringResource(string.collection_open_tabs), - color = FirefoxTheme.colors.textPrimary, - ) { - onOpenTabsTapped(collection) - }, - CollectionMenuItem( - title = stringResource(string.collection_rename), - color = FirefoxTheme.colors.textPrimary, - ) { - onRenameCollectionTapped(collection) - }, - - if (hasOpenTabs()) { - CollectionMenuItem( - title = stringResource(string.add_tab), - color = FirefoxTheme.colors.textPrimary, - ) { - onAddTabTapped(collection) - } - } else { - null - }, - - CollectionMenuItem( - title = stringResource(string.collection_delete), - color = FirefoxTheme.colors.textWarning, - ) { - onDeleteCollectionTapped(collection) - }, - ) -} - -@Composable -private fun hasOpenTabs() = when (inComposePreview) { - true -> true - false -> LocalContext.current.components.core.store.state.normalTabs.isNotEmpty() -} - -@Composable -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -private fun CollectionMenuDarkPreview() { - FirefoxTheme(Theme.Dark) { - CollectionMenu( - showMenu = true, - menuItems = getMenuItems( - collection = collectionPreview, - onOpenTabsTapped = {}, - onRenameCollectionTapped = {}, - onAddTabTapped = {}, - onDeleteCollectionTapped = {}, - ), - ) {} - } -} - -@Composable -@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) -private fun CollectionMenuLightPreview() { - FirefoxTheme(Theme.Light) { - CollectionMenu( - showMenu = true, - menuItems = getMenuItems( - collection = collectionPreview, - onOpenTabsTapped = {}, - onRenameCollectionTapped = {}, - onAddTabTapped = {}, - onDeleteCollectionTapped = {}, - ), - ) {} - } -} - -private val collectionPreview = object : TabCollection { - override val id: Long = 1L - override val tabs: List = emptyList() - override val title: String = "Collection 1" - - override fun restore( - context: Context, - engine: Engine, - restoreSessionId: Boolean, - ): List = emptyList() - - override fun restoreSubset( - context: Context, - engine: Engine, - tabs: List, - restoreSessionId: Boolean, - ): List = emptyList() -} diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/CollectionViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionViewHolder.kt index 4dafd56ebd..cd70ec0612 100644 --- a/app/src/main/java/org/mozilla/fenix/home/collections/CollectionViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionViewHolder.kt @@ -15,13 +15,19 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView +import mozilla.components.browser.state.selector.normalTabs import mozilla.components.feature.tab.collections.TabCollection import org.mozilla.fenix.R import org.mozilla.fenix.compose.ComposeViewHolder +import org.mozilla.fenix.compose.MenuItem +import org.mozilla.fenix.ext.components import org.mozilla.fenix.home.sessioncontrol.CollectionInteractor +import org.mozilla.fenix.theme.FirefoxTheme /** * [RecyclerView.ViewHolder] for displaying an individual [TabCollection]. @@ -90,6 +96,58 @@ class CollectionViewHolder( } } +/** + * Constructs and returns the default list of menu options for a [TabCollection]. + * + * @param collection [TabCollection] for which the menu will be shown. + * Might serve as an argument for the callbacks for when the user interacts with certain menu options. + * @param onOpenTabsTapped Invoked when the user chooses to open the tabs from [collection]. + * @param onRenameCollectionTapped Invoked when the user chooses to rename the [collection]. + * @param onAddTabTapped Invoked when the user chooses to add tabs to [collection]. + * @param onDeleteCollectionTapped Invoked when the user chooses to delete [collection]. + */ +@Composable +private fun getMenuItems( + collection: TabCollection, + onOpenTabsTapped: (TabCollection) -> Unit, + onRenameCollectionTapped: (TabCollection) -> Unit, + onAddTabTapped: (TabCollection) -> Unit, + onDeleteCollectionTapped: (TabCollection) -> Unit, +): List { + return listOfNotNull( + MenuItem( + title = stringResource(R.string.collection_open_tabs), + color = FirefoxTheme.colors.textPrimary, + ) { + onOpenTabsTapped(collection) + }, + MenuItem( + title = stringResource(R.string.collection_rename), + color = FirefoxTheme.colors.textPrimary, + ) { + onRenameCollectionTapped(collection) + }, + + if (LocalContext.current.components.core.store.state.normalTabs.isNotEmpty()) { + MenuItem( + title = stringResource(R.string.add_tab), + color = FirefoxTheme.colors.textPrimary, + ) { + onAddTabTapped(collection) + } + } else { + null + }, + + MenuItem( + title = stringResource(R.string.collection_delete), + color = FirefoxTheme.colors.textWarning, + ) { + onDeleteCollectionTapped(collection) + }, + ) +} + /** * Wrapper over a [TabCollection] adding information about whether it should be shown as expanded or collapsed. * diff --git a/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarks.kt b/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarks.kt index ac13dcd8b1..d970c8ff6b 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarks.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarks.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -24,8 +23,6 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card -import androidx.compose.material.DropdownMenu -import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -48,7 +45,9 @@ import mozilla.components.browser.icons.compose.Placeholder import mozilla.components.browser.icons.compose.WithIcon import mozilla.components.ui.colors.PhotonColors import org.mozilla.fenix.components.components +import org.mozilla.fenix.compose.DropdownMenu import org.mozilla.fenix.compose.Image +import org.mozilla.fenix.compose.MenuItem import org.mozilla.fenix.compose.annotation.LightDarkPreview import org.mozilla.fenix.compose.inComposePreview import org.mozilla.fenix.home.recentbookmarks.RecentBookmark @@ -151,11 +150,14 @@ private fun RecentBookmarkItem( style = FirefoxTheme.typography.caption, ) - RecentBookmarksMenu( + DropdownMenu( showMenu = isMenuExpanded, - menuItems = menuItems, - recentBookmark = bookmark, onDismissRequest = { isMenuExpanded = false }, + menuItems = menuItems.map { item -> MenuItem(item.title) { item.onClick(bookmark) } }, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.bookmark.menu" + }, ) } } @@ -218,54 +220,6 @@ private fun PlaceholderBookmarkImage() { ) } -/** - * Menu shown for a [RecentBookmark]. - * - * @see [DropdownMenu] - * - * @param showMenu Whether this is currently open and visible to the user. - * @param menuItems List of options shown. - * @param recentBookmark The [RecentBookmark] for which this menu is shown. - * @param onDismissRequest Called when the user chooses a menu option or requests to dismiss the menu. - */ -@OptIn(ExperimentalComposeUiApi::class) -@Composable -private fun RecentBookmarksMenu( - showMenu: Boolean, - menuItems: List, - recentBookmark: RecentBookmark, - onDismissRequest: () -> Unit, -) { - DropdownMenu( - expanded = showMenu, - onDismissRequest = { onDismissRequest() }, - modifier = Modifier - .background(color = FirefoxTheme.colors.layer2) - .semantics { - testTagsAsResourceId = true - testTag = "recent.bookmark.menu" - }, - ) { - for (item in menuItems) { - DropdownMenuItem( - onClick = { - onDismissRequest() - item.onClick(recentBookmark) - }, - ) { - Text( - text = item.title, - color = FirefoxTheme.colors.textPrimary, - maxLines = 1, - modifier = Modifier - .fillMaxHeight() - .align(Alignment.CenterVertically), - ) - } - } - } -} - @Composable @LightDarkPreview private fun RecentBookmarksPreview() { diff --git a/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTab.kt b/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTab.kt index 5ebf823cdc..ad5b8bba6e 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTab.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTab.kt @@ -22,11 +22,8 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card -import androidx.compose.material.DropdownMenu -import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -36,7 +33,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -46,11 +42,12 @@ import androidx.compose.ui.unit.sp import mozilla.components.concept.sync.DeviceType import mozilla.components.support.ktx.kotlin.trimmed import org.mozilla.fenix.R +import org.mozilla.fenix.compose.DropdownMenu import org.mozilla.fenix.compose.Image +import org.mozilla.fenix.compose.MenuItem import org.mozilla.fenix.compose.ThumbnailCard import org.mozilla.fenix.compose.button.SecondaryButton import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab -import org.mozilla.fenix.home.recenttabs.RecentTab import org.mozilla.fenix.theme.FirefoxTheme /** @@ -185,7 +182,15 @@ fun RecentSyncedTab( } } - SyncedTabDropdown(isDropdownExpanded, tab, ::removeSyncedTab) { isDropdownExpanded = false } + DropdownMenu( + showMenu = isDropdownExpanded && tab != null, + onDismissRequest = { isDropdownExpanded = false }, + menuItems = listOf( + MenuItem(stringResource(id = R.string.recent_synced_tab_menu_item_remove)) { + tab?.let { removeSyncedTab(it) } + }, + ), + ) } /** @@ -228,48 +233,6 @@ private fun TextLinePlaceHolder() { ) } -/** - * Long click dropdown menu shown for a [RecentSyncedTab]. - * - * @param showMenu Whether this is currently open and visible to the user. - * @param tab The [RecentTab.Tab] for which this menu is shown. - * @param onRemove Called when the user interacts with the `Remove` option. - * @param onDismiss Called when the user chooses a menu option or requests to dismiss the menu. - */ -@Composable -private fun SyncedTabDropdown( - showMenu: Boolean, - tab: RecentSyncedTab?, - onRemove: (RecentSyncedTab) -> Unit, - onDismiss: () -> Unit, -) { - DisposableEffect(LocalConfiguration.current.orientation) { - onDispose { onDismiss() } - } - - DropdownMenu( - expanded = showMenu && tab != null, - onDismissRequest = { onDismiss() }, - modifier = Modifier - .background(color = FirefoxTheme.colors.layer2), - ) { - DropdownMenuItem( - onClick = { - tab?.let { onRemove(it) } - }, - ) { - Text( - text = stringResource(id = R.string.recent_synced_tab_menu_item_remove), - color = FirefoxTheme.colors.textPrimary, - maxLines = 1, - modifier = Modifier - .fillMaxHeight() - .align(Alignment.CenterVertically), - ) - } - } -} - @Preview @Composable private fun LoadedRecentSyncedTab() { diff --git a/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabs.kt b/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabs.kt index c3b769720b..90914217e7 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabs.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabs.kt @@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -26,11 +25,8 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card -import androidx.compose.material.DropdownMenu -import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -43,7 +39,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTag import androidx.compose.ui.semantics.testTagsAsResourceId @@ -58,7 +53,9 @@ import mozilla.components.browser.state.state.TabSessionState import mozilla.components.support.ktx.kotlin.trimmed import mozilla.components.ui.colors.PhotonColors import org.mozilla.fenix.components.components +import org.mozilla.fenix.compose.DropdownMenu import org.mozilla.fenix.compose.Image +import org.mozilla.fenix.compose.MenuItem import org.mozilla.fenix.compose.ThumbnailCard import org.mozilla.fenix.compose.annotation.LightDarkPreview import org.mozilla.fenix.compose.inComposePreview @@ -194,11 +191,14 @@ private fun RecentTabItem( } } - RecentTabMenu( + DropdownMenu( showMenu = isMenuExpanded, - menuItems = menuItems, - tab = tab, onDismissRequest = { isMenuExpanded = false }, + menuItems = menuItems.map { item -> MenuItem(item.title) { item.onClick(tab) } }, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.tab.menu" + }, ) } } @@ -237,58 +237,6 @@ fun RecentTabImage( } } -/** - * Menu shown for a [RecentTab.Tab]. - * - * @see [DropdownMenu] - * - * @param showMenu Whether this is currently open and visible to the user. - * @param menuItems List of options shown. - * @param tab The [RecentTab.Tab] for which this menu is shown. - * @param onDismissRequest Called when the user chooses a menu option or requests to dismiss the menu. - */ -@OptIn(ExperimentalComposeUiApi::class) -@Composable -private fun RecentTabMenu( - showMenu: Boolean, - menuItems: List, - tab: RecentTab.Tab, - onDismissRequest: () -> Unit, -) { - DisposableEffect(LocalConfiguration.current.orientation) { - onDispose { onDismissRequest() } - } - - DropdownMenu( - expanded = showMenu, - onDismissRequest = { onDismissRequest() }, - modifier = Modifier - .background(color = FirefoxTheme.colors.layer2) - .semantics { - testTagsAsResourceId = true - testTag = "recent.tab.menu" - }, - ) { - for (item in menuItems) { - DropdownMenuItem( - onClick = { - onDismissRequest() - item.onClick(tab) - }, - ) { - Text( - text = item.title, - color = FirefoxTheme.colors.textPrimary, - maxLines = 1, - modifier = Modifier - .fillMaxHeight() - .align(Alignment.CenterVertically), - ) - } - } - } -} - /** * A recent tab icon. * diff --git a/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisited.kt b/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisited.kt index eeba4069f7..c358cfcf0d 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisited.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisited.kt @@ -6,7 +6,6 @@ package org.mozilla.fenix.home.recentvisits.view import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement @@ -15,7 +14,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -27,11 +25,8 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card -import androidx.compose.material.DropdownMenu -import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -40,7 +35,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.semantics @@ -53,8 +47,10 @@ import androidx.compose.ui.unit.sp import mozilla.components.support.ktx.kotlin.trimmed import org.mozilla.fenix.R import org.mozilla.fenix.compose.Divider +import org.mozilla.fenix.compose.DropdownMenu import org.mozilla.fenix.compose.EagerFlingBehavior import org.mozilla.fenix.compose.Favicon +import org.mozilla.fenix.compose.MenuItem import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem.RecentHistoryGroup import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem.RecentHistoryHighlight @@ -206,11 +202,14 @@ private fun RecentlyVisitedHistoryGroup( } } - RecentlyVisitedMenu( + DropdownMenu( showMenu = isMenuExpanded, - menuItems = menuItems, - recentVisit = recentVisit, onDismissRequest = { isMenuExpanded = false }, + menuItems = menuItems.map { MenuItem(it.title) { it.onClick(recentVisit) } }, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.visit.menu" + }, ) } } @@ -272,11 +271,14 @@ private fun RecentlyVisitedHistoryHighlight( } } - RecentlyVisitedMenu( + DropdownMenu( showMenu = isMenuExpanded, - menuItems = menuItems, - recentVisit = recentVisit, onDismissRequest = { isMenuExpanded = false }, + menuItems = menuItems.map { item -> MenuItem(item.title) { item.onClick(recentVisit) } }, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.visit.menu" + }, ) } } @@ -332,58 +334,6 @@ private fun RecentlyVisitedCaption( ) } -/** - * Menu shown for a [RecentlyVisitedItem]. - * - * @see [DropdownMenu] - * - * @param showMenu Whether this is currently open and visible to the user. - * @param menuItems List of options shown. - * @param recentVisit The [RecentlyVisitedItem] for which this menu is shown. - * @param onDismissRequest Called when the user chooses a menu option or requests to dismiss the menu. - */ -@OptIn(ExperimentalComposeUiApi::class) -@Composable -private fun RecentlyVisitedMenu( - showMenu: Boolean, - menuItems: List, - recentVisit: RecentlyVisitedItem, - onDismissRequest: () -> Unit, -) { - DisposableEffect(LocalConfiguration.current.orientation) { - onDispose { onDismissRequest() } - } - - DropdownMenu( - expanded = showMenu, - onDismissRequest = { onDismissRequest() }, - modifier = Modifier - .background(color = FirefoxTheme.colors.layer2) - .semantics { - testTagsAsResourceId = true - testTag = "recent.visit.menu" - }, - ) { - for (item in menuItems) { - DropdownMenuItem( - onClick = { - onDismissRequest() - item.onClick(recentVisit) - }, - ) { - Text( - text = item.title, - color = FirefoxTheme.colors.textPrimary, - maxLines = 1, - modifier = Modifier - .fillMaxHeight() - .align(Alignment.CenterVertically), - ) - } - } - } -} - /** * Get the indexes in list of all items which have more than half showing. */