Update SearchBar by using the DockedSearchBar from material3

This commit is contained in:
Florian Renaud 2023-03-06 16:25:26 +01:00
parent 4342c4ec07
commit 1f85df8a1a
5 changed files with 175 additions and 54 deletions

View file

@ -16,22 +16,22 @@
package io.element.android.features.createroom.root
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SearchBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -40,6 +40,7 @@ import androidx.compose.ui.unit.sp
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.CenterAlignedTopAppBar
import io.element.android.libraries.designsystem.theme.components.DockedSearchBar
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.Scaffold
@ -54,22 +55,22 @@ fun CreateRoomRootScreen(
modifier: Modifier = Modifier,
onClosePressed: () -> Unit = {}
) {
val isSearchActive = rememberSaveable { mutableStateOf(false) }
Scaffold(
modifier = modifier.fillMaxWidth(),
topBar = {
CreateRoomRootViewTopBar(onClosePressed = onClosePressed)
if (!isSearchActive.value) {
CreateRoomRootViewTopBar(onClosePressed = onClosePressed)
}
}
) {
Column(
modifier = Modifier.padding(it)
) {
SearchBar(
modifier = Modifier.padding(horizontal = 16.dp),
// TODO use resource string
placeHolderTitle = "Search for someone",
// TODO implement click behavior
onClickDescription = "",
onClick = {}
CreateRoomSearchBar(
modifier = Modifier.fillMaxWidth(),
placeHolderTitle = stringResource(StringR.string.search_for_someone),
active = isSearchActive,
)
}
}
@ -98,47 +99,62 @@ fun CreateRoomRootViewTopBar(
)
}
// TODO export into design system package
// TODO comment that SearchBar is not yet implemented in Material3 compose
// and that TextField cannot be used since contentPadding cannot be changed
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SearchBar(
modifier: Modifier = Modifier,
fun CreateRoomSearchBar(
placeHolderTitle: String,
onClickDescription: String = "",
onClick: () -> Unit = {},
active: MutableState<Boolean>,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.fillMaxWidth()
.height(48.dp)
.background(
color = MaterialTheme.colorScheme.surfaceVariant,
shape = RoundedCornerShape(28.dp),
)
.clickable(
role = Role.Button,
onClickLabel = onClickDescription,
onClick = onClick,
),
) {
Text(
modifier = Modifier
.padding(horizontal = 16.dp)
.align(Alignment.CenterVertically)
.weight(1f)
.alpha(0.4f),
text = placeHolderTitle,
)
Icon(
modifier = Modifier
.padding(horizontal = 16.dp)
.align(Alignment.CenterVertically)
.alpha(0.4f),
resourceId = DrawableR.drawable.ic_search,
contentDescription = stringResource(id = StringR.string.search)
)
var text by rememberSaveable { mutableStateOf("") }
val focusManager = LocalFocusManager.current
fun closeSearchBar() {
focusManager.clearFocus()
active.value = false
}
DockedSearchBar(
query = text,
onQueryChange = { text = it },
onSearch = { closeSearchBar() },
active = active.value,
onActiveChange = {
active.value = it
if (!active.value) focusManager.clearFocus()
},
modifier = modifier
.padding(horizontal = if (!active.value) 16.dp else 0.dp),
placeholder = {
Text(
text = placeHolderTitle,
modifier = Modifier.alpha(0.4f), // FIXME align on Design system theme (removing alpha should be fine)
)
},
leadingIcon = if (active.value) {
{
IconButton(onClick = { closeSearchBar() }) {
Icon(DrawableR.drawable.ic_arrow_back, stringResource(StringR.string.a11y_back))
}
}
} else null,
trailingIcon = {
if (active.value) {
IconButton(onClick = { text = "" }) {
Icon(DrawableR.drawable.ic_close, stringResource(StringR.string.a11y_clear))
}
} else {
Icon(
resourceId = DrawableR.drawable.ic_search,
contentDescription = stringResource(StringR.string.search),
modifier = Modifier.alpha(0.4f), // FIXME align on Design system theme (removing alpha should be fine)
)
}
},
shape = if (!active.value) SearchBarDefaults.dockedShape else SearchBarDefaults.fullScreenShape,
colors = if (!active.value) SearchBarDefaults.colors() else SearchBarDefaults.colors(containerColor = Color.Transparent),
content = {},
)
}
@Preview

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:OptIn(ExperimentalMaterial3Api::class)
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SearchBarColors
import androidx.compose.material3.SearchBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DockedSearchBar(
query: String,
onQueryChange: (String) -> Unit,
onSearch: (String) -> Unit,
active: Boolean,
onActiveChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
shape: Shape = SearchBarDefaults.dockedShape,
colors: SearchBarColors = SearchBarDefaults.colors(),
tonalElevation: Dp = SearchBarDefaults.Elevation,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable ColumnScope.() -> Unit,
) {
androidx.compose.material3.DockedSearchBar(
query = query,
onQueryChange = onQueryChange,
onSearch = onSearch,
active = active,
onActiveChange = onActiveChange,
modifier = modifier,
enabled = enabled,
placeholder = placeholder,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
shape = shape,
colors = colors,
tonalElevation = tonalElevation,
interactionSource = interactionSource,
content = content,
)
}
@Preview
@Composable
internal fun DockedSearchBarLightPreview() = ElementPreviewLight { ContentToPreview() }
@Preview
@Composable
internal fun DockedSearchBarDarkPreview() = ElementPreviewDark { ContentToPreview() }
@Composable
private fun ContentToPreview() {
DockedSearchBar(
query = "Some text",
onQueryChange = {},
onSearch = {},
active = false,
onActiveChange = {},
content = {},
)
}

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M16,7H3.83L9.42,1.41L8,0L0,8L8,16L9.41,14.59L3.83,9H16V7Z"
android:fillColor="#17191C"/>
</vector>

View file

@ -14,5 +14,8 @@
<string name="server_selection_server_footer">You can only connect to an existing server that supports sliding sync. Your homeserver admin will need to configure it.</string>
<string name="server_selection_sliding_sync_alert_title">Server not supported</string>
<string name="server_selection_sliding_sync_alert_message">This server currently doesn\'t support sliding sync.</string>
<string name="a11y_back">Back</string>
<string name="a11y_clear">Clear</string>
<string name="search_for_someone">Search for someone</string>
</resources>

View file

@ -39,7 +39,9 @@ fun DependencyHandlerScope.composeDependencies(libs: LibrariesForLibs) {
androidTestImplementation(composeBom)
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material:material")
implementation("androidx.compose.material3:material3")
// Override BOM version, SearchBar is not available in the actual version
// do not use latest version because of clashes on androidx lifecycle dependency
implementation("androidx.compose.material3:material3:1.1.0-alpha04")
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.activity:activity-compose:1.6.1")