compose: search: Switch to new AppBarWithSearch API
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -6,7 +6,6 @@
|
|||||||
package com.aurora.store.compose.ui.details
|
package com.aurora.store.compose.ui.details
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@@ -17,9 +16,7 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
|
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.VerticalDragHandle
|
|
||||||
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
|
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
|
||||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||||
import androidx.compose.material3.adaptive.layout.AdaptStrategy
|
import androidx.compose.material3.adaptive.layout.AdaptStrategy
|
||||||
@@ -34,7 +31,6 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
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.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -137,7 +133,7 @@ fun AppDetailsScreen(
|
|||||||
context.startActivity(
|
context.startActivity(
|
||||||
PackageUtil.getLaunchIntent(context, packageName)
|
PackageUtil.getLaunchIntent(context, packageName)
|
||||||
)
|
)
|
||||||
} catch (exception: ActivityNotFoundException) {
|
} catch (_: ActivityNotFoundException) {
|
||||||
context.toast(context.getString(R.string.unable_to_open))
|
context.toast(context.getString(R.string.unable_to_open))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -471,16 +467,6 @@ private fun ScreenContentApp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
paneExpansionDragHandle = { state ->
|
|
||||||
VerticalDragHandle(
|
|
||||||
modifier = Modifier.paneExpansionDraggable(
|
|
||||||
state = state,
|
|
||||||
minTouchTargetSize = LocalMinimumInteractiveComponentSize.current,
|
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
|
||||||
),
|
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,29 +8,32 @@ package com.aurora.store.compose.ui.search
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
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.material3.DockedSearchBar
|
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.ExpandedDockedSearchBar
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SearchBarDefaults
|
import androidx.compose.material3.SearchBarDefaults
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.adaptive.layout.AnimatedPane
|
import androidx.compose.material3.adaptive.layout.AnimatedPane
|
||||||
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
|
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
|
||||||
import androidx.compose.material3.adaptive.navigation.NavigableListDetailPaneScaffold
|
import androidx.compose.material3.adaptive.navigation.NavigableListDetailPaneScaffold
|
||||||
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
|
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
|
||||||
|
import androidx.compose.material3.rememberSearchBarState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
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.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.dimensionResource
|
import androidx.compose.ui.res.dimensionResource
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -56,6 +59,7 @@ import com.aurora.store.compose.preview.coilPreviewProvider
|
|||||||
import com.aurora.store.compose.ui.details.AppDetailsScreen
|
import com.aurora.store.compose.ui.details.AppDetailsScreen
|
||||||
import com.aurora.store.viewmodel.search.SearchViewModel
|
import com.aurora.store.viewmodel.search.SearchViewModel
|
||||||
import kotlinx.coroutines.android.awaitFrame
|
import kotlinx.coroutines.android.awaitFrame
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
@@ -82,18 +86,24 @@ private fun ScreenContent(
|
|||||||
onFetchSuggestions: (String) -> Unit = {},
|
onFetchSuggestions: (String) -> Unit = {},
|
||||||
onSearch: (String) -> Unit = {}
|
onSearch: (String) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
var currentQuery by rememberSaveable { mutableStateOf("") }
|
val textFieldState = rememberTextFieldState()
|
||||||
var isExpanded by rememberSaveable { mutableStateOf(true) }
|
val searchBarState = rememberSearchBarState()
|
||||||
|
val scrollBehavior = SearchBarDefaults.enterAlwaysSearchBarScrollBehavior()
|
||||||
|
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator<String>()
|
val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator<String>()
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
LaunchedEffect(focusRequester) {
|
LaunchedEffect(key1 = focusRequester) {
|
||||||
awaitFrame()
|
awaitFrame()
|
||||||
focusRequester.requestFocus()
|
focusRequester.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = textFieldState) {
|
||||||
|
snapshotFlow { textFieldState.text.toString() }
|
||||||
|
.collectLatest { query -> onFetchSuggestions(query) }
|
||||||
|
}
|
||||||
|
|
||||||
fun closeDetailPane() {
|
fun closeDetailPane() {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail, null)
|
scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail, null)
|
||||||
@@ -106,57 +116,54 @@ private fun ScreenContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRequestSuggestions(query: String) {
|
|
||||||
currentQuery = query.trim()
|
|
||||||
onFetchSuggestions(query.trim())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onRequestSearch(query: String) {
|
fun onRequestSearch(query: String) {
|
||||||
currentQuery = query.trim()
|
textFieldState.setTextAndPlaceCursorAtEnd(query.trim())
|
||||||
isExpanded = false
|
coroutineScope.launch { searchBarState.animateToCollapsed() }
|
||||||
onSearch(query.trim())
|
onSearch(textFieldState.text.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SearchBar() {
|
fun SearchBar() {
|
||||||
DockedSearchBar(
|
val inputField = @Composable {
|
||||||
expanded = isExpanded,
|
SearchBarDefaults.InputField(
|
||||||
onExpandedChange = { expanded -> isExpanded = expanded },
|
modifier = Modifier.focusRequester(focusRequester),
|
||||||
inputField = {
|
searchBarState = searchBarState,
|
||||||
SearchBarDefaults.InputField(
|
textFieldState = textFieldState,
|
||||||
modifier = Modifier.focusRequester(focusRequester),
|
onSearch = { query -> onRequestSearch(query) },
|
||||||
query = currentQuery,
|
placeholder = { Text(text = stringResource(R.string.search_hint)) },
|
||||||
onQueryChange = { query -> onRequestSuggestions(query) },
|
leadingIcon = {
|
||||||
onSearch = { query -> onRequestSearch(query) },
|
IconButton(onClick = onNavigateUp) {
|
||||||
expanded = isExpanded,
|
Icon(
|
||||||
onExpandedChange = { expanded -> isExpanded = expanded },
|
painter = painterResource(R.drawable.ic_arrow_back),
|
||||||
leadingIcon = {
|
contentDescription = stringResource(R.string.action_back)
|
||||||
IconButton(onClick = onNavigateUp) {
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
if (textFieldState.text.isNotBlank()) {
|
||||||
|
IconButton(onClick = { textFieldState.clearText() }) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(R.drawable.ic_arrow_back),
|
painter = painterResource(R.drawable.ic_cancel),
|
||||||
contentDescription = stringResource(R.string.action_back)
|
contentDescription = stringResource(R.string.action_clear)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
trailingIcon = {
|
}
|
||||||
if (currentQuery.isNotBlank() && isExpanded) {
|
)
|
||||||
IconButton(onClick = { currentQuery = "" }) {
|
}
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_cancel),
|
AppBarWithSearch(
|
||||||
contentDescription = stringResource(R.string.action_clear)
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
state = searchBarState,
|
||||||
}
|
inputField = inputField
|
||||||
}
|
)
|
||||||
},
|
|
||||||
placeholder = { Text(text = stringResource(R.string.search_hint)) }
|
ExpandedDockedSearchBar(state = searchBarState, inputField = inputField) {
|
||||||
)
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
suggestions.forEach { suggestion ->
|
suggestions.forEach { suggestion ->
|
||||||
SearchSuggestionComposable(
|
SearchSuggestionComposable(
|
||||||
searchSuggestEntry = suggestion,
|
searchSuggestEntry = suggestion,
|
||||||
onClick = { query -> onRequestSearch(query) },
|
onClick = { query -> onRequestSearch(query) },
|
||||||
onAction = { query -> currentQuery = query.trim() }
|
onAction = { query -> textFieldState.setTextAndPlaceCursorAtEnd(query.trim()) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,9 +172,8 @@ private fun ScreenContent(
|
|||||||
@Composable
|
@Composable
|
||||||
fun ListPane() {
|
fun ListPane() {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
TopAppBar(title = { SearchBar() })
|
topBar = { SearchBar() }
|
||||||
}
|
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
when (results.loadState.refresh) {
|
when (results.loadState.refresh) {
|
||||||
is LoadState.Loading -> ProgressComposable()
|
is LoadState.Loading -> ProgressComposable()
|
||||||
@@ -214,7 +220,7 @@ private fun ScreenContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
if (currentQuery.isNotBlank() && results.itemCount > 0) {
|
if (textFieldState.text.isNotBlank() && results.itemCount > 0) {
|
||||||
ErrorComposable(
|
ErrorComposable(
|
||||||
icon = R.drawable.ic_round_search,
|
icon = R.drawable.ic_round_search,
|
||||||
message = R.string.select_app_for_details
|
message = R.string.select_app_for_details
|
||||||
|
|||||||
Reference in New Issue
Block a user