Bug 1816567 - Create a top-level DropdownMenu composable

fenix/113.0
Alexandru2909 1 year ago committed by mergify[bot]
parent e5c7f151b0
commit 701bfd97a2

@ -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<MenuItem>,
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,
{},
)
}
}

@ -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<CollectionMenuItem>,
menuItems: List<MenuItem>,
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 },

@ -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<CollectionMenuItem>,
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<CollectionMenuItem> {
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<Tab> = emptyList()
override val title: String = "Collection 1"
override fun restore(
context: Context,
engine: Engine,
restoreSessionId: Boolean,
): List<RecoverableTab> = emptyList()
override fun restoreSubset(
context: Context,
engine: Engine,
tabs: List<Tab>,
restoreSessionId: Boolean,
): List<RecoverableTab> = emptyList()
}

@ -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<MenuItem> {
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.
*

@ -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<RecentBookmarksMenuItem>,
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() {

@ -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() {

@ -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<RecentTabMenuItem>,
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.
*

@ -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<RecentVisitMenuItem>,
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.
*/

Loading…
Cancel
Save