From 16cacdeeb7c1cf226af90d50009ad293d4d48773 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Thu, 11 Sep 2025 16:54:18 +0800 Subject: [PATCH] compose: blacklist: Switch to new search appbar API Signed-off-by: Aayush Gupta --- .../composables/SearchAppBarComposable.kt | 107 ------------------ .../compose/ui/commons/BlacklistScreen.kt | 99 ++++++++++++++-- .../store/compose/ui/search/SearchScreen.kt | 9 +- 3 files changed, 97 insertions(+), 118 deletions(-) delete mode 100644 app/src/main/java/com/aurora/store/compose/composables/SearchAppBarComposable.kt diff --git a/app/src/main/java/com/aurora/store/compose/composables/SearchAppBarComposable.kt b/app/src/main/java/com/aurora/store/compose/composables/SearchAppBarComposable.kt deleted file mode 100644 index d4b95ea75..000000000 --- a/app/src/main/java/com/aurora/store/compose/composables/SearchAppBarComposable.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composables - -import androidx.annotation.StringRes -import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.material3.TextFieldDefaults -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -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.graphics.Color -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R - -/** - * A top app bar composable to be used with Scaffold in different Screen - * @param modifier The modifier to be applied to the composable - * @param searchHint Hint to show to the user in search bar - * @param onNavigateUp Action when user clicks the navigation icon - * @param onSearch Callback for a search - * @param actions Actions to display on the top app bar (for e.g. menu) - */ -@Composable -fun SearchAppBarComposable( - modifier: Modifier = Modifier, - @StringRes searchHint: Int? = null, - onNavigateUp: () -> Unit, - onSearch: (query: String) -> Unit, - actions: @Composable (RowScope.() -> Unit) = {} -) { - val focusManager = LocalFocusManager.current - var query by rememberSaveable { mutableStateOf("") } - - TopAppBar( - modifier = modifier, - title = { - TextField( - modifier = Modifier.fillMaxWidth(), - value = query, - onValueChange = { newQuery -> - query = newQuery.trim() - onSearch(query) - }, - maxLines = 1, - placeholder = { if (searchHint != null) Text(text = stringResource(searchHint)) }, - colors = TextFieldDefaults.colors( - focusedContainerColor = Color.Transparent, - focusedIndicatorColor = Color.Transparent, - unfocusedContainerColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent - ), - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), - keyboardActions = KeyboardActions(onSearch = { focusManager.clearFocus() }) - ) - }, - navigationIcon = { - IconButton(onClick = onNavigateUp) { - Icon( - painter = painterResource(R.drawable.ic_arrow_back), - contentDescription = null - ) - } - }, - actions = { - if (query.isNotBlank()) { - IconButton( - onClick = { - query = "" - onSearch(query) - focusManager.clearFocus(force = true) - } - ) { - Icon(painter = painterResource(R.drawable.ic_cancel), contentDescription = null) - } - } - actions() - } - ) -} - -@Preview(showBackground = true) -@Composable -private fun SearchAppBarComposablePreview() { - SearchAppBarComposable( - searchHint = R.string.search_hint, - onNavigateUp = {}, - onSearch = {} - ) -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/commons/BlacklistScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/commons/BlacklistScreen.kt index beee39203..b821de681 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/commons/BlacklistScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/commons/BlacklistScreen.kt @@ -14,12 +14,30 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.text.input.clearText +import androidx.compose.foundation.text.input.rememberTextFieldState +import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd +import androidx.compose.material3.AppBarWithSearch +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold +import androidx.compose.material3.SearchBarDefaults +import androidx.compose.material3.Text +import androidx.compose.material3.rememberSearchBarState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.core.content.pm.PackageInfoCompat import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel @@ -28,11 +46,12 @@ import com.aurora.Constants import com.aurora.extensions.toast import com.aurora.store.R import com.aurora.store.compose.composables.BlackListComposable -import com.aurora.store.compose.composables.SearchAppBarComposable import com.aurora.store.compose.menu.BlacklistMenu import com.aurora.store.compose.menu.items.BlacklistMenuItem import com.aurora.store.util.PackageUtil import com.aurora.store.viewmodel.all.BlacklistViewModel +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch import java.util.Calendar @Composable @@ -75,8 +94,12 @@ private fun ScreenContent( onWhitelistAll: () -> Unit = {}, onSearch: (query: String) -> Unit = {} ) { - val context = LocalContext.current + val textFieldState = rememberTextFieldState() + val searchBarState = rememberSearchBarState() + val focusRequester = remember { FocusRequester() } + val coroutineScope = rememberCoroutineScope() + val docImportLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.OpenDocument(), onResult = { @@ -98,6 +121,11 @@ private fun ScreenContent( } ) + LaunchedEffect(key1 = textFieldState) { + snapshotFlow { textFieldState.text.toString() } + .collectLatest { query -> onSearch(query) } + } + @Composable fun SetupMenu() { BlacklistMenu { menuItem -> @@ -117,16 +145,67 @@ private fun ScreenContent( } } - Scaffold( - topBar = { - SearchAppBarComposable( - onNavigateUp = onNavigateUp, - actions = { if (!packages.isNullOrEmpty()) SetupMenu() }, - searchHint = R.string.search_hint, - onSearch = { query -> onSearch(query) } + fun onRequestSearch(query: String) { + textFieldState.setTextAndPlaceCursorAtEnd(query.trim()) + coroutineScope.launch { searchBarState.animateToCollapsed() } + onSearch(textFieldState.text.toString()) + } + + @Composable + fun SearchBar() { + val inputField = @Composable { + SearchBarDefaults.InputField( + modifier = Modifier.focusRequester(focusRequester), + searchBarState = searchBarState, + textFieldState = textFieldState, + onSearch = { query -> onRequestSearch(query) }, + placeholder = { + Text( + text = stringResource(R.string.search_hint), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + }, + leadingIcon = { + Icon( + painter = painterResource(R.drawable.ic_round_search), + contentDescription = stringResource(R.string.action_search) + ) + }, + trailingIcon = { + if (textFieldState.text.isNotBlank()) { + IconButton( + onClick = { + textFieldState.clearText() + focusRequester.requestFocus() + } + ) { + Icon( + painter = painterResource(R.drawable.ic_cancel), + contentDescription = stringResource(R.string.action_clear) + ) + } + } + } ) } - ) { paddingValues -> + + AppBarWithSearch( + state = searchBarState, + inputField = inputField, + navigationIcon = { + IconButton(onClick = onNavigateUp) { + Icon( + painter = painterResource(R.drawable.ic_arrow_back), + contentDescription = stringResource(R.string.action_back) + ) + } + }, + actions = { if (!packages.isNullOrEmpty()) SetupMenu() } + ) + } + + Scaffold(topBar = { SearchBar() }) { paddingValues -> LazyColumn( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt index 4b856a8af..9807121eb 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewScreenSizes import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel @@ -142,7 +143,13 @@ private fun ScreenContent( searchBarState = searchBarState, textFieldState = textFieldState, onSearch = { query -> onRequestSearch(query) }, - placeholder = { Text(text = stringResource(R.string.search_hint)) }, + placeholder = { + Text( + text = stringResource(R.string.search_hint), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + }, leadingIcon = { IconButton(onClick = onNavigateUp) { Icon(