Bug 1864710 - Add UI for creating tabs

fenix/123.0
Noah Bond 5 months ago committed by mergify[bot]
parent 5e87f4d37a
commit 66f402398d

@ -14,37 +14,54 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Snackbar
import androidx.compose.material.SnackbarHost
import androidx.compose.material.SnackbarHostState
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.core.text.isDigitsOnly
import kotlinx.coroutines.launch
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.lib.state.ext.observeAsState
import org.mozilla.fenix.R
import org.mozilla.fenix.compose.Divider
import org.mozilla.fenix.compose.annotation.LightDarkPreview
import org.mozilla.fenix.compose.button.PrimaryButton
import org.mozilla.fenix.ext.maxActiveTime
import org.mozilla.fenix.tabstray.ext.isNormalTabInactive
import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.utils.Settings
/**
* Tab Tools UI for [DebugDrawer] that displays the tab counts and allows easy bulk-opening of tabs.
*
* @param store [BrowserStore] used to obtain the tab counts and fire any tab creation actions.
* @param settings Used to obtain whether the inactive tabs feature is enabled.
* @param inactiveTabsEnabled Whether the inactive tabs feature is enabled.
*/
@Composable
fun TabTools(
store: BrowserStore,
settings: Settings,
inactiveTabsEnabled: Boolean,
) {
val inactiveTabsEnabled = settings.inactiveTabsAreEnabled
val tabs by store.observeAsState(initialValue = emptyList()) { state -> state.tabs }
val totalTabCount = remember(tabs) { tabs.size }
val privateTabCount = remember(tabs) { tabs.filter { it.content.private }.size }
@ -63,21 +80,29 @@ fun TabTools(
privateTabCount = privateTabCount,
totalTabCount = totalTabCount,
inactiveTabsEnabled = inactiveTabsEnabled,
onAddTabsToActiveClick = {},
onAddTabsToInactiveClick = {},
onAddTabsToPrivateClick = {},
)
}
@Composable
@Suppress("LongParameterList")
private fun TabToolsContent(
activeTabCount: Int,
inactiveTabCount: Int,
privateTabCount: Int,
totalTabCount: Int,
inactiveTabsEnabled: Boolean,
onAddTabsToActiveClick: ((Int) -> Unit),
onAddTabsToInactiveClick: ((Int) -> Unit),
onAddTabsToPrivateClick: ((Int) -> Unit),
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(all = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
TabCounter(
activeTabCount = activeTabCount,
@ -86,6 +111,13 @@ private fun TabToolsContent(
totalTabCount = totalTabCount,
inactiveTabsEnabled = inactiveTabsEnabled,
)
TabCreationTool(
inactiveTabsEnabled = inactiveTabsEnabled,
onAddTabsToActiveClick = onAddTabsToActiveClick,
onAddTabsToInactiveClick = onAddTabsToInactiveClick,
onAddTabsToPrivateClick = onAddTabsToPrivateClick,
)
}
}
@ -161,6 +193,97 @@ private fun TabCountRow(
}
}
private const val DEFAULT_TABS_TO_ADD = "1"
@OptIn(ExperimentalComposeUiApi::class)
@Composable
private fun TabCreationTool(
inactiveTabsEnabled: Boolean,
onAddTabsToActiveClick: ((Int) -> Unit),
onAddTabsToInactiveClick: ((Int) -> Unit),
onAddTabsToPrivateClick: ((Int) -> Unit),
) {
var tabQuantityToCreate by rememberSaveable { mutableStateOf(DEFAULT_TABS_TO_ADD) }
var hasError by rememberSaveable { mutableStateOf(false) }
val keyboardController = LocalSoftwareKeyboardController.current
Column {
Text(
text = stringResource(R.string.debug_drawer_tab_tools_tab_creation_tool_title),
color = FirefoxTheme.colors.textPrimary,
style = FirefoxTheme.typography.headline5,
)
TextField(
value = tabQuantityToCreate,
onValueChange = {
tabQuantityToCreate = it
hasError = it.isEmpty() || !it.isDigitsOnly() || it.toInt() == 0
},
modifier = Modifier.fillMaxWidth(),
textStyle = FirefoxTheme.typography.subtitle1,
label = {
Text(
text = stringResource(R.string.debug_drawer_tab_tools_tab_creation_tool_text_field_label),
color = FirefoxTheme.colors.textPrimary,
style = FirefoxTheme.typography.caption,
)
},
isError = hasError,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
),
keyboardActions = KeyboardActions(
onDone = {
keyboardController?.hide()
},
),
singleLine = true,
colors = TextFieldDefaults.textFieldColors(
textColor = FirefoxTheme.colors.textPrimary,
backgroundColor = Color.Transparent,
cursorColor = FirefoxTheme.colors.borderFormDefault,
errorCursorColor = FirefoxTheme.colors.borderWarning,
focusedIndicatorColor = FirefoxTheme.colors.borderPrimary,
unfocusedIndicatorColor = FirefoxTheme.colors.borderPrimary,
errorIndicatorColor = FirefoxTheme.colors.borderWarning,
),
)
Spacer(modifier = Modifier.height(8.dp))
PrimaryButton(
text = stringResource(id = R.string.debug_drawer_tab_tools_tab_creation_tool_button_text_active),
enabled = !hasError,
onClick = {
onAddTabsToActiveClick(tabQuantityToCreate.toInt())
},
)
Spacer(modifier = Modifier.height(8.dp))
if (inactiveTabsEnabled) {
PrimaryButton(
text = stringResource(id = R.string.debug_drawer_tab_tools_tab_creation_tool_button_text_inactive),
enabled = !hasError,
onClick = {
onAddTabsToInactiveClick(tabQuantityToCreate.toInt())
},
)
Spacer(modifier = Modifier.height(8.dp))
}
PrimaryButton(
text = stringResource(id = R.string.debug_drawer_tab_tools_tab_creation_tool_button_text_private),
enabled = !hasError,
onClick = {
onAddTabsToPrivateClick(tabQuantityToCreate.toInt())
},
)
}
}
private data class TabToolsPreviewModel(
val activeTabCount: Int = 0,
val inactiveTabCount: Int = 0,
@ -197,6 +320,9 @@ private class TabToolsPreviewParameterProvider : PreviewParameterProvider<TabToo
private fun TabToolsPreview(
@PreviewParameter(TabToolsPreviewParameterProvider::class) model: TabToolsPreviewModel,
) {
val snackbarState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
with(model) {
FirefoxTheme {
Box(
@ -208,7 +334,31 @@ private fun TabToolsPreview(
privateTabCount = privateTabCount,
totalTabCount = totalTabCount,
inactiveTabsEnabled = inactiveTabsEnabled,
onAddTabsToActiveClick = {
scope.launch {
snackbarState.showSnackbar("Add $it tabs to active")
}
},
onAddTabsToInactiveClick = {
scope.launch {
snackbarState.showSnackbar("Add $it tabs to inactive")
}
},
onAddTabsToPrivateClick = {
scope.launch {
snackbarState.showSnackbar("Add $it tabs to private")
}
},
)
SnackbarHost(
hostState = snackbarState,
modifier = Modifier.align(Alignment.BottomCenter),
) { snackbarData ->
Snackbar(
snackbarData = snackbarData,
)
}
}
}
}

@ -2409,4 +2409,14 @@
<string name="debug_drawer_tab_tools_tab_count_private">Private</string>
<!-- The total tab count category in the tab count section in Tab Tools. -->
<string name="debug_drawer_tab_tools_tab_count_total">Total</string>
<!-- The title of the tab creation tool section in Tab Tools. -->
<string name="debug_drawer_tab_tools_tab_creation_tool_title">Tab creation tool</string>
<!-- The label of the text field in the tab creation tool. -->
<string name="debug_drawer_tab_tools_tab_creation_tool_text_field_label">Tab quantity to create</string>
<!-- The button text to add tabs to the active tab group in the tab creation tool. -->
<string name="debug_drawer_tab_tools_tab_creation_tool_button_text_active">Add to active tabs</string>
<!-- The button text to add tabs to the inactive tab group in the tab creation tool. -->
<string name="debug_drawer_tab_tools_tab_creation_tool_button_text_inactive">Add to inactive tabs</string>
<!-- The button text to add tabs to the private tab group in the tab creation tool. -->
<string name="debug_drawer_tab_tools_tab_creation_tool_button_text_private">Add to private tabs</string>
</resources>

Loading…
Cancel
Save