Bug 1844967 - Improve performance of tab thumbnail loading in Compose

fenix/118.0
Noah Bond 11 months ago committed by mergify[bot]
parent a314d38140
commit fa9c47d5fa

@ -16,14 +16,15 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import mozilla.components.concept.base.images.ImageLoadRequest
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
private const val THUMBNAIL_SIZE = 108
private const val FALLBACK_ICON_SIZE = 36 private const val FALLBACK_ICON_SIZE = 36
/** /**
@ -31,9 +32,10 @@ private const val FALLBACK_ICON_SIZE = 36
* will be displayed until the thumbnail is loaded. * will be displayed until the thumbnail is loaded.
* *
* @param tab The given [TabSessionState] to render a thumbnail for. * @param tab The given [TabSessionState] to render a thumbnail for.
* @param size [Dp] size of the thumbnail. * @param storage [ThumbnailStorage] to obtain tab thumbnail bitmaps from.
* @param backgroundColor [Color] used for the background of the favicon. * @param size Size of the thumbnail.
* @param modifier [Modifier] used to draw the image content. * @param modifier [Modifier] used to draw the image content.
* @param backgroundColor [Color] used for the background of the favicon.
* @param contentDescription Text used by accessibility services * @param contentDescription Text used by accessibility services
* to describe what this image represents. * to describe what this image represents.
* @param contentScale [ContentScale] used to draw image content. * @param contentScale [ContentScale] used to draw image content.
@ -43,8 +45,9 @@ private const val FALLBACK_ICON_SIZE = 36
@Suppress("LongParameterList") @Suppress("LongParameterList")
fun TabThumbnail( fun TabThumbnail(
tab: TabSessionState, tab: TabSessionState,
storage: ThumbnailStorage,
size: Int,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
size: Dp = THUMBNAIL_SIZE.dp,
backgroundColor: Color = FirefoxTheme.colors.layer2, backgroundColor: Color = FirefoxTheme.colors.layer2,
contentDescription: String? = null, contentDescription: String? = null,
contentScale: ContentScale = ContentScale.FillWidth, contentScale: ContentScale = ContentScale.FillWidth,
@ -55,8 +58,11 @@ fun TabThumbnail(
backgroundColor = backgroundColor, backgroundColor = backgroundColor,
) { ) {
ThumbnailImage( ThumbnailImage(
key = tab.id, request = ImageLoadRequest(
size = size, id = tab.id,
size = size,
),
storage = storage,
modifier = modifier, modifier = modifier,
contentScale = contentScale, contentScale = contentScale,
alignment = alignment, alignment = alignment,
@ -93,8 +99,10 @@ private fun ThumbnailCardPreview() {
FirefoxTheme { FirefoxTheme {
TabThumbnail( TabThumbnail(
tab = createTab(url = "www.mozilla.com", title = "Mozilla"), tab = createTab(url = "www.mozilla.com", title = "Mozilla"),
size = 108,
storage = ThumbnailStorage(LocalContext.current),
modifier = Modifier modifier = Modifier
.size(THUMBNAIL_SIZE.dp, 80.dp) .size(108.dp, 80.dp)
.clip(RoundedCornerShape(8.dp)), .clip(RoundedCornerShape(8.dp)),
) )
} }

@ -16,12 +16,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import mozilla.components.browser.icons.compose.Loader import mozilla.components.browser.icons.compose.Loader
import mozilla.components.browser.icons.compose.Placeholder import mozilla.components.browser.icons.compose.Placeholder
import mozilla.components.browser.icons.compose.WithIcon import mozilla.components.browser.icons.compose.WithIcon
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import mozilla.components.concept.base.images.ImageLoadRequest
import org.mozilla.fenix.components.components import org.mozilla.fenix.components.components
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
@ -33,10 +35,10 @@ private const val FALLBACK_ICON_SIZE = 36
* will be displayed until the thumbnail is loaded. * will be displayed until the thumbnail is loaded.
* *
* @param url Url to display thumbnail for. * @param url Url to display thumbnail for.
* @param key Key used to remember the thumbnail for future compositions. * @param request [ImageLoadRequest] used to fetch the thumbnail bitmap.
* @param size [Dp] size of the thumbnail. * @param storage [ThumbnailStorage] to obtain tab thumbnail bitmaps from.
* @param backgroundColor [Color] used for the background of the favicon.
* @param modifier [Modifier] used to draw the image content. * @param modifier [Modifier] used to draw the image content.
* @param backgroundColor [Color] used for the background of the favicon.
* @param contentDescription Text used by accessibility services * @param contentDescription Text used by accessibility services
* to describe what this image represents. * to describe what this image represents.
* @param contentScale [ContentScale] used to draw image content. * @param contentScale [ContentScale] used to draw image content.
@ -45,10 +47,10 @@ private const val FALLBACK_ICON_SIZE = 36
@Composable @Composable
fun ThumbnailCard( fun ThumbnailCard(
url: String, url: String,
key: String, request: ImageLoadRequest,
size: Dp = THUMBNAIL_SIZE.dp, storage: ThumbnailStorage,
backgroundColor: Color = FirefoxTheme.colors.layer2,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
backgroundColor: Color = FirefoxTheme.colors.layer2,
contentDescription: String? = null, contentDescription: String? = null,
contentScale: ContentScale = ContentScale.FillWidth, contentScale: ContentScale = ContentScale.FillWidth,
alignment: Alignment = Alignment.TopCenter, alignment: Alignment = Alignment.TopCenter,
@ -58,8 +60,8 @@ fun ThumbnailCard(
backgroundColor = backgroundColor, backgroundColor = backgroundColor,
) { ) {
ThumbnailImage( ThumbnailImage(
key = key, request = request,
size = size, storage = storage,
modifier = modifier, modifier = modifier,
contentScale = contentScale, contentScale = contentScale,
alignment = alignment, alignment = alignment,
@ -95,7 +97,8 @@ private fun ThumbnailCardPreview() {
FirefoxTheme { FirefoxTheme {
ThumbnailCard( ThumbnailCard(
url = "https://mozilla.com", url = "https://mozilla.com",
key = "123", request = ImageLoadRequest("123", THUMBNAIL_SIZE),
storage = ThumbnailStorage(LocalContext.current),
modifier = Modifier modifier = Modifier
.size(THUMBNAIL_SIZE.dp) .size(THUMBNAIL_SIZE.dp)
.clip(RoundedCornerShape(8.dp)), .clip(RoundedCornerShape(8.dp)),

@ -20,29 +20,28 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import mozilla.components.concept.base.images.ImageLoadRequest import mozilla.components.concept.base.images.ImageLoadRequest
import org.mozilla.fenix.components.components
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
/** /**
* Thumbnail belonging to a [key]. Asynchronously fetches the bitmap from storage. * Thumbnail belonging to a [ImageLoadRequest]. Asynchronously fetches the bitmap from storage.
* *
* @param key Key used to remember the thumbnail for future compositions. * @param request [ImageLoadRequest] used to fetch the thumbnail bitmap.
* @param size [Dp] size of the thumbnail. * @param storage [ThumbnailStorage] to obtain tab thumbnail bitmaps from.
* @param modifier [Modifier] used to draw the image content. * @param modifier [Modifier] used to draw the image content.
* @param contentScale [ContentScale] used to draw image content. * @param contentScale [ContentScale] used to draw image content.
* @param alignment [Alignment] used to draw the image content. * @param alignment [Alignment] used to draw the image content.
* @param fallbackContent The content to display with a thumbnail is unable to be loaded.
*/ */
@Composable @Composable
@Suppress("LongParameterList") @Suppress("LongParameterList")
fun ThumbnailImage( fun ThumbnailImage(
key: String, request: ImageLoadRequest,
size: Dp, storage: ThumbnailStorage,
modifier: Modifier, modifier: Modifier,
contentScale: ContentScale, contentScale: ContentScale,
alignment: Alignment, alignment: Alignment,
@ -51,9 +50,6 @@ fun ThumbnailImage(
if (inComposePreview) { if (inComposePreview) {
Box(modifier = Modifier.background(color = FirefoxTheme.colors.layer3)) Box(modifier = Modifier.background(color = FirefoxTheme.colors.layer3))
} else { } else {
val thumbnailSize = LocalDensity.current.run { size.toPx().toInt() }
val request = ImageLoadRequest(key, thumbnailSize)
val storage = components.core.thumbnailStorage
var state by remember { mutableStateOf(ThumbnailImageState(null, false)) } var state by remember { mutableStateOf(ThumbnailImageState(null, false)) }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@ -113,8 +109,8 @@ private data class ThumbnailImageState(
private fun ThumbnailImagePreview() { private fun ThumbnailImagePreview() {
FirefoxTheme { FirefoxTheme {
ThumbnailImage( ThumbnailImage(
key = "", request = ImageLoadRequest("1", 1),
size = 1.dp, storage = ThumbnailStorage(LocalContext.current),
modifier = Modifier, modifier = Modifier,
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
alignment = Alignment.Center, alignment = Alignment.Center,

@ -41,7 +41,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource
@ -57,6 +57,7 @@ import androidx.compose.ui.zIndex
import androidx.core.text.BidiFormatter import androidx.core.text.BidiFormatter
import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import mozilla.components.support.ktx.kotlin.MAX_URI_LENGTH import mozilla.components.support.ktx.kotlin.MAX_URI_LENGTH
import mozilla.components.ui.colors.PhotonColors import mozilla.components.ui.colors.PhotonColors
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -74,6 +75,8 @@ import org.mozilla.fenix.theme.FirefoxTheme
* long clicks, multiple selection, and media controls. * long clicks, multiple selection, and media controls.
* *
* @param tab The given tab to be render as view a grid item. * @param tab The given tab to be render as view a grid item.
* @param storage [ThumbnailStorage] to obtain tab thumbnail bitmaps from.
* @param thumbnailSize Size of tab's thumbnail.
* @param isSelected Indicates if the item should be render as selected. * @param isSelected Indicates if the item should be render as selected.
* @param multiSelectionEnabled Indicates if the item should be render with multi selection options, * @param multiSelectionEnabled Indicates if the item should be render with multi selection options,
* enabled. * enabled.
@ -89,6 +92,8 @@ import org.mozilla.fenix.theme.FirefoxTheme
@Suppress("MagicNumber", "LongParameterList", "LongMethod") @Suppress("MagicNumber", "LongParameterList", "LongMethod")
fun TabGridItem( fun TabGridItem(
tab: TabSessionState, tab: TabSessionState,
storage: ThumbnailStorage,
thumbnailSize: Int,
isSelected: Boolean = false, isSelected: Boolean = false,
multiSelectionEnabled: Boolean = false, multiSelectionEnabled: Boolean = false,
multiSelectionSelected: Boolean = false, multiSelectionSelected: Boolean = false,
@ -226,6 +231,8 @@ fun TabGridItem(
Thumbnail( Thumbnail(
tab = tab, tab = tab,
size = thumbnailSize,
storage = storage,
multiSelectionSelected = multiSelectionSelected, multiSelectionSelected = multiSelectionSelected,
) )
} }
@ -253,6 +260,8 @@ fun TabGridItem(
@Composable @Composable
private fun Thumbnail( private fun Thumbnail(
tab: TabSessionState, tab: TabSessionState,
size: Int,
storage: ThumbnailStorage,
multiSelectionSelected: Boolean, multiSelectionSelected: Boolean,
) { ) {
Box( Box(
@ -265,7 +274,8 @@ private fun Thumbnail(
) { ) {
TabThumbnail( TabThumbnail(
tab = tab, tab = tab,
size = LocalConfiguration.current.screenWidthDp.dp, size = size,
storage = storage,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) )
@ -305,6 +315,8 @@ private fun TabGridItemPreview() {
url = "www.mozilla.com", url = "www.mozilla.com",
title = "Mozilla Domain", title = "Mozilla Domain",
), ),
thumbnailSize = 108,
storage = ThumbnailStorage(LocalContext.current),
onCloseClick = {}, onCloseClick = {},
onMediaClick = {}, onMediaClick = {},
onClick = {}, onClick = {},
@ -319,6 +331,8 @@ private fun TabGridItemSelectedPreview() {
FirefoxTheme { FirefoxTheme {
TabGridItem( TabGridItem(
tab = createTab(url = "www.mozilla.com", title = "Mozilla"), tab = createTab(url = "www.mozilla.com", title = "Mozilla"),
thumbnailSize = 108,
storage = ThumbnailStorage(LocalContext.current),
isSelected = true, isSelected = true,
onCloseClick = {}, onCloseClick = {},
onMediaClick = {}, onMediaClick = {},
@ -334,6 +348,8 @@ private fun TabGridItemMultiSelectedPreview() {
FirefoxTheme { FirefoxTheme {
TabGridItem( TabGridItem(
tab = createTab(url = "www.mozilla.com", title = "Mozilla"), tab = createTab(url = "www.mozilla.com", title = "Mozilla"),
thumbnailSize = 108,
storage = ThumbnailStorage(LocalContext.current),
multiSelectionEnabled = true, multiSelectionEnabled = true,
multiSelectionSelected = true, multiSelectionSelected = true,
onCloseClick = {}, onCloseClick = {},

@ -31,6 +31,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -42,6 +43,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import mozilla.components.support.ktx.kotlin.MAX_URI_LENGTH import mozilla.components.support.ktx.kotlin.MAX_URI_LENGTH
import mozilla.components.ui.colors.PhotonColors import mozilla.components.ui.colors.PhotonColors
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -57,7 +59,9 @@ import org.mozilla.fenix.theme.FirefoxTheme
* List item used to display a tab that supports clicks, * List item used to display a tab that supports clicks,
* long clicks, multiselection, and media controls. * long clicks, multiselection, and media controls.
* *
* @param tab The given tab to be render as view a list item. * @param tab The given tab to be render as view a grid item.
* @param storage [ThumbnailStorage] to obtain tab thumbnail bitmaps from.
* @param thumbnailSize Size of tab's thumbnail.
* @param isSelected Indicates if the item should be render as selected. * @param isSelected Indicates if the item should be render as selected.
* @param multiSelectionEnabled Indicates if the item should be render with multi selection options, * @param multiSelectionEnabled Indicates if the item should be render with multi selection options,
* enabled. * enabled.
@ -70,9 +74,11 @@ import org.mozilla.fenix.theme.FirefoxTheme
*/ */
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class) @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
@Composable @Composable
@Suppress("MagicNumber", "LongMethod") @Suppress("MagicNumber", "LongMethod", "LongParameterList")
fun TabListItem( fun TabListItem(
tab: TabSessionState, tab: TabSessionState,
storage: ThumbnailStorage,
thumbnailSize: Int,
isSelected: Boolean = false, isSelected: Boolean = false,
multiSelectionEnabled: Boolean = false, multiSelectionEnabled: Boolean = false,
multiSelectionSelected: Boolean = false, multiSelectionSelected: Boolean = false,
@ -130,6 +136,8 @@ fun TabListItem(
) { ) {
Thumbnail( Thumbnail(
tab = tab, tab = tab,
size = thumbnailSize,
storage = storage,
multiSelectionEnabled = multiSelectionEnabled, multiSelectionEnabled = multiSelectionEnabled,
isSelected = multiSelectionSelected, isSelected = multiSelectionSelected,
onMediaIconClicked = { onMediaClick(it) }, onMediaIconClicked = { onMediaClick(it) },
@ -184,8 +192,11 @@ fun TabListItem(
} }
@Composable @Composable
@Suppress("LongParameterList")
private fun Thumbnail( private fun Thumbnail(
tab: TabSessionState, tab: TabSessionState,
size: Int,
storage: ThumbnailStorage,
multiSelectionEnabled: Boolean, multiSelectionEnabled: Boolean,
isSelected: Boolean, isSelected: Boolean,
onMediaIconClicked: ((TabSessionState) -> Unit), onMediaIconClicked: ((TabSessionState) -> Unit),
@ -194,6 +205,8 @@ private fun Thumbnail(
Box { Box {
TabThumbnail( TabThumbnail(
tab = tab, tab = tab,
size = size,
storage = storage,
modifier = Modifier modifier = Modifier
.size(width = 92.dp, height = 72.dp) .size(width = 92.dp, height = 72.dp)
.semantics(mergeDescendants = true) { .semantics(mergeDescendants = true) {
@ -245,6 +258,8 @@ private fun TabListItemPreview() {
FirefoxTheme { FirefoxTheme {
TabListItem( TabListItem(
tab = createTab(url = "www.mozilla.com", title = "Mozilla"), tab = createTab(url = "www.mozilla.com", title = "Mozilla"),
thumbnailSize = 108,
storage = ThumbnailStorage(LocalContext.current),
onCloseClick = {}, onCloseClick = {},
onMediaClick = {}, onMediaClick = {},
onClick = {}, onClick = {},
@ -259,6 +274,8 @@ private fun SelectedTabListItemPreview() {
FirefoxTheme { FirefoxTheme {
TabListItem( TabListItem(
tab = createTab(url = "www.mozilla.com", title = "Mozilla"), tab = createTab(url = "www.mozilla.com", title = "Mozilla"),
thumbnailSize = 108,
storage = ThumbnailStorage(LocalContext.current),
onCloseClick = {}, onCloseClick = {},
onMediaClick = {}, onMediaClick = {},
onClick = {}, onClick = {},

@ -33,12 +33,16 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import mozilla.components.concept.base.images.ImageLoadRequest
import mozilla.components.concept.sync.DeviceType import mozilla.components.concept.sync.DeviceType
import mozilla.components.support.ktx.kotlin.trimmed import mozilla.components.support.ktx.kotlin.trimmed
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -50,10 +54,13 @@ import org.mozilla.fenix.compose.button.SecondaryButton
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
private const val THUMBNAIL_SIZE = 108
/** /**
* A recent synced tab card. * A recent synced tab card.
* *
* @param tab The [RecentSyncedTab] to display. * @param tab The [RecentSyncedTab] to display.
* @param storage [ThumbnailStorage] to obtain tab thumbnail bitmaps from.
* @param backgroundColor The background [Color] of the item. * @param backgroundColor The background [Color] of the item.
* @param buttonBackgroundColor The background [Color] of the item's button. * @param buttonBackgroundColor The background [Color] of the item's button.
* @param buttonTextColor The [Color] of the button's text. * @param buttonTextColor The [Color] of the button's text.
@ -66,6 +73,7 @@ import org.mozilla.fenix.theme.FirefoxTheme
@Composable @Composable
fun RecentSyncedTab( fun RecentSyncedTab(
tab: RecentSyncedTab?, tab: RecentSyncedTab?,
storage: ThumbnailStorage,
backgroundColor: Color = FirefoxTheme.colors.layer2, backgroundColor: Color = FirefoxTheme.colors.layer2,
buttonBackgroundColor: Color = FirefoxTheme.colors.actionSecondary, buttonBackgroundColor: Color = FirefoxTheme.colors.actionSecondary,
buttonTextColor: Color = FirefoxTheme.colors.textActionSecondary, buttonTextColor: Color = FirefoxTheme.colors.textActionSecondary,
@ -109,7 +117,11 @@ fun RecentSyncedTab(
} else { } else {
ThumbnailCard( ThumbnailCard(
url = tab.url, url = tab.url,
key = tab.url.hashCode().toString(), request = ImageLoadRequest(
id = tab.url.hashCode().toString(),
size = LocalDensity.current.run { THUMBNAIL_SIZE.dp.toPx().toInt() },
),
storage = storage,
modifier = imageModifier, modifier = imageModifier,
) )
} }
@ -246,6 +258,7 @@ private fun LoadedRecentSyncedTab() {
FirefoxTheme { FirefoxTheme {
RecentSyncedTab( RecentSyncedTab(
tab = tab, tab = tab,
storage = ThumbnailStorage(LocalContext.current),
onRecentSyncedTabClick = {}, onRecentSyncedTabClick = {},
onSeeAllSyncedTabsButtonClick = {}, onSeeAllSyncedTabsButtonClick = {},
onRemoveSyncedTab = {}, onRemoveSyncedTab = {},
@ -259,6 +272,7 @@ private fun LoadingRecentSyncedTab() {
FirefoxTheme { FirefoxTheme {
RecentSyncedTab( RecentSyncedTab(
tab = null, tab = null,
storage = ThumbnailStorage(LocalContext.current),
buttonBackgroundColor = FirefoxTheme.colors.layer3, buttonBackgroundColor = FirefoxTheme.colors.layer3,
onRecentSyncedTabClick = {}, onRecentSyncedTabClick = {},
onSeeAllSyncedTabsButtonClick = {}, onSeeAllSyncedTabsButtonClick = {},

@ -71,6 +71,7 @@ class RecentSyncedTabViewHolder(
RecentSyncedTab( RecentSyncedTab(
tab = syncedTab, tab = syncedTab,
storage = components.core.thumbnailStorage,
backgroundColor = wallpaperState.wallpaperCardColor, backgroundColor = wallpaperState.wallpaperCardColor,
buttonBackgroundColor = buttonBackgroundColor, buttonBackgroundColor = buttonBackgroundColor,
buttonTextColor = buttonTextColor, buttonTextColor = buttonTextColor,

@ -48,6 +48,7 @@ class RecentTabViewHolder(
RecentTabs( RecentTabs(
recentTabs = recentTabs.value ?: emptyList(), recentTabs = recentTabs.value ?: emptyList(),
storage = components.core.thumbnailStorage,
backgroundColor = wallpaperState.wallpaperCardColor, backgroundColor = wallpaperState.wallpaperCardColor,
onRecentTabClick = { recentTabInteractor.onRecentTabClicked(it) }, onRecentTabClick = { recentTabInteractor.onRecentTabClicked(it) },
menuItems = listOf( menuItems = listOf(

@ -39,6 +39,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.semantics.testTagsAsResourceId
@ -50,6 +52,7 @@ import mozilla.components.browser.icons.compose.Placeholder
import mozilla.components.browser.icons.compose.WithIcon import mozilla.components.browser.icons.compose.WithIcon
import mozilla.components.browser.state.state.ContentState import mozilla.components.browser.state.state.ContentState
import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import mozilla.components.support.ktx.kotlin.trimmed import mozilla.components.support.ktx.kotlin.trimmed
import mozilla.components.ui.colors.PhotonColors import mozilla.components.ui.colors.PhotonColors
import org.mozilla.fenix.components.components import org.mozilla.fenix.components.components
@ -62,6 +65,8 @@ import org.mozilla.fenix.compose.inComposePreview
import org.mozilla.fenix.home.recenttabs.RecentTab import org.mozilla.fenix.home.recenttabs.RecentTab
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
private const val THUMBNAIL_SIZE = 108
/** /**
* A list of recent tabs to jump back to. * A list of recent tabs to jump back to.
* *
@ -75,6 +80,7 @@ import org.mozilla.fenix.theme.FirefoxTheme
fun RecentTabs( fun RecentTabs(
recentTabs: List<RecentTab>, recentTabs: List<RecentTab>,
menuItems: List<RecentTabMenuItem>, menuItems: List<RecentTabMenuItem>,
storage: ThumbnailStorage,
backgroundColor: Color = FirefoxTheme.colors.layer2, backgroundColor: Color = FirefoxTheme.colors.layer2,
onRecentTabClick: (String) -> Unit = {}, onRecentTabClick: (String) -> Unit = {},
) { ) {
@ -92,6 +98,7 @@ fun RecentTabs(
is RecentTab.Tab -> { is RecentTab.Tab -> {
RecentTabItem( RecentTabItem(
tab = tab, tab = tab,
storage = storage,
menuItems = menuItems, menuItems = menuItems,
backgroundColor = backgroundColor, backgroundColor = backgroundColor,
onRecentTabClick = onRecentTabClick, onRecentTabClick = onRecentTabClick,
@ -117,6 +124,7 @@ fun RecentTabs(
@Suppress("LongMethod") @Suppress("LongMethod")
private fun RecentTabItem( private fun RecentTabItem(
tab: RecentTab.Tab, tab: RecentTab.Tab,
storage: ThumbnailStorage,
menuItems: List<RecentTabMenuItem>, menuItems: List<RecentTabMenuItem>,
backgroundColor: Color, backgroundColor: Color,
onRecentTabClick: (String) -> Unit = {}, onRecentTabClick: (String) -> Unit = {},
@ -141,6 +149,7 @@ private fun RecentTabItem(
) { ) {
RecentTabImage( RecentTabImage(
tab = tab, tab = tab,
storage = storage,
modifier = Modifier modifier = Modifier
.size(108.dp, 80.dp) .size(108.dp, 80.dp)
.clip(RoundedCornerShape(8.dp)), .clip(RoundedCornerShape(8.dp)),
@ -214,6 +223,7 @@ private fun RecentTabItem(
@Composable @Composable
fun RecentTabImage( fun RecentTabImage(
tab: RecentTab.Tab, tab: RecentTab.Tab,
storage: ThumbnailStorage,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.FillWidth, contentScale: ContentScale = ContentScale.FillWidth,
) { ) {
@ -224,12 +234,14 @@ fun RecentTabImage(
Image( Image(
url = previewImageUrl, url = previewImageUrl,
modifier = modifier, modifier = modifier,
targetSize = 108.dp, targetSize = THUMBNAIL_SIZE.dp,
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
) )
} }
else -> TabThumbnail( else -> TabThumbnail(
tab = tab.state, tab = tab.state,
size = LocalDensity.current.run { THUMBNAIL_SIZE.dp.toPx().toInt() },
storage = storage,
modifier = modifier, modifier = modifier,
contentScale = contentScale, contentScale = contentScale,
) )
@ -320,6 +332,7 @@ private fun RecentTabsPreview() {
recentTabs = listOf( recentTabs = listOf(
tab, tab,
), ),
storage = ThumbnailStorage(LocalContext.current),
menuItems = listOf( menuItems = listOf(
RecentTabMenuItem( RecentTabMenuItem(
title = "Menu item", title = "Menu item",

@ -27,6 +27,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -36,6 +37,7 @@ import mozilla.components.browser.state.state.ContentState
import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.storage.sync.TabEntry import mozilla.components.browser.storage.sync.TabEntry
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import mozilla.components.lib.state.ext.observeAsComposableState import mozilla.components.lib.state.ext.observeAsComposableState
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.components.AppStore
@ -55,6 +57,7 @@ import mozilla.components.browser.storage.sync.Tab as SyncTab
* @param appStore [AppStore] used to listen for changes to [AppState]. * @param appStore [AppStore] used to listen for changes to [AppState].
* @param browserStore [BrowserStore] used to listen for changes to [BrowserState]. * @param browserStore [BrowserStore] used to listen for changes to [BrowserState].
* @param tabsTrayStore [TabsTrayStore] used to listen for changes to [TabsTrayState]. * @param tabsTrayStore [TabsTrayStore] used to listen for changes to [TabsTrayState].
* @param storage [ThumbnailStorage] to obtain tab thumbnail bitmaps from.
* @param displayTabsInGrid Whether the normal and private tabs should be displayed in a grid. * @param displayTabsInGrid Whether the normal and private tabs should be displayed in a grid.
* @param isInDebugMode True for debug variant or if secret menu is enabled for this session. * @param isInDebugMode True for debug variant or if secret menu is enabled for this session.
* @param shouldShowTabAutoCloseBanner Whether the tab auto closer banner should be displayed. * @param shouldShowTabAutoCloseBanner Whether the tab auto closer banner should be displayed.
@ -98,6 +101,7 @@ fun TabsTray(
appStore: AppStore, appStore: AppStore,
browserStore: BrowserStore, browserStore: BrowserStore,
tabsTrayStore: TabsTrayStore, tabsTrayStore: TabsTrayStore,
storage: ThumbnailStorage,
displayTabsInGrid: Boolean, displayTabsInGrid: Boolean,
isInDebugMode: Boolean, isInDebugMode: Boolean,
shouldShowTabAutoCloseBanner: Boolean, shouldShowTabAutoCloseBanner: Boolean,
@ -193,6 +197,7 @@ fun TabsTray(
appStore = appStore, appStore = appStore,
browserStore = browserStore, browserStore = browserStore,
tabsTrayStore = tabsTrayStore, tabsTrayStore = tabsTrayStore,
storage = storage,
displayTabsInGrid = displayTabsInGrid, displayTabsInGrid = displayTabsInGrid,
onTabClose = onTabClose, onTabClose = onTabClose,
onTabMediaClick = onTabMediaClick, onTabMediaClick = onTabMediaClick,
@ -213,6 +218,7 @@ fun TabsTray(
PrivateTabsPage( PrivateTabsPage(
browserStore = browserStore, browserStore = browserStore,
tabsTrayStore = tabsTrayStore, tabsTrayStore = tabsTrayStore,
storage = storage,
displayTabsInGrid = displayTabsInGrid, displayTabsInGrid = displayTabsInGrid,
onTabClose = onTabClose, onTabClose = onTabClose,
onTabMediaClick = onTabMediaClick, onTabMediaClick = onTabMediaClick,
@ -239,6 +245,7 @@ private fun NormalTabsPage(
appStore: AppStore, appStore: AppStore,
browserStore: BrowserStore, browserStore: BrowserStore,
tabsTrayStore: TabsTrayStore, tabsTrayStore: TabsTrayStore,
storage: ThumbnailStorage,
displayTabsInGrid: Boolean, displayTabsInGrid: Boolean,
onTabClose: (TabSessionState) -> Unit, onTabClose: (TabSessionState) -> Unit,
onTabMediaClick: (TabSessionState) -> Unit, onTabMediaClick: (TabSessionState) -> Unit,
@ -299,6 +306,7 @@ private fun NormalTabsPage(
TabLayout( TabLayout(
tabs = normalTabs, tabs = normalTabs,
storage = storage,
displayTabsInGrid = displayTabsInGrid, displayTabsInGrid = displayTabsInGrid,
selectedTabId = selectedTabId, selectedTabId = selectedTabId,
selectionMode = selectionMode, selectionMode = selectionMode,
@ -319,6 +327,7 @@ private fun NormalTabsPage(
private fun PrivateTabsPage( private fun PrivateTabsPage(
browserStore: BrowserStore, browserStore: BrowserStore,
tabsTrayStore: TabsTrayStore, tabsTrayStore: TabsTrayStore,
storage: ThumbnailStorage,
displayTabsInGrid: Boolean, displayTabsInGrid: Boolean,
onTabClose: (TabSessionState) -> Unit, onTabClose: (TabSessionState) -> Unit,
onTabMediaClick: (TabSessionState) -> Unit, onTabMediaClick: (TabSessionState) -> Unit,
@ -335,6 +344,7 @@ private fun PrivateTabsPage(
if (privateTabs.isNotEmpty()) { if (privateTabs.isNotEmpty()) {
TabLayout( TabLayout(
tabs = privateTabs, tabs = privateTabs,
storage = storage,
displayTabsInGrid = displayTabsInGrid, displayTabsInGrid = displayTabsInGrid,
selectedTabId = selectedTabId, selectedTabId = selectedTabId,
selectionMode = selectionMode, selectionMode = selectionMode,
@ -508,6 +518,7 @@ private fun TabsTrayPreviewRoot(
appStore = appStore, appStore = appStore,
browserStore = browserStore, browserStore = browserStore,
tabsTrayStore = tabsTrayStore, tabsTrayStore = tabsTrayStore,
storage = ThumbnailStorage(LocalContext.current),
displayTabsInGrid = displayTabsInGrid, displayTabsInGrid = displayTabsInGrid,
isInDebugMode = false, isInDebugMode = false,
shouldShowInactiveTabsAutoCloseDialog = { true }, shouldShowInactiveTabsAutoCloseDialog = { true },

@ -240,6 +240,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
appStore = requireComponents.appStore, appStore = requireComponents.appStore,
browserStore = requireComponents.core.store, browserStore = requireComponents.core.store,
tabsTrayStore = tabsTrayStore, tabsTrayStore = tabsTrayStore,
storage = requireComponents.core.thumbnailStorage,
displayTabsInGrid = requireContext().settings().gridTabView, displayTabsInGrid = requireContext().settings().gridTabView,
isInDebugMode = Config.channel.isDebug || isInDebugMode = Config.channel.isDebug ||
requireComponents.settings.showSecretDebugMenuThisSession, requireComponents.settings.showSecretDebugMenuThisSession,

@ -21,25 +21,30 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.toMutableStateList import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import mozilla.components.browser.state.state.ContentState import mozilla.components.browser.state.state.ContentState
import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.compose.annotation.LightDarkPreview import org.mozilla.fenix.compose.annotation.LightDarkPreview
import org.mozilla.fenix.compose.tabstray.TabGridItem import org.mozilla.fenix.compose.tabstray.TabGridItem
import org.mozilla.fenix.compose.tabstray.TabListItem import org.mozilla.fenix.compose.tabstray.TabListItem
import org.mozilla.fenix.tabstray.ext.MIN_COLUMN_WIDTH_DP import org.mozilla.fenix.tabstray.ext.MIN_COLUMN_WIDTH_DP
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
import kotlin.math.max
/** /**
* Top-level UI for displaying a list of tabs. * Top-level UI for displaying a list of tabs.
* *
* @param tabs The list of [TabSessionState] to display. * @param tabs The list of [TabSessionState] to display.
* @param storage [ThumbnailStorage] to obtain tab thumbnail bitmaps from.
* @param displayTabsInGrid Whether the tabs should be displayed in a grid. * @param displayTabsInGrid Whether the tabs should be displayed in a grid.
* @param selectedTabId The ID of the currently selected tab. * @param selectedTabId The ID of the currently selected tab.
* @param selectionMode [TabsTrayState.Mode] indicating whether the Tabs Tray is in single selection * @param selectionMode [TabsTrayState.Mode] indicating whether the Tabs Tray is in single selection
* or multi-selection and contains the set of selected tabs. * or multi-selection and contains the set of selected tabs.
* @param modifier
* @param onTabClose Invoked when the user clicks to close a tab. * @param onTabClose Invoked when the user clicks to close a tab.
* @param onTabMediaClick Invoked when the user interacts with a tab's media controls. * @param onTabMediaClick Invoked when the user interacts with a tab's media controls.
* @param onTabClick Invoked when the user clicks on a tab. * @param onTabClick Invoked when the user clicks on a tab.
@ -50,6 +55,7 @@ import org.mozilla.fenix.theme.FirefoxTheme
@Composable @Composable
fun TabLayout( fun TabLayout(
tabs: List<TabSessionState>, tabs: List<TabSessionState>,
storage: ThumbnailStorage,
displayTabsInGrid: Boolean, displayTabsInGrid: Boolean,
selectedTabId: String?, selectedTabId: String?,
selectionMode: TabsTrayState.Mode, selectionMode: TabsTrayState.Mode,
@ -72,6 +78,7 @@ fun TabLayout(
if (displayTabsInGrid) { if (displayTabsInGrid) {
TabGrid( TabGrid(
tabs = tabs, tabs = tabs,
storage = storage,
selectedTabId = selectedTabId, selectedTabId = selectedTabId,
selectedTabIndex = selectedTabIndex, selectedTabIndex = selectedTabIndex,
selectionMode = selectionMode, selectionMode = selectionMode,
@ -85,6 +92,7 @@ fun TabLayout(
} else { } else {
TabList( TabList(
tabs = tabs, tabs = tabs,
storage = storage,
selectedTabId = selectedTabId, selectedTabId = selectedTabId,
selectedTabIndex = selectedTabIndex, selectedTabIndex = selectedTabIndex,
selectionMode = selectionMode, selectionMode = selectionMode,
@ -102,6 +110,7 @@ fun TabLayout(
@Composable @Composable
private fun TabGrid( private fun TabGrid(
tabs: List<TabSessionState>, tabs: List<TabSessionState>,
storage: ThumbnailStorage,
selectedTabId: String?, selectedTabId: String?,
selectedTabIndex: Int, selectedTabIndex: Int,
selectionMode: TabsTrayState.Mode, selectionMode: TabsTrayState.Mode,
@ -114,6 +123,10 @@ private fun TabGrid(
) { ) {
val state = rememberLazyGridState(initialFirstVisibleItemIndex = selectedTabIndex) val state = rememberLazyGridState(initialFirstVisibleItemIndex = selectedTabIndex)
val tabListBottomPadding = dimensionResource(id = R.dimen.tab_tray_list_bottom_padding) val tabListBottomPadding = dimensionResource(id = R.dimen.tab_tray_list_bottom_padding)
val tabThumbnailSize = max(
LocalContext.current.resources.getDimensionPixelSize(R.dimen.tab_tray_grid_item_thumbnail_height),
LocalContext.current.resources.getDimensionPixelSize(R.dimen.tab_tray_grid_item_thumbnail_width),
)
val isInMultiSelectMode = selectionMode is TabsTrayState.Mode.Select val isInMultiSelectMode = selectionMode is TabsTrayState.Mode.Select
LazyVerticalGrid( LazyVerticalGrid(
@ -133,6 +146,8 @@ private fun TabGrid(
) { tab -> ) { tab ->
TabGridItem( TabGridItem(
tab = tab, tab = tab,
thumbnailSize = tabThumbnailSize,
storage = storage,
isSelected = tab.id == selectedTabId, isSelected = tab.id == selectedTabId,
multiSelectionEnabled = isInMultiSelectMode, multiSelectionEnabled = isInMultiSelectMode,
multiSelectionSelected = selectionMode.selectedTabs.contains(tab), multiSelectionSelected = selectionMode.selectedTabs.contains(tab),
@ -153,6 +168,7 @@ private fun TabGrid(
@Composable @Composable
private fun TabList( private fun TabList(
tabs: List<TabSessionState>, tabs: List<TabSessionState>,
storage: ThumbnailStorage,
selectedTabId: String?, selectedTabId: String?,
selectedTabIndex: Int, selectedTabIndex: Int,
selectionMode: TabsTrayState.Mode, selectionMode: TabsTrayState.Mode,
@ -165,6 +181,10 @@ private fun TabList(
) { ) {
val state = rememberLazyListState(initialFirstVisibleItemIndex = selectedTabIndex) val state = rememberLazyListState(initialFirstVisibleItemIndex = selectedTabIndex)
val tabListBottomPadding = dimensionResource(id = R.dimen.tab_tray_list_bottom_padding) val tabListBottomPadding = dimensionResource(id = R.dimen.tab_tray_list_bottom_padding)
val tabThumbnailSize = max(
LocalContext.current.resources.getDimensionPixelSize(R.dimen.tab_tray_list_item_thumbnail_height),
LocalContext.current.resources.getDimensionPixelSize(R.dimen.tab_tray_list_item_thumbnail_width),
)
val isInMultiSelectMode = selectionMode is TabsTrayState.Mode.Select val isInMultiSelectMode = selectionMode is TabsTrayState.Mode.Select
LazyColumn( LazyColumn(
@ -183,6 +203,8 @@ private fun TabList(
) { tab -> ) { tab ->
TabListItem( TabListItem(
tab = tab, tab = tab,
thumbnailSize = tabThumbnailSize,
storage = storage,
isSelected = tab.id == selectedTabId, isSelected = tab.id == selectedTabId,
multiSelectionEnabled = isInMultiSelectMode, multiSelectionEnabled = isInMultiSelectMode,
multiSelectionSelected = selectionMode.selectedTabs.contains(tab), multiSelectionSelected = selectionMode.selectedTabs.contains(tab),
@ -212,6 +234,7 @@ private fun TabListPreview() {
) { ) {
TabLayout( TabLayout(
tabs = tabs, tabs = tabs,
storage = ThumbnailStorage(LocalContext.current),
selectedTabId = tabs[1].id, selectedTabId = tabs[1].id,
selectionMode = TabsTrayState.Mode.Normal, selectionMode = TabsTrayState.Mode.Normal,
displayTabsInGrid = false, displayTabsInGrid = false,
@ -237,6 +260,7 @@ private fun TabGridPreview() {
) { ) {
TabLayout( TabLayout(
tabs = tabs, tabs = tabs,
storage = ThumbnailStorage(LocalContext.current),
selectedTabId = tabs[0].id, selectedTabId = tabs[0].id,
selectionMode = TabsTrayState.Mode.Normal, selectionMode = TabsTrayState.Mode.Normal,
displayTabsInGrid = true, displayTabsInGrid = true,
@ -264,6 +288,7 @@ private fun TabGridMultiSelectPreview() {
) { ) {
TabLayout( TabLayout(
tabs = tabs, tabs = tabs,
storage = ThumbnailStorage(LocalContext.current),
selectedTabId = tabs[0].id, selectedTabId = tabs[0].id,
selectionMode = TabsTrayState.Mode.Select(selectedTabs.toSet()), selectionMode = TabsTrayState.Mode.Select(selectedTabs.toSet()),
displayTabsInGrid = false, displayTabsInGrid = false,

@ -15,6 +15,7 @@ import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.tabstray.TabsTray import mozilla.components.browser.tabstray.TabsTray
import mozilla.components.browser.tabstray.TabsTrayStyling import mozilla.components.browser.tabstray.TabsTrayStyling
import mozilla.components.lib.state.ext.observeAsComposableState import mozilla.components.lib.state.ext.observeAsComposableState
import org.mozilla.fenix.components.components
import org.mozilla.fenix.compose.tabstray.TabGridItem import org.mozilla.fenix.compose.tabstray.TabGridItem
import org.mozilla.fenix.tabstray.TabsTrayInteractor import org.mozilla.fenix.tabstray.TabsTrayInteractor
import org.mozilla.fenix.tabstray.TabsTrayState import org.mozilla.fenix.tabstray.TabsTrayState
@ -82,6 +83,8 @@ class ComposeGridViewHolder(
TabGridItem( TabGridItem(
tab = tab, tab = tab,
thumbnailSize = 108,
storage = components.core.thumbnailStorage,
isSelected = isSelectedTab, isSelected = isSelectedTab,
multiSelectionEnabled = multiSelectionEnabled, multiSelectionEnabled = multiSelectionEnabled,
multiSelectionSelected = isMultiSelectionSelected, multiSelectionSelected = isMultiSelectionSelected,

@ -15,6 +15,7 @@ import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.tabstray.TabsTray import mozilla.components.browser.tabstray.TabsTray
import mozilla.components.browser.tabstray.TabsTrayStyling import mozilla.components.browser.tabstray.TabsTrayStyling
import mozilla.components.lib.state.ext.observeAsComposableState import mozilla.components.lib.state.ext.observeAsComposableState
import org.mozilla.fenix.components.components
import org.mozilla.fenix.compose.tabstray.TabListItem import org.mozilla.fenix.compose.tabstray.TabListItem
import org.mozilla.fenix.tabstray.TabsTrayInteractor import org.mozilla.fenix.tabstray.TabsTrayInteractor
import org.mozilla.fenix.tabstray.TabsTrayState import org.mozilla.fenix.tabstray.TabsTrayState
@ -86,6 +87,8 @@ class ComposeListViewHolder(
TabListItem( TabListItem(
tab = tab, tab = tab,
thumbnailSize = 108,
storage = components.core.thumbnailStorage,
isSelected = isSelectedTabState, isSelected = isSelectedTabState,
multiSelectionEnabled = multiSelectionEnabled, multiSelectionEnabled = multiSelectionEnabled,
multiSelectionSelected = multiSelectionSelected, multiSelectionSelected = multiSelectionSelected,

Loading…
Cancel
Save