mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-02 03:40:16 +00:00
[fenix] For https://github.com/mozilla-mobile/fenix/issues/23238 - Refactor synced tabs sections to be collapsible
This commit is contained in:
parent
6caab8dc25
commit
118a681bf7
@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -33,6 +34,8 @@ import androidx.compose.material.Divider
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@ -54,10 +57,13 @@ import org.mozilla.fenix.compose.SecondaryText
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
import mozilla.components.browser.storage.sync.Tab as SyncTab
|
||||
|
||||
private const val EXPANDED_BY_DEFAULT = true
|
||||
|
||||
/**
|
||||
* Top-level list UI for displaying Synced Tabs in the Tabs Tray.
|
||||
*
|
||||
* @param syncedTabs The tab UI items to be displayed.
|
||||
* @param taskContinuityEnabled Indicates whether the Task Continuity enhancements should be visible for users.
|
||||
* @param onTabClick The lambda for handling clicks on synced tabs.
|
||||
*/
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@ -68,30 +74,40 @@ fun SyncedTabsList(
|
||||
onTabClick: (SyncTab) -> Unit,
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
val expandedState = remember(syncedTabs) { syncedTabs.map { EXPANDED_BY_DEFAULT }.toMutableStateList() }
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = listState,
|
||||
) {
|
||||
if (taskContinuityEnabled) {
|
||||
syncedTabs.forEach { syncedTabItem ->
|
||||
syncedTabs.forEachIndexed { index, syncedTabItem ->
|
||||
when (syncedTabItem) {
|
||||
is SyncedTabsListItem.DeviceSection -> {
|
||||
val sectionExpanded = expandedState[index]
|
||||
|
||||
stickyHeader {
|
||||
SyncedTabsDeviceItem(deviceName = syncedTabItem.displayName)
|
||||
SyncedTabsSectionHeader(
|
||||
sectionText = syncedTabItem.displayName,
|
||||
expanded = sectionExpanded,
|
||||
) {
|
||||
expandedState[index] = !sectionExpanded
|
||||
}
|
||||
}
|
||||
|
||||
if (syncedTabItem.tabs.isNotEmpty()) {
|
||||
items(syncedTabItem.tabs) { syncedTab ->
|
||||
SyncedTabsTabItem(
|
||||
tabTitleText = syncedTab.displayTitle,
|
||||
url = syncedTab.displayURL,
|
||||
) {
|
||||
onTabClick(syncedTab.tab)
|
||||
if (sectionExpanded) {
|
||||
if (syncedTabItem.tabs.isNotEmpty()) {
|
||||
items(syncedTabItem.tabs) { syncedTab ->
|
||||
SyncedTabsTabItem(
|
||||
tabTitleText = syncedTab.displayTitle,
|
||||
url = syncedTab.displayURL,
|
||||
) {
|
||||
onTabClick(syncedTab.tab)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item { SyncedTabsNoTabsItem() }
|
||||
}
|
||||
} else {
|
||||
item { SyncedTabsNoTabsItem() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +127,7 @@ fun SyncedTabsList(
|
||||
} else {
|
||||
items(syncedTabs) { syncedTabItem ->
|
||||
when (syncedTabItem) {
|
||||
is SyncedTabsListItem.Device -> SyncedTabsDeviceItem(deviceName = syncedTabItem.displayName)
|
||||
is SyncedTabsListItem.Device -> SyncedTabsSectionHeader(sectionText = syncedTabItem.displayName)
|
||||
is SyncedTabsListItem.Error -> SyncedTabsErrorItem(
|
||||
errorText = syncedTabItem.errorText,
|
||||
errorButton = syncedTabItem.errorButton
|
||||
@ -135,32 +151,57 @@ fun SyncedTabsList(
|
||||
item {
|
||||
// The Spacer here is to act as a footer to add padding to the bottom of the list so
|
||||
// the FAB or any potential SnackBar doesn't overlap with the items at the end.
|
||||
Spacer(Modifier.height(240.dp))
|
||||
Spacer(modifier = Modifier.height(240.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Text header for sections of synced tabs
|
||||
* Collapsible header for sections of synced tabs
|
||||
*
|
||||
* @param deviceName The name of the user's device connected that has synced tabs.
|
||||
* @param sectionText The section title for a group of synced tabs.
|
||||
* @param expanded Indicates whether the section of content is expanded. If null, the Icon will be hidden.
|
||||
* @param onClick Optional lambda for handling section header clicks.
|
||||
*/
|
||||
@Composable
|
||||
fun SyncedTabsDeviceItem(deviceName: String) {
|
||||
fun SyncedTabsSectionHeader(
|
||||
sectionText: String,
|
||||
expanded: Boolean? = null,
|
||||
onClick: () -> Unit = {},
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(FirefoxTheme.colors.layer1)
|
||||
.clickable(onClick = onClick)
|
||||
) {
|
||||
PrimaryText(
|
||||
text = deviceName,
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, top = 16.dp, end = 8.dp, bottom = 8.dp),
|
||||
fontSize = 14.sp,
|
||||
fontFamily = FontFamily(Font(R.font.metropolis_semibold)),
|
||||
maxLines = 1
|
||||
)
|
||||
.padding(top = 16.dp, bottom = 8.dp, start = 16.dp, end = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
PrimaryText(
|
||||
text = sectionText,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = FontFamily(Font(R.font.metropolis_semibold)),
|
||||
maxLines = 1,
|
||||
)
|
||||
|
||||
expanded?.let {
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
Icon(
|
||||
painter = painterResource(
|
||||
if (expanded) R.drawable.ic_chevron_down else R.drawable.ic_chevron_up
|
||||
),
|
||||
contentDescription = stringResource(
|
||||
if (expanded) R.string.synced_tabs_collapse_group else R.string.synced_tabs_expand_group,
|
||||
),
|
||||
tint = FirefoxTheme.colors.textPrimary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Divider(color = FirefoxTheme.colors.borderPrimary)
|
||||
}
|
||||
@ -272,7 +313,7 @@ fun SyncedTabsErrorButton(buttonText: String, onClick: () -> Unit) {
|
||||
tint = FirefoxTheme.colors.textOnColorPrimary,
|
||||
)
|
||||
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
Text(
|
||||
text = buttonText,
|
||||
@ -305,21 +346,28 @@ fun SyncedTabsNoTabsItem() {
|
||||
private fun SyncedTabsListItemsPreview() {
|
||||
FirefoxTheme {
|
||||
Column(Modifier.background(FirefoxTheme.colors.layer1)) {
|
||||
SyncedTabsDeviceItem(deviceName = "Google Pixel Pro Max +Ultra 5000")
|
||||
SyncedTabsSectionHeader(sectionText = "Google Pixel Pro Max +Ultra 5000")
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
SyncedTabsSectionHeader(
|
||||
sectionText = "Collapsible Google Pixel Pro Max +Ultra 5000",
|
||||
expanded = true,
|
||||
) { println("Clicked section header") }
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
SyncedTabsTabItem(tabTitleText = "Mozilla", url = "www.mozilla.org") { println("Clicked tab") }
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
SyncedTabsErrorItem(errorText = stringResource(R.string.synced_tabs_reauth))
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
SyncedTabsNoTabsItem()
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1647,6 +1647,10 @@
|
||||
<string name="synced_tabs_sign_in_button">Sign in to sync</string>
|
||||
<!-- The text displayed when a synced device has no tabs to show in the list of Synced Tabs. -->
|
||||
<string name="synced_tabs_no_open_tabs">No open tabs</string>
|
||||
<!-- Content description for expanding a group of synced tabs. -->
|
||||
<string name="synced_tabs_expand_group">Expand group of synced tabs</string>
|
||||
<!-- Content description for collapsing a group of synced tabs. -->
|
||||
<string name="synced_tabs_collapse_group">Collapse group of synced tabs</string>
|
||||
|
||||
<!-- Top Sites -->
|
||||
<!-- Title text displayed in the dialog when top sites limit is reached. -->
|
||||
|
Loading…
Reference in New Issue
Block a user