mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-03 23:15:31 +00:00
Bug 1814994 - Create Tabs Tray list and grid layouts
This commit is contained in:
parent
fd61f88da2
commit
0acebea167
@ -12,29 +12,39 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||
import com.google.accompanist.pager.HorizontalPager
|
||||
import com.google.accompanist.pager.rememberPagerState
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.state.state.ContentState
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
import mozilla.components.lib.state.ext.observeAsComposableState
|
||||
import org.mozilla.fenix.compose.Divider
|
||||
import org.mozilla.fenix.compose.annotation.LightDarkPreview
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
import org.mozilla.fenix.theme.Theme
|
||||
|
||||
/**
|
||||
* Top-level UI for displaying the Tabs Tray feature.
|
||||
*
|
||||
* @param tabsTrayStore [TabsTrayStore] used to listen for changes to [TabsTrayState].
|
||||
* @param displayTabsInGrid Whether the normal and private tabs should be displayed in a grid.
|
||||
*/
|
||||
@OptIn(ExperimentalPagerApi::class)
|
||||
@OptIn(ExperimentalPagerApi::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun TabsTray(
|
||||
tabsTrayStore: TabsTrayStore,
|
||||
displayTabsInGrid: Boolean,
|
||||
) {
|
||||
val multiselectMode = tabsTrayStore
|
||||
.observeAsComposableState { state -> state.mode }.value ?: TabsTrayState.Mode.Normal
|
||||
val normalTabs = tabsTrayStore
|
||||
.observeAsComposableState { state -> state.normalTabs }.value ?: emptyList()
|
||||
val pagerState = rememberPagerState(initialPage = 0)
|
||||
val scope = rememberCoroutineScope()
|
||||
val animateScrollToPage: ((Page) -> Unit) = { page ->
|
||||
@ -48,10 +58,12 @@ fun TabsTray(
|
||||
.fillMaxSize()
|
||||
.background(FirefoxTheme.colors.layer1),
|
||||
) {
|
||||
TabsTrayBanner(
|
||||
isInMultiSelectMode = multiselectMode is TabsTrayState.Mode.Select,
|
||||
onTabPageIndicatorClicked = animateScrollToPage,
|
||||
)
|
||||
Box(modifier = Modifier.nestedScroll(rememberNestedScrollInteropConnection())) {
|
||||
TabsTrayBanner(
|
||||
isInMultiSelectMode = multiselectMode is TabsTrayState.Mode.Select,
|
||||
onTabPageIndicatorClicked = animateScrollToPage,
|
||||
)
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
@ -64,12 +76,17 @@ fun TabsTray(
|
||||
) { position ->
|
||||
when (Page.positionToPage(position)) {
|
||||
Page.NormalTabs -> {
|
||||
Text(
|
||||
text = "Normal tabs",
|
||||
modifier = Modifier.padding(all = 16.dp),
|
||||
color = FirefoxTheme.colors.textPrimary,
|
||||
style = FirefoxTheme.typography.body1,
|
||||
)
|
||||
FirefoxTheme(theme = Theme.getTheme(allowPrivateTheme = false)) {
|
||||
if (displayTabsInGrid) {
|
||||
TabGrid(
|
||||
tabs = normalTabs,
|
||||
)
|
||||
} else {
|
||||
TabList(
|
||||
tabs = normalTabs,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Page.PrivateTabs -> {
|
||||
Text(
|
||||
@ -96,9 +113,16 @@ fun TabsTray(
|
||||
@LightDarkPreview
|
||||
@Composable
|
||||
private fun TabsTrayPreview() {
|
||||
val store = TabsTrayStore(
|
||||
initialState = TabsTrayState(
|
||||
normalTabs = generateFakeTabsList(),
|
||||
),
|
||||
)
|
||||
|
||||
FirefoxTheme {
|
||||
TabsTray(
|
||||
tabsTrayStore = TabsTrayStore(),
|
||||
tabsTrayStore = store,
|
||||
displayTabsInGrid = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -109,12 +133,25 @@ private fun TabsTrayMultiSelectPreview() {
|
||||
val store = TabsTrayStore(
|
||||
initialState = TabsTrayState(
|
||||
mode = TabsTrayState.Mode.Select(setOf()),
|
||||
normalTabs = generateFakeTabsList(),
|
||||
),
|
||||
)
|
||||
|
||||
FirefoxTheme {
|
||||
TabsTray(
|
||||
tabsTrayStore = store,
|
||||
displayTabsInGrid = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateFakeTabsList(tabCount: Int = 10): List<TabSessionState> {
|
||||
val fakeTab = TabSessionState(
|
||||
id = "tabId",
|
||||
content = ContentState(
|
||||
url = "www.mozilla.com",
|
||||
),
|
||||
)
|
||||
|
||||
return List(tabCount) { fakeTab }
|
||||
}
|
||||
|
@ -208,6 +208,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
|
||||
FirefoxTheme {
|
||||
TabsTray(
|
||||
tabsTrayStore = tabsTrayStore,
|
||||
displayTabsInGrid = requireContext().settings().gridTabView,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,145 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.fenix.tabstray
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import mozilla.components.browser.state.state.ContentState
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.compose.annotation.LightDarkPreview
|
||||
import org.mozilla.fenix.compose.tabstray.TabGridItem
|
||||
import org.mozilla.fenix.compose.tabstray.TabListItem
|
||||
import org.mozilla.fenix.tabstray.ext.MIN_COLUMN_WIDTH_DP
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
|
||||
/**
|
||||
* Top-level UI for displaying a list of tabs.
|
||||
*
|
||||
* @param tabs The list of [TabSessionState] to display.
|
||||
*/
|
||||
@Composable
|
||||
fun TabList(
|
||||
tabs: List<TabSessionState>,
|
||||
) {
|
||||
val tabListBottomPadding = dimensionResource(id = R.dimen.tab_tray_list_bottom_padding)
|
||||
val state = rememberLazyListState()
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = state,
|
||||
) {
|
||||
items(
|
||||
items = tabs,
|
||||
key = { tab -> tab.id },
|
||||
) { tab ->
|
||||
TabListItem(
|
||||
tab = tab,
|
||||
onCloseClick = {},
|
||||
onMediaClick = {},
|
||||
onClick = {},
|
||||
onLongClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(tabListBottomPadding))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Top-level UI for displaying a grid of tabs.
|
||||
*
|
||||
* @param tabs The list of [TabSessionState] to display.
|
||||
*/
|
||||
@Composable
|
||||
fun TabGrid(
|
||||
tabs: List<TabSessionState>,
|
||||
) {
|
||||
val tabListBottomPadding = dimensionResource(id = R.dimen.tab_tray_list_bottom_padding)
|
||||
val state = rememberLazyGridState()
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Adaptive(minSize = MIN_COLUMN_WIDTH_DP.dp),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = state,
|
||||
) {
|
||||
items(
|
||||
items = tabs,
|
||||
key = { tab -> tab.id },
|
||||
) { tab ->
|
||||
TabGridItem(
|
||||
tab = tab,
|
||||
onCloseClick = {},
|
||||
onMediaClick = {},
|
||||
onClick = {},
|
||||
onLongClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||
Spacer(modifier = Modifier.height(tabListBottomPadding))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@LightDarkPreview
|
||||
@Composable
|
||||
private fun TabListPreview() {
|
||||
FirefoxTheme {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(FirefoxTheme.colors.layer1),
|
||||
) {
|
||||
TabList(
|
||||
tabs = generateFakeTabsList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@LightDarkPreview
|
||||
@Composable
|
||||
private fun TabGridPreview() {
|
||||
FirefoxTheme {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(FirefoxTheme.colors.layer1),
|
||||
) {
|
||||
TabGrid(
|
||||
tabs = generateFakeTabsList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateFakeTabsList(tabCount: Int = 10): List<TabSessionState> {
|
||||
val fakeTab = TabSessionState(
|
||||
id = "tabId",
|
||||
content = ContentState(
|
||||
url = "www.mozilla.com",
|
||||
),
|
||||
)
|
||||
|
||||
return List(tabCount) { fakeTab }
|
||||
}
|
Loading…
Reference in New Issue
Block a user