|
|
@ -8,9 +8,7 @@ import androidx.compose.foundation.background
|
|
|
|
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.fillMaxSize
|
|
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
|
|
import androidx.compose.foundation.layout.padding
|
|
|
|
|
|
|
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
|
import androidx.compose.material.Text
|
|
|
|
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
|
|
import androidx.compose.runtime.getValue
|
|
|
|
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.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.lib.state.ext.observeAsComposableState
|
|
|
|
import mozilla.components.lib.state.ext.observeAsComposableState
|
|
|
|
import org.mozilla.fenix.components.AppStore
|
|
|
|
import org.mozilla.fenix.components.AppStore
|
|
|
|
import org.mozilla.fenix.components.appstate.AppState
|
|
|
|
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.compose.annotation.LightDarkPreview
|
|
|
|
import org.mozilla.fenix.tabstray.ext.isNormalTab
|
|
|
|
import org.mozilla.fenix.tabstray.ext.isNormalTab
|
|
|
|
import org.mozilla.fenix.tabstray.inactivetabs.InactiveTabsList
|
|
|
|
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 org.mozilla.fenix.theme.FirefoxTheme
|
|
|
|
|
|
|
|
import mozilla.components.browser.storage.sync.Tab as SyncTab
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Top-level UI for displaying the Tabs Tray feature.
|
|
|
|
* Top-level UI for displaying the Tabs Tray feature.
|
|
|
@ -62,6 +64,7 @@ import org.mozilla.fenix.theme.FirefoxTheme
|
|
|
|
* close dialog's enable button.
|
|
|
|
* close dialog's enable button.
|
|
|
|
* @param onInactiveTabClick Invoked when the user clicks on an inactive tab.
|
|
|
|
* @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 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)
|
|
|
|
@OptIn(ExperimentalPagerApi::class, ExperimentalComposeUiApi::class)
|
|
|
|
@Suppress("LongMethod", "LongParameterList")
|
|
|
|
@Suppress("LongMethod", "LongParameterList")
|
|
|
@ -85,6 +88,7 @@ fun TabsTray(
|
|
|
|
onEnableInactiveTabAutoCloseClick: () -> Unit,
|
|
|
|
onEnableInactiveTabAutoCloseClick: () -> Unit,
|
|
|
|
onInactiveTabClick: (TabSessionState) -> Unit,
|
|
|
|
onInactiveTabClick: (TabSessionState) -> Unit,
|
|
|
|
onInactiveTabClose: (TabSessionState) -> Unit,
|
|
|
|
onInactiveTabClose: (TabSessionState) -> Unit,
|
|
|
|
|
|
|
|
onSyncedTabClick: (SyncTab) -> Unit,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
val selectedTabId = browserStore
|
|
|
|
val selectedTabId = browserStore
|
|
|
|
.observeAsComposableState { state -> state.selectedTabId }.value
|
|
|
|
.observeAsComposableState { state -> state.selectedTabId }.value
|
|
|
@ -197,11 +201,13 @@ fun TabsTray(
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Page.SyncedTabs -> {
|
|
|
|
Page.SyncedTabs -> {
|
|
|
|
Text(
|
|
|
|
val syncedTabs = tabsTrayStore
|
|
|
|
text = "Synced tabs",
|
|
|
|
.observeAsComposableState { state -> state.syncedTabs }.value ?: emptyList()
|
|
|
|
modifier = Modifier.padding(all = 16.dp),
|
|
|
|
|
|
|
|
color = FirefoxTheme.colors.textPrimary,
|
|
|
|
SyncedTabsList(
|
|
|
|
style = FirefoxTheme.typography.body1,
|
|
|
|
syncedTabs = syncedTabs,
|
|
|
|
|
|
|
|
taskContinuityEnabled = true,
|
|
|
|
|
|
|
|
onTabClick = onSyncedTabClick,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -222,6 +228,7 @@ private fun TabsTrayPreview() {
|
|
|
|
tabCount = 7,
|
|
|
|
tabCount = 7,
|
|
|
|
isPrivate = true,
|
|
|
|
isPrivate = true,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
syncedTabs = generateFakeSyncedTabsList(),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -262,9 +269,11 @@ private fun TabsTrayPrivateTabsPreview() {
|
|
|
|
private fun TabsTraySyncedTabsPreview() {
|
|
|
|
private fun TabsTraySyncedTabsPreview() {
|
|
|
|
TabsTrayPreviewRoot(
|
|
|
|
TabsTrayPreviewRoot(
|
|
|
|
selectedPage = Page.SyncedTabs,
|
|
|
|
selectedPage = Page.SyncedTabs,
|
|
|
|
|
|
|
|
syncedTabs = generateFakeSyncedTabsList(deviceCount = 3),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Suppress("LongMethod", "LongParameterList")
|
|
|
|
@Composable
|
|
|
|
@Composable
|
|
|
|
private fun TabsTrayPreviewRoot(
|
|
|
|
private fun TabsTrayPreviewRoot(
|
|
|
|
displayTabsInGrid: Boolean = true,
|
|
|
|
displayTabsInGrid: Boolean = true,
|
|
|
@ -274,6 +283,7 @@ private fun TabsTrayPreviewRoot(
|
|
|
|
normalTabs: List<TabSessionState> = emptyList(),
|
|
|
|
normalTabs: List<TabSessionState> = emptyList(),
|
|
|
|
inactiveTabs: List<TabSessionState> = emptyList(),
|
|
|
|
inactiveTabs: List<TabSessionState> = emptyList(),
|
|
|
|
privateTabs: List<TabSessionState> = emptyList(),
|
|
|
|
privateTabs: List<TabSessionState> = emptyList(),
|
|
|
|
|
|
|
|
syncedTabs: List<SyncedTabsListItem> = emptyList(),
|
|
|
|
inactiveTabsExpanded: Boolean = false,
|
|
|
|
inactiveTabsExpanded: Boolean = false,
|
|
|
|
showInactiveTabsAutoCloseDialog: Boolean = false,
|
|
|
|
showInactiveTabsAutoCloseDialog: Boolean = false,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
@ -281,6 +291,7 @@ private fun TabsTrayPreviewRoot(
|
|
|
|
val normalTabsState = remember { normalTabs.toMutableStateList() }
|
|
|
|
val normalTabsState = remember { normalTabs.toMutableStateList() }
|
|
|
|
val inactiveTabsState = remember { inactiveTabs.toMutableStateList() }
|
|
|
|
val inactiveTabsState = remember { inactiveTabs.toMutableStateList() }
|
|
|
|
val privateTabsState = remember { privateTabs.toMutableStateList() }
|
|
|
|
val privateTabsState = remember { privateTabs.toMutableStateList() }
|
|
|
|
|
|
|
|
val syncedTabsState = remember { syncedTabs.toMutableStateList() }
|
|
|
|
var inactiveTabsExpandedState by remember { mutableStateOf(inactiveTabsExpanded) }
|
|
|
|
var inactiveTabsExpandedState by remember { mutableStateOf(inactiveTabsExpanded) }
|
|
|
|
var showInactiveTabsAutoCloseDialogState by remember { mutableStateOf(showInactiveTabsAutoCloseDialog) }
|
|
|
|
var showInactiveTabsAutoCloseDialogState by remember { mutableStateOf(showInactiveTabsAutoCloseDialog) }
|
|
|
|
|
|
|
|
|
|
|
@ -302,6 +313,7 @@ private fun TabsTrayPreviewRoot(
|
|
|
|
inactiveTabs = inactiveTabsState,
|
|
|
|
inactiveTabs = inactiveTabsState,
|
|
|
|
normalTabs = normalTabsState,
|
|
|
|
normalTabs = normalTabsState,
|
|
|
|
privateTabs = privateTabsState,
|
|
|
|
privateTabs = privateTabsState,
|
|
|
|
|
|
|
|
syncedTabs = syncedTabsState,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
@ -347,6 +359,7 @@ private fun TabsTrayPreviewRoot(
|
|
|
|
},
|
|
|
|
},
|
|
|
|
onInactiveTabClick = {},
|
|
|
|
onInactiveTabClick = {},
|
|
|
|
onInactiveTabClose = inactiveTabsState::remove,
|
|
|
|
onInactiveTabClose = inactiveTabsState::remove,
|
|
|
|
|
|
|
|
onSyncedTabClick = {},
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -361,3 +374,26 @@ private fun generateFakeTabsList(tabCount: Int = 10, isPrivate: Boolean = false)
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun generateFakeSyncedTabsList(deviceCount: Int = 1): List<SyncedTabsListItem> =
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
)
|
|
|
|