diff --git a/src/main/kotlin/com/looker/droidify/ui/compose/components/TopBar.kt b/src/main/kotlin/com/looker/droidify/ui/compose/components/TopBar.kt new file mode 100644 index 00000000..d46deb4a --- /dev/null +++ b/src/main/kotlin/com/looker/droidify/ui/compose/components/TopBar.kt @@ -0,0 +1,174 @@ +package com.looker.droidify.ui.compose.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Close +import androidx.compose.material.icons.rounded.Search +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextRange +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.unit.dp +import com.looker.droidify.R +import com.looker.droidify.ui.compose.utils.HorizontalExpandingVisibility + + +@Composable +fun TopBar( + title: String, + actions: @Composable (RowScope.() -> Unit) +) { + TopAppBar( + modifier = Modifier.wrapContentHeight(), + title = { + Text(text = title, style = MaterialTheme.typography.headlineSmall) + }, + backgroundColor = MaterialTheme.colorScheme.surface, + contentColor = MaterialTheme.colorScheme.onSurface, + elevation = 0.dp, + actions = actions + ) +} + +@Composable +fun ExpandableSearchAction( + query: String, + modifier: Modifier = Modifier, + expanded: Boolean = false, + onClose: () -> Unit, + onQueryChanged: (String) -> Unit +) { + val (expanded, onExpanded) = remember { + mutableStateOf(expanded) + } + + HorizontalExpandingVisibility( + expanded = expanded, + expandedView = { + ExpandedSearchView( + query = query, + modifier = modifier, + onClose = onClose, + onExpanded = onExpanded, + onQueryChanged = onQueryChanged + ) + }, + collapsedView = { + CollapsedSearchView( + modifier = modifier, + onExpanded = onExpanded + ) + } + ) +} + +@Composable +fun CollapsedSearchView( + modifier: Modifier = Modifier, + onExpanded: (Boolean) -> Unit +) { + TopBarAction( + icon = Icons.Rounded.Search, + description = stringResource(id = R.string.search), + onClick = { onExpanded(true) } + ) +} + +@Composable +fun ExpandedSearchView( + query: String, + modifier: Modifier = Modifier, + onClose: () -> Unit, + onExpanded: (Boolean) -> Unit, + onQueryChanged: (String) -> Unit +) { + val focusManager = LocalFocusManager.current + val textFieldFocusRequester = remember { FocusRequester() } + SideEffect { textFieldFocusRequester.requestFocus() } + + var textFieldValue by remember { + mutableStateOf(TextFieldValue(query, TextRange(query.length))) + } + + Row( + modifier = modifier + .fillMaxWidth() + .background( + color = Color.Transparent, + shape = MaterialTheme.shapes.medium + ), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + TextField( + value = textFieldValue, + onValueChange = { + textFieldValue = it + onQueryChanged(it.text) + }, + modifier = Modifier + .weight(1f) + .focusRequester(textFieldFocusRequester), + colors = TextFieldDefaults.textFieldColors( + backgroundColor = Color.Transparent, + ), + leadingIcon = { + Icon( + painter = painterResource(id = R.drawable.ic_search), + contentDescription = stringResource(id = R.string.search), + ) + }, + singleLine = true, + label = { Text(text = stringResource(id = R.string.search)) }, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), + ) + TopBarAction( + icon = Icons.Rounded.Close, + description = stringResource(id = R.string.cancel), + onClick = { + onExpanded(false) + onClose() + } + ) + } +} + +@Composable +fun TopBarAction( + icon: ImageVector, + description: String = "", + onClick: (() -> Unit) +) { + IconButton(onClick = onClick) { + Icon(imageVector = icon, contentDescription = description) + } +} \ No newline at end of file