You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
9.6 KiB
Kotlin
279 lines
9.6 KiB
Kotlin
/* 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.tabstray
|
|
|
|
import androidx.compose.foundation.BorderStroke
|
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.border
|
|
import androidx.compose.foundation.clickable
|
|
import androidx.compose.foundation.combinedClickable
|
|
import androidx.compose.foundation.layout.Box
|
|
import androidx.compose.foundation.layout.Column
|
|
import androidx.compose.foundation.layout.Row
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
import androidx.compose.foundation.layout.height
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.foundation.layout.requiredHeight
|
|
import androidx.compose.foundation.layout.size
|
|
import androidx.compose.foundation.layout.wrapContentHeight
|
|
import androidx.compose.foundation.layout.wrapContentWidth
|
|
import androidx.compose.foundation.shape.CircleShape
|
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
import androidx.compose.material.Card
|
|
import androidx.compose.material.Icon
|
|
import androidx.compose.material.Text
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.ui.Alignment
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.draw.clipToBounds
|
|
import androidx.compose.ui.platform.LocalConfiguration
|
|
import androidx.compose.ui.res.colorResource
|
|
import androidx.compose.ui.res.dimensionResource
|
|
import androidx.compose.ui.res.painterResource
|
|
import androidx.compose.ui.res.stringResource
|
|
import androidx.compose.ui.text.TextStyle
|
|
import androidx.compose.ui.text.style.TextDirection
|
|
import androidx.compose.ui.unit.dp
|
|
import androidx.compose.ui.unit.sp
|
|
import androidx.core.text.BidiFormatter
|
|
import mozilla.components.browser.state.state.TabSessionState
|
|
import mozilla.components.browser.state.state.createTab
|
|
import org.mozilla.fenix.R
|
|
import org.mozilla.fenix.compose.Divider
|
|
import org.mozilla.fenix.compose.Favicon
|
|
import org.mozilla.fenix.compose.HorizontalFadingEdgeBox
|
|
import org.mozilla.fenix.compose.ThumbnailCard
|
|
import org.mozilla.fenix.compose.annotation.LightDarkPreview
|
|
import org.mozilla.fenix.theme.FirefoxTheme
|
|
|
|
/**
|
|
* Tab grid item used to display a tab that supports clicks,
|
|
* long clicks, multiple selection, and media controls.
|
|
*
|
|
* @param tab The given tab to be render as view a grid item.
|
|
* @param isSelected Indicates if the item should be render as selected.
|
|
* @param multiSelectionEnabled Indicates if the item should be render with multi selection options,
|
|
* enabled.
|
|
* @param multiSelectionSelected Indicates if the item should be render as multi selection selected
|
|
* option.
|
|
* @param onCloseClick Callback to handle the click event of the close button.
|
|
* @param onMediaClick Callback to handle when the media item is clicked.
|
|
* @param onClick Callback to handle when item is clicked.
|
|
* @param onLongClick Callback to handle when item is long clicked.
|
|
*/
|
|
@OptIn(ExperimentalFoundationApi::class)
|
|
@Composable
|
|
@Suppress("MagicNumber", "LongParameterList", "LongMethod")
|
|
fun TabGridItem(
|
|
tab: TabSessionState,
|
|
isSelected: Boolean = false,
|
|
multiSelectionEnabled: Boolean = false,
|
|
multiSelectionSelected: Boolean = false,
|
|
onCloseClick: (tab: TabSessionState) -> Unit,
|
|
onMediaClick: (tab: TabSessionState) -> Unit,
|
|
onClick: (tab: TabSessionState) -> Unit,
|
|
onLongClick: (tab: TabSessionState) -> Unit,
|
|
) {
|
|
val tabBorderModifier = if (isSelected && !multiSelectionEnabled) {
|
|
Modifier.border(
|
|
4.dp,
|
|
FirefoxTheme.colors.borderAccent,
|
|
RoundedCornerShape(12.dp),
|
|
)
|
|
} else {
|
|
Modifier
|
|
}
|
|
|
|
Box(
|
|
modifier = Modifier
|
|
.wrapContentHeight()
|
|
.wrapContentWidth(),
|
|
) {
|
|
Card(
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.height(202.dp)
|
|
.padding(4.dp)
|
|
.then(tabBorderModifier)
|
|
.padding(4.dp)
|
|
.combinedClickable(
|
|
onLongClick = { onLongClick(tab) },
|
|
onClick = { onClick(tab) },
|
|
),
|
|
elevation = 0.dp,
|
|
shape = RoundedCornerShape(dimensionResource(id = R.dimen.tab_tray_grid_item_border_radius)),
|
|
border = BorderStroke(1.dp, FirefoxTheme.colors.borderPrimary),
|
|
) {
|
|
Column(
|
|
modifier = Modifier.background(FirefoxTheme.colors.layer2),
|
|
) {
|
|
Row(
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.wrapContentHeight(),
|
|
) {
|
|
Favicon(
|
|
url = tab.content.url,
|
|
size = 16.dp,
|
|
modifier = Modifier
|
|
.align(Alignment.CenterVertically)
|
|
.padding(start = 8.dp),
|
|
)
|
|
|
|
HorizontalFadingEdgeBox(
|
|
modifier = Modifier
|
|
.weight(1f)
|
|
.wrapContentHeight()
|
|
.requiredHeight(30.dp)
|
|
.padding(7.dp, 5.dp)
|
|
.clipToBounds(),
|
|
backgroundColor = FirefoxTheme.colors.layer2,
|
|
isContentRtl = BidiFormatter.getInstance().isRtl(tab.content.title),
|
|
) {
|
|
Text(
|
|
text = tab.content.title,
|
|
fontSize = 14.sp,
|
|
maxLines = 1,
|
|
softWrap = false,
|
|
style = TextStyle(
|
|
color = FirefoxTheme.colors.textPrimary,
|
|
textDirection = TextDirection.Content,
|
|
),
|
|
)
|
|
}
|
|
|
|
Icon(
|
|
painter = painterResource(id = R.drawable.mozac_ic_close),
|
|
contentDescription = stringResource(id = R.string.close_tab),
|
|
tint = FirefoxTheme.colors.iconPrimary,
|
|
modifier = Modifier
|
|
.clickable { onCloseClick(tab) }
|
|
.size(24.dp)
|
|
.align(Alignment.CenterVertically),
|
|
|
|
)
|
|
}
|
|
|
|
Divider()
|
|
|
|
Thumbnail(
|
|
tab = tab,
|
|
multiSelectionSelected = multiSelectionSelected,
|
|
)
|
|
}
|
|
}
|
|
|
|
if (!multiSelectionEnabled) {
|
|
MediaImage(
|
|
tab = tab,
|
|
onMediaIconClicked = { onMediaClick(tab) },
|
|
modifier = Modifier
|
|
.align(Alignment.TopStart),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Thumbnail specific for the [TabGridItem], which can be selected.
|
|
*
|
|
* @param tab Tab, containing the thumbnail to be displayed.
|
|
* @param multiSelectionSelected Whether or not the multiple selection is enabled.
|
|
*/
|
|
@Composable
|
|
private fun Thumbnail(
|
|
tab: TabSessionState,
|
|
multiSelectionSelected: Boolean,
|
|
) {
|
|
Box(
|
|
modifier = Modifier
|
|
.fillMaxSize()
|
|
.background(FirefoxTheme.colors.layer2),
|
|
) {
|
|
ThumbnailCard(
|
|
url = tab.content.url,
|
|
key = tab.id,
|
|
size = LocalConfiguration.current.screenWidthDp.dp,
|
|
backgroundColor = FirefoxTheme.colors.layer2,
|
|
modifier = Modifier.fillMaxSize(),
|
|
)
|
|
|
|
if (multiSelectionSelected) {
|
|
Box(
|
|
modifier = Modifier
|
|
.fillMaxSize()
|
|
.background(FirefoxTheme.colors.layerAccentNonOpaque),
|
|
)
|
|
|
|
Card(
|
|
modifier = Modifier
|
|
.size(size = 40.dp)
|
|
.align(alignment = Alignment.Center),
|
|
shape = CircleShape,
|
|
backgroundColor = FirefoxTheme.colors.layerAccent,
|
|
) {
|
|
Icon(
|
|
painter = painterResource(id = R.drawable.mozac_ic_check),
|
|
modifier = Modifier
|
|
.matchParentSize()
|
|
.padding(all = 8.dp),
|
|
contentDescription = null,
|
|
tint = colorResource(id = R.color.mozac_ui_icons_fill),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
@LightDarkPreview
|
|
private fun TabGridItemPreview() {
|
|
FirefoxTheme {
|
|
TabGridItem(
|
|
tab = createTab(
|
|
url = "www.mozilla.com",
|
|
title = "Mozilla Domain",
|
|
),
|
|
onCloseClick = {},
|
|
onMediaClick = {},
|
|
onClick = {},
|
|
onLongClick = {},
|
|
)
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
@LightDarkPreview
|
|
private fun TabGridItemSelectedPreview() {
|
|
FirefoxTheme {
|
|
TabGridItem(
|
|
tab = createTab(url = "www.mozilla.com", title = "Mozilla"),
|
|
isSelected = true,
|
|
onCloseClick = {},
|
|
onMediaClick = {},
|
|
onClick = {},
|
|
onLongClick = {},
|
|
)
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
@LightDarkPreview
|
|
private fun TabGridItemMultiSelectedPreview() {
|
|
FirefoxTheme {
|
|
TabGridItem(
|
|
tab = createTab(url = "www.mozilla.com", title = "Mozilla"),
|
|
multiSelectionEnabled = true,
|
|
multiSelectionSelected = true,
|
|
onCloseClick = {},
|
|
onMediaClick = {},
|
|
onClick = {},
|
|
onLongClick = {},
|
|
)
|
|
}
|
|
}
|