diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTray.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTray.kt index e3394ad5a2..f62b6d4f96 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTray.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTray.kt @@ -8,9 +8,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -31,6 +29,7 @@ import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.ContentState import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.store.BrowserStore +import mozilla.components.browser.storage.sync.TabEntry import mozilla.components.lib.state.ext.observeAsComposableState import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.components.appstate.AppState @@ -38,7 +37,10 @@ import org.mozilla.fenix.compose.Divider import org.mozilla.fenix.compose.annotation.LightDarkPreview import org.mozilla.fenix.tabstray.ext.isNormalTab import org.mozilla.fenix.tabstray.inactivetabs.InactiveTabsList +import org.mozilla.fenix.tabstray.syncedtabs.SyncedTabsList +import org.mozilla.fenix.tabstray.syncedtabs.SyncedTabsListItem import org.mozilla.fenix.theme.FirefoxTheme +import mozilla.components.browser.storage.sync.Tab as SyncTab /** * Top-level UI for displaying the Tabs Tray feature. @@ -62,6 +64,7 @@ import org.mozilla.fenix.theme.FirefoxTheme * close dialog's enable button. * @param onInactiveTabClick Invoked when the user clicks on an inactive tab. * @param onInactiveTabClose Invoked when the user clicks on an inactive tab's close button. + * @param onSyncedTabClick Invoked when the user clicks on a synced tab. */ @OptIn(ExperimentalPagerApi::class, ExperimentalComposeUiApi::class) @Suppress("LongMethod", "LongParameterList") @@ -85,6 +88,7 @@ fun TabsTray( onEnableInactiveTabAutoCloseClick: () -> Unit, onInactiveTabClick: (TabSessionState) -> Unit, onInactiveTabClose: (TabSessionState) -> Unit, + onSyncedTabClick: (SyncTab) -> Unit, ) { val selectedTabId = browserStore .observeAsComposableState { state -> state.selectedTabId }.value @@ -197,11 +201,13 @@ fun TabsTray( ) } Page.SyncedTabs -> { - Text( - text = "Synced tabs", - modifier = Modifier.padding(all = 16.dp), - color = FirefoxTheme.colors.textPrimary, - style = FirefoxTheme.typography.body1, + val syncedTabs = tabsTrayStore + .observeAsComposableState { state -> state.syncedTabs }.value ?: emptyList() + + SyncedTabsList( + syncedTabs = syncedTabs, + taskContinuityEnabled = true, + onTabClick = onSyncedTabClick, ) } } @@ -222,6 +228,7 @@ private fun TabsTrayPreview() { tabCount = 7, isPrivate = true, ), + syncedTabs = generateFakeSyncedTabsList(), ) } @@ -262,9 +269,11 @@ private fun TabsTrayPrivateTabsPreview() { private fun TabsTraySyncedTabsPreview() { TabsTrayPreviewRoot( selectedPage = Page.SyncedTabs, + syncedTabs = generateFakeSyncedTabsList(deviceCount = 3), ) } +@Suppress("LongMethod", "LongParameterList") @Composable private fun TabsTrayPreviewRoot( displayTabsInGrid: Boolean = true, @@ -274,6 +283,7 @@ private fun TabsTrayPreviewRoot( normalTabs: List = emptyList(), inactiveTabs: List = emptyList(), privateTabs: List = emptyList(), + syncedTabs: List = emptyList(), inactiveTabsExpanded: Boolean = false, showInactiveTabsAutoCloseDialog: Boolean = false, ) { @@ -281,6 +291,7 @@ private fun TabsTrayPreviewRoot( val normalTabsState = remember { normalTabs.toMutableStateList() } val inactiveTabsState = remember { inactiveTabs.toMutableStateList() } val privateTabsState = remember { privateTabs.toMutableStateList() } + val syncedTabsState = remember { syncedTabs.toMutableStateList() } var inactiveTabsExpandedState by remember { mutableStateOf(inactiveTabsExpanded) } var showInactiveTabsAutoCloseDialogState by remember { mutableStateOf(showInactiveTabsAutoCloseDialog) } @@ -302,6 +313,7 @@ private fun TabsTrayPreviewRoot( inactiveTabs = inactiveTabsState, normalTabs = normalTabsState, privateTabs = privateTabsState, + syncedTabs = syncedTabsState, ), ) @@ -347,6 +359,7 @@ private fun TabsTrayPreviewRoot( }, onInactiveTabClick = {}, onInactiveTabClose = inactiveTabsState::remove, + onSyncedTabClick = {}, ) } } @@ -361,3 +374,26 @@ private fun generateFakeTabsList(tabCount: Int = 10, isPrivate: Boolean = false) ), ) } + +private fun generateFakeSyncedTabsList(deviceCount: Int = 1): List = + List(deviceCount) { index -> + SyncedTabsListItem.DeviceSection( + displayName = "Device $index", + tabs = listOf( + generateFakeSyncedTab("Mozilla", "www.mozilla.org"), + generateFakeSyncedTab("Google", "www.google.com"), + generateFakeSyncedTab("", "www.google.com"), + ), + ) + } + +private fun generateFakeSyncedTab(tabName: String, tabUrl: String): SyncedTabsListItem.Tab = + SyncedTabsListItem.Tab( + tabName.ifEmpty { tabUrl }, + tabUrl, + SyncTab( + history = listOf(TabEntry(tabName, tabUrl, null)), + active = 0, + lastUsed = 0L, + ), + ) diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt index d105ca9d05..e4f8f73bbb 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt @@ -252,6 +252,7 @@ class TabsTrayFragment : AppCompatDialogFragment() { }, onInactiveTabClick = tabsTrayInteractor::onInactiveTabClicked, onInactiveTabClose = tabsTrayInteractor::onInactiveTabClosed, + onSyncedTabClick = tabsTrayInteractor::onSyncedTabClicked, ) } }