compose: blacklist: Switch to new search appbar API
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -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 = {}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -14,12 +14,30 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
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.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.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
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.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.dimensionResource
|
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.compose.ui.tooling.preview.Preview
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
import androidx.core.content.pm.PackageInfoCompat
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
@@ -28,11 +46,12 @@ import com.aurora.Constants
|
|||||||
import com.aurora.extensions.toast
|
import com.aurora.extensions.toast
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
import com.aurora.store.compose.composables.BlackListComposable
|
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.BlacklistMenu
|
||||||
import com.aurora.store.compose.menu.items.BlacklistMenuItem
|
import com.aurora.store.compose.menu.items.BlacklistMenuItem
|
||||||
import com.aurora.store.util.PackageUtil
|
import com.aurora.store.util.PackageUtil
|
||||||
import com.aurora.store.viewmodel.all.BlacklistViewModel
|
import com.aurora.store.viewmodel.all.BlacklistViewModel
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -75,8 +94,12 @@ private fun ScreenContent(
|
|||||||
onWhitelistAll: () -> Unit = {},
|
onWhitelistAll: () -> Unit = {},
|
||||||
onSearch: (query: String) -> Unit = {}
|
onSearch: (query: String) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val textFieldState = rememberTextFieldState()
|
||||||
|
val searchBarState = rememberSearchBarState()
|
||||||
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val docImportLauncher = rememberLauncherForActivityResult(
|
val docImportLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.OpenDocument(),
|
contract = ActivityResultContracts.OpenDocument(),
|
||||||
onResult = {
|
onResult = {
|
||||||
@@ -98,6 +121,11 @@ private fun ScreenContent(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = textFieldState) {
|
||||||
|
snapshotFlow { textFieldState.text.toString() }
|
||||||
|
.collectLatest { query -> onSearch(query) }
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SetupMenu() {
|
fun SetupMenu() {
|
||||||
BlacklistMenu { menuItem ->
|
BlacklistMenu { menuItem ->
|
||||||
@@ -117,16 +145,67 @@ private fun ScreenContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
fun onRequestSearch(query: String) {
|
||||||
topBar = {
|
textFieldState.setTextAndPlaceCursorAtEnd(query.trim())
|
||||||
SearchAppBarComposable(
|
coroutineScope.launch { searchBarState.animateToCollapsed() }
|
||||||
onNavigateUp = onNavigateUp,
|
onSearch(textFieldState.text.toString())
|
||||||
actions = { if (!packages.isNullOrEmpty()) SetupMenu() },
|
}
|
||||||
searchHint = R.string.search_hint,
|
|
||||||
onSearch = { query -> onSearch(query) }
|
@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(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import androidx.compose.ui.res.dimensionResource
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringArrayResource
|
import androidx.compose.ui.res.stringArrayResource
|
||||||
import androidx.compose.ui.res.stringResource
|
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.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.PreviewScreenSizes
|
import androidx.compose.ui.tooling.preview.PreviewScreenSizes
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
@@ -142,7 +143,13 @@ private fun ScreenContent(
|
|||||||
searchBarState = searchBarState,
|
searchBarState = searchBarState,
|
||||||
textFieldState = textFieldState,
|
textFieldState = textFieldState,
|
||||||
onSearch = { query -> onRequestSearch(query) },
|
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 = {
|
leadingIcon = {
|
||||||
IconButton(onClick = onNavigateUp) {
|
IconButton(onClick = onNavigateUp) {
|
||||||
Icon(
|
Icon(
|
||||||
|
|||||||
Reference in New Issue
Block a user