mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-17 15:26:23 +00:00
[fenix] for https://github.com/mozilla-mobile/fenix/issues/24177: add ui wireframe for synced recent tab
This commit is contained in:
parent
13af68853e
commit
da6d15fc81
@ -48,6 +48,21 @@ sealed class RecentTab {
|
|||||||
*/
|
*/
|
||||||
data class Tab(val state: TabSessionState) : RecentTab()
|
data class Tab(val state: TabSessionState) : RecentTab()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tab that was recently viewed on a synced device.
|
||||||
|
*
|
||||||
|
* @param deviceDisplayName The device the tab was viewed on.
|
||||||
|
* @param title The title of the tab.
|
||||||
|
* @param url The url of the tab.
|
||||||
|
* @param previewImageUrl The url used to retrieve the preview image of the tab.
|
||||||
|
*/
|
||||||
|
data class SyncedTab(
|
||||||
|
val deviceDisplayName: String,
|
||||||
|
val title: String,
|
||||||
|
val url: String,
|
||||||
|
val previewImageUrl: String?,
|
||||||
|
) : RecentTab()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A search term group that was recently viewed
|
* A search term group that was recently viewed
|
||||||
*
|
*
|
||||||
|
@ -46,7 +46,7 @@ class RecentTabViewHolder(
|
|||||||
RecentTabs(
|
RecentTabs(
|
||||||
recentTabs = recentTabs.value ?: emptyList(),
|
recentTabs = recentTabs.value ?: emptyList(),
|
||||||
onRecentTabClick = { interactor.onRecentTabClicked(it) },
|
onRecentTabClick = { interactor.onRecentTabClicked(it) },
|
||||||
onRecentSearchGroupClicked = { interactor.onRecentSearchGroupClicked(it) },
|
onRecentSearchGroupClick = { interactor.onRecentSearchGroupClicked(it) },
|
||||||
menuItems = listOf(
|
menuItems = listOf(
|
||||||
RecentTabMenuItem(
|
RecentTabMenuItem(
|
||||||
title = stringResource(id = R.string.recent_tab_menu_item_remove),
|
title = stringResource(id = R.string.recent_tab_menu_item_remove),
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
@file:Suppress("MagicNumber")
|
@file:Suppress("MagicNumber", "TooManyFunctions")
|
||||||
|
|
||||||
package org.mozilla.fenix.home.recenttabs.view
|
package org.mozilla.fenix.home.recenttabs.view
|
||||||
|
|
||||||
@ -16,6 +16,7 @@ import androidx.compose.foundation.isSystemInDarkTheme
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
@ -26,6 +27,8 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.ButtonDefaults
|
||||||
import androidx.compose.material.Card
|
import androidx.compose.material.Card
|
||||||
import androidx.compose.material.DropdownMenu
|
import androidx.compose.material.DropdownMenu
|
||||||
import androidx.compose.material.DropdownMenuItem
|
import androidx.compose.material.DropdownMenuItem
|
||||||
@ -50,6 +53,7 @@ import androidx.compose.ui.platform.LocalDensity
|
|||||||
import androidx.compose.ui.res.colorResource
|
import androidx.compose.ui.res.colorResource
|
||||||
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.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@ -59,6 +63,7 @@ import mozilla.components.browser.icons.compose.WithIcon
|
|||||||
import mozilla.components.concept.base.images.ImageLoadRequest
|
import mozilla.components.concept.base.images.ImageLoadRequest
|
||||||
import mozilla.components.support.ktx.kotlin.getRepresentativeSnippet
|
import mozilla.components.support.ktx.kotlin.getRepresentativeSnippet
|
||||||
import mozilla.components.ui.colors.PhotonColors
|
import mozilla.components.ui.colors.PhotonColors
|
||||||
|
import org.mozilla.fenix.FeatureFlags
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.components
|
import org.mozilla.fenix.components.components
|
||||||
import org.mozilla.fenix.compose.Image
|
import org.mozilla.fenix.compose.Image
|
||||||
@ -71,14 +76,19 @@ import org.mozilla.fenix.theme.FirefoxTheme
|
|||||||
* @param recentTabs List of [RecentTab] to display.
|
* @param recentTabs List of [RecentTab] to display.
|
||||||
* @param menuItems List of [RecentTabMenuItem] shown long clicking a [RecentTab].
|
* @param menuItems List of [RecentTabMenuItem] shown long clicking a [RecentTab].
|
||||||
* @param onRecentTabClick Invoked when the user clicks on a recent tab.
|
* @param onRecentTabClick Invoked when the user clicks on a recent tab.
|
||||||
* @param onRecentSearchGroupClicked Invoked when the user clicks on a recent search group.
|
* @param onRecentSearchGroupClick Invoked when the user clicks on a recent search group.
|
||||||
|
* @param onRecentSyncedTabClick Invoked when the user clicks on the recent synced tab.
|
||||||
|
* @param onSyncedTabSeeAllButtonClick Invoked when user clicks on the "See all" button in the synced tab card.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
|
@Suppress("LongParameterList")
|
||||||
fun RecentTabs(
|
fun RecentTabs(
|
||||||
recentTabs: List<RecentTab>,
|
recentTabs: List<RecentTab>,
|
||||||
menuItems: List<RecentTabMenuItem>,
|
menuItems: List<RecentTabMenuItem>,
|
||||||
onRecentTabClick: (String) -> Unit = {},
|
onRecentTabClick: (String) -> Unit = {},
|
||||||
onRecentSearchGroupClicked: (String) -> Unit = {}
|
onRecentSearchGroupClick: (String) -> Unit = {},
|
||||||
|
onRecentSyncedTabClick: (RecentTab.SyncedTab) -> Unit = {},
|
||||||
|
onSyncedTabSeeAllButtonClick: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@ -99,7 +109,16 @@ fun RecentTabs(
|
|||||||
searchTerm = tab.searchTerm,
|
searchTerm = tab.searchTerm,
|
||||||
tabId = tab.tabId,
|
tabId = tab.tabId,
|
||||||
count = tab.count,
|
count = tab.count,
|
||||||
onSearchGroupClicked = onRecentSearchGroupClicked
|
onSearchGroupClick = onRecentSearchGroupClick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is RecentTab.SyncedTab -> {
|
||||||
|
if (FeatureFlags.taskContinuityFeature) {
|
||||||
|
RecentSyncedTabItem(
|
||||||
|
tab,
|
||||||
|
onRecentSyncedTabClick,
|
||||||
|
onSyncedTabSeeAllButtonClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,9 +177,7 @@ private fun RecentTabItem(
|
|||||||
Row {
|
Row {
|
||||||
RecentTabIcon(
|
RecentTabIcon(
|
||||||
url = tab.state.content.url,
|
url = tab.state.content.url,
|
||||||
modifier = Modifier
|
modifier = Modifier.size(18.dp).clip(RoundedCornerShape(2.dp)),
|
||||||
.size(18.dp, 18.dp)
|
|
||||||
.clip(RoundedCornerShape(2.dp)),
|
|
||||||
icon = tab.state.content.icon
|
icon = tab.state.content.icon
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -186,7 +203,7 @@ private fun RecentTabItem(
|
|||||||
* @param searchTerm The search term for the group.
|
* @param searchTerm The search term for the group.
|
||||||
* @param tabId The id of the last accessed tab in the group.
|
* @param tabId The id of the last accessed tab in the group.
|
||||||
* @param count Count of how many tabs belongs to the group.
|
* @param count Count of how many tabs belongs to the group.
|
||||||
* @param onSearchGroupClicked Invoked when the user clicks on a group.
|
* @param onSearchGroupClick Invoked when the user clicks on a group.
|
||||||
*/
|
*/
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
@Composable
|
@Composable
|
||||||
@ -194,13 +211,13 @@ private fun RecentSearchGroupItem(
|
|||||||
searchTerm: String,
|
searchTerm: String,
|
||||||
tabId: String,
|
tabId: String,
|
||||||
count: Int,
|
count: Int,
|
||||||
onSearchGroupClicked: (String) -> Unit = {}
|
onSearchGroupClick: (String) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(112.dp)
|
.height(112.dp)
|
||||||
.clickable { onSearchGroupClicked(tabId) },
|
.clickable { onSearchGroupClick(tabId) },
|
||||||
shape = RoundedCornerShape(8.dp),
|
shape = RoundedCornerShape(8.dp),
|
||||||
backgroundColor = FirefoxTheme.colors.layer2,
|
backgroundColor = FirefoxTheme.colors.layer2,
|
||||||
elevation = 6.dp
|
elevation = 6.dp
|
||||||
@ -244,25 +261,139 @@ private fun RecentSearchGroupItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A recent synced tab.
|
||||||
|
*
|
||||||
|
* @param tab Optional synced tab. If null, displays placeholders.
|
||||||
|
* @param onRecentSyncedTabClick Invoked when item is clicked.
|
||||||
|
* @param onSeeAllButtonClick Invoked when "See all" button is clicked.
|
||||||
|
*/
|
||||||
|
@Suppress("LongMethod")
|
||||||
|
@Composable
|
||||||
|
private fun RecentSyncedTabItem(
|
||||||
|
tab: RecentTab.SyncedTab?,
|
||||||
|
onRecentSyncedTabClick: (RecentTab.SyncedTab) -> Unit,
|
||||||
|
onSeeAllButtonClick: () -> Unit,
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(180.dp)
|
||||||
|
.clickable { tab?.let { onRecentSyncedTabClick(tab) } },
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
backgroundColor = FirefoxTheme.colors.layer2,
|
||||||
|
elevation = 6.dp
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(16.dp)) {
|
||||||
|
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
|
||||||
|
if (tab == null) {
|
||||||
|
RecentTabImagePlaceholder()
|
||||||
|
} else {
|
||||||
|
RecentTabImage(
|
||||||
|
tab = tab,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(108.dp, 80.dp)
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.SpaceBetween,
|
||||||
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
) {
|
||||||
|
if (tab == null) {
|
||||||
|
RecentTabTitlePlaceholder()
|
||||||
|
} else {
|
||||||
|
RecentTabTitle(title = tab.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
if (tab == null) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(FirefoxTheme.colors.layer3)
|
||||||
|
.size(18.dp)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.ic_synced_tabs),
|
||||||
|
contentDescription = stringResource(
|
||||||
|
R.string.recent_tabs_synced_device_icon_content_description
|
||||||
|
),
|
||||||
|
modifier = Modifier.size(18.dp, 18.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
if (tab == null) {
|
||||||
|
TextLinePlaceHolder()
|
||||||
|
} else {
|
||||||
|
RecentTabSubtitle(subtitle = tab.deviceDisplayName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = onSeeAllButtonClick,
|
||||||
|
colors = ButtonDefaults.outlinedButtonColors(
|
||||||
|
backgroundColor = if (tab == null) {
|
||||||
|
FirefoxTheme.colors.layer3
|
||||||
|
} else {
|
||||||
|
FirefoxTheme.colors.actionSecondary
|
||||||
|
}
|
||||||
|
),
|
||||||
|
elevation = ButtonDefaults.elevation(
|
||||||
|
defaultElevation = 0.dp,
|
||||||
|
pressedElevation = 0.dp
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.height(36.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
if (tab != null) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.recent_tabs_see_all_synced_tabs_button_text),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
color = FirefoxTheme.colors.textActionSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A recent tab image.
|
* A recent tab image.
|
||||||
*
|
*
|
||||||
* @param tab [RecentTab.Tab] that was recently viewed.
|
* @param tab [RecentTab] that was recently viewed.
|
||||||
* @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.
|
||||||
* is null.
|
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
private fun RecentTabImage(
|
private fun RecentTabImage(
|
||||||
tab: RecentTab.Tab,
|
tab: RecentTab,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
contentScale: ContentScale = ContentScale.FillWidth,
|
contentScale: ContentScale = ContentScale.FillWidth,
|
||||||
alignment: Alignment = Alignment.TopCenter
|
alignment: Alignment = Alignment.TopCenter
|
||||||
) {
|
) {
|
||||||
val previewImageUrl = tab.state.content.previewImageUrl
|
val (previewImageUrl, loaderUrl, key) = when (tab) {
|
||||||
val thumbnail = tab.state.content.thumbnail
|
is RecentTab.Tab -> Triple(
|
||||||
|
tab.state.content.previewImageUrl,
|
||||||
|
tab.state.content.url,
|
||||||
|
tab.state.id
|
||||||
|
)
|
||||||
|
is RecentTab.SyncedTab -> Triple(tab.previewImageUrl, tab.url, tab.url)
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
val thumbnail = (tab as? RecentTab.Tab)?.state?.content?.thumbnail
|
||||||
|
|
||||||
when {
|
when {
|
||||||
!previewImageUrl.isNullOrEmpty() -> {
|
!previewImageUrl.isNullOrEmpty() -> {
|
||||||
@ -287,15 +418,10 @@ private fun RecentTabImage(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
backgroundColor = colorResource(id = R.color.photonGrey20)
|
backgroundColor = colorResource(id = R.color.photonGrey20)
|
||||||
) {
|
) {
|
||||||
components.core.icons.Loader(tab.state.content.url) {
|
components.core.icons.Loader(loaderUrl) {
|
||||||
Placeholder {
|
Placeholder {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.background(
|
modifier = Modifier.background(color = FirefoxTheme.colors.layer3)
|
||||||
color = when (isSystemInDarkTheme()) {
|
|
||||||
true -> PhotonColors.DarkGrey30
|
|
||||||
false -> PhotonColors.LightGrey30
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +443,7 @@ private fun RecentTabImage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ThumbnailImage(
|
ThumbnailImage(
|
||||||
tabId = tab.state.id,
|
key = key,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
contentScale = contentScale,
|
contentScale = contentScale,
|
||||||
alignment = alignment
|
alignment = alignment
|
||||||
@ -327,6 +453,19 @@ private fun RecentTabImage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder for a recent tab image.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
private fun RecentTabImagePlaceholder() {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(108.dp, 80.dp)
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.background(color = FirefoxTheme.colors.layer3)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Menu shown for a [RecentTab.Tab].
|
* Menu shown for a [RecentTab.Tab].
|
||||||
*
|
*
|
||||||
@ -444,6 +583,20 @@ private fun RecentTabTitle(title: String) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder for a tab title.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
private fun RecentTabTitlePlaceholder() {
|
||||||
|
Column {
|
||||||
|
TextLinePlaceHolder()
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
TextLinePlaceHolder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A recent tab subtitle.
|
* A recent tab subtitle.
|
||||||
*
|
*
|
||||||
@ -465,18 +618,18 @@ private fun RecentTabSubtitle(subtitle: String) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ThumbnailImage(
|
private fun ThumbnailImage(
|
||||||
tabId: String,
|
key: String,
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
contentScale: ContentScale,
|
contentScale: ContentScale,
|
||||||
alignment: Alignment
|
alignment: Alignment
|
||||||
) {
|
) {
|
||||||
val rememberBitmap = remember(tabId) { mutableStateOf<ImageBitmap?>(null) }
|
val rememberBitmap = remember(key) { mutableStateOf<ImageBitmap?>(null) }
|
||||||
val size = LocalDensity.current.run { 108.dp.toPx().toInt() }
|
val size = LocalDensity.current.run { 108.dp.toPx().toInt() }
|
||||||
val request = ImageLoadRequest(tabId, size)
|
val request = ImageLoadRequest(key, size)
|
||||||
val storage = components.core.thumbnailStorage
|
val storage = components.core.thumbnailStorage
|
||||||
val bitmap = rememberBitmap.value
|
val bitmap = rememberBitmap.value
|
||||||
|
|
||||||
LaunchedEffect(tabId) {
|
LaunchedEffect(key) {
|
||||||
rememberBitmap.value = storage.loadThumbnail(request).await()?.asImageBitmap()
|
rememberBitmap.value = storage.loadThumbnail(request).await()?.asImageBitmap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,3 +644,13 @@ private fun ThumbnailImage(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TextLinePlaceHolder() {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(12.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(FirefoxTheme.colors.layer3)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -127,6 +127,10 @@
|
|||||||
<!-- Text for the number of tabs in a group in the 'Jump back in' section of the new tab
|
<!-- Text for the number of tabs in a group in the 'Jump back in' section of the new tab
|
||||||
%d is a placeholder for the number of sites in the group. This number will always be more than one. -->
|
%d is a placeholder for the number of sites in the group. This number will always be more than one. -->
|
||||||
<string name="recent_tabs_search_term_count_2">%d sites</string>
|
<string name="recent_tabs_search_term_count_2">%d sites</string>
|
||||||
|
<!-- Text for button in synced tab card that opens synced tabs tray -->
|
||||||
|
<string name="recent_tabs_see_all_synced_tabs_button_text">See all synced tabs</string>
|
||||||
|
<!-- Accessibility description for icon for recent synced tab -->
|
||||||
|
<string name="recent_tabs_synced_device_icon_content_description">Synced device</string>
|
||||||
<!-- Text for the menu button to remove a grouped highlight from the user's browsing history
|
<!-- Text for the menu button to remove a grouped highlight from the user's browsing history
|
||||||
in the Recently visited section -->
|
in the Recently visited section -->
|
||||||
<string name="recent_tab_menu_item_remove">Remove</string>
|
<string name="recent_tab_menu_item_remove">Remove</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user