11package com.androidvip.sysctlgui.ui.search
22
3+ import androidx.compose.animation.AnimatedContent
34import androidx.compose.animation.AnimatedVisibility
45import androidx.compose.animation.core.animateDpAsState
56import androidx.compose.animation.core.tween
67import androidx.compose.animation.expandHorizontally
7- import androidx.compose.animation.expandVertically
88import androidx.compose.animation.fadeIn
99import androidx.compose.animation.fadeOut
1010import androidx.compose.animation.shrinkHorizontally
11- import androidx.compose.animation.shrinkVertically
1211import androidx.compose.foundation.clickable
1312import androidx.compose.foundation.layout.Box
13+ import androidx.compose.foundation.layout.PaddingValues
1414import androidx.compose.foundation.layout.fillMaxSize
1515import androidx.compose.foundation.layout.fillMaxWidth
1616import androidx.compose.foundation.layout.offset
@@ -63,8 +63,8 @@ import org.koin.compose.viewmodel.koinViewModel
6363fun SearchScreen (
6464 viewModel : SearchViewModel = koinViewModel(),
6565 mainViewModel : MainViewModel = koinViewModel(),
66- onParamSelected : ( UiKernelParam ) -> Unit ,
67- onNavigateBack : () -> Unit
66+ outerScaffoldPadding : PaddingValues ,
67+ onParamSelected : (UiKernelParam ) -> Unit
6868) {
6969 val state by viewModel.uiState.collectAsStateWithLifecycle()
7070 var searchQuery by remember { mutableStateOf(" " ) }
@@ -81,29 +81,30 @@ fun SearchScreen(
8181 )
8282 }
8383
84- LaunchedEffect (viewModel.effect ) {
84+ LaunchedEffect (Unit ) {
8585 viewModel.effect.collect { effect ->
8686 when (effect) {
8787 is SearchViewEffect .EditKernelParam -> onParamSelected(effect.param)
88- SearchViewEffect .NavigateBack -> onNavigateBack()
8988 }
9089 }
9190 }
9291
9392 SearchScreenContent (
93+ outerScaffoldPadding = outerScaffoldPadding,
9494 searchQuery = searchQuery,
9595 onSearchQueryChange = {
9696 searchQuery = it
9797 viewModel.onEvent(SearchViewEvent .SearchQueryChange (it))
9898 },
9999 searchActive = searchActive,
100100 onSearchActiveChange = { searchActive = it },
101- searchHints = state.searchHints,
102- searchResults = state.searchResults,
103- onNavigateBack = { viewModel.onEvent(SearchViewEvent .BackClicked ) },
101+ state = state,
104102 onHistoryItemRemoveClicked = {
105103 viewModel.onEvent(SearchViewEvent .HistoryItemRemoveClicked (it))
106104 },
105+ onParamClicked = {
106+ viewModel.onEvent(SearchViewEvent .ParamClicked (it))
107+ },
107108 onSearch = { query ->
108109 searchActive = false
109110 viewModel.onEvent(SearchViewEvent .SearchRequested (query))
@@ -114,17 +115,18 @@ fun SearchScreen(
114115@OptIn(ExperimentalMaterial3Api ::class )
115116@Composable
116117private fun SearchScreenContent (
118+ state : SearchViewState ,
119+ outerScaffoldPadding : PaddingValues = PaddingValues (),
117120 searchQuery : String ,
118121 onSearchQueryChange : (String ) -> Unit ,
119122 searchActive : Boolean ,
120123 onSearchActiveChange : (Boolean ) -> Unit ,
121- searchHints : List <SearchHint >,
122- searchResults : List <UiKernelParam >,
123124 onHistoryItemRemoveClicked : (SearchHint ) -> Unit ,
124- onNavigateBack : () -> Unit ,
125- onSearch : (String ) -> Unit
125+ onParamClicked : (UiKernelParam ) -> Unit ,
126+ onSearch : (String ) -> Unit ,
126127) {
127128 val focusManager = LocalFocusManager .current
129+ val navHostTopPadding = outerScaffoldPadding.calculateTopPadding()
128130 val searchBarHorizontalPadding by animateDpAsState(
129131 targetValue = if (searchActive) 0 .dp else 16 .dp,
130132 label = " SearchBarHorizontalPadding" ,
@@ -137,6 +139,9 @@ private fun SearchScreenContent(
137139 )
138140
139141 Scaffold (
142+ modifier = Modifier
143+ .fillMaxSize()
144+ .offset(y = - navHostTopPadding),
140145 topBar = {
141146 val onActiveChange: (Boolean ) -> Unit = { isActive ->
142147 if (searchActive != isActive) {
@@ -157,42 +162,25 @@ private fun SearchScreenContent(
157162 onExpandedChange = onActiveChange,
158163 placeholder = { Text (" Search kernel parameters" ) },
159164 leadingIcon = {
160- AnimatedVisibility (
161- visible = searchActive,
162- enter = expandVertically() + fadeIn(),
163- exit = shrinkVertically() + fadeOut()
164- ) {
165- IconButton (onClick = {
166- focusManager.clearFocus()
167- onSearchActiveChange(false )
168- onSearchQueryChange(" " )
169- if (searchQuery.isEmpty()) {
170- onNavigateBack()
165+ AnimatedContent (
166+ targetState = searchActive,
167+ label = " SearchIconsAnimation"
168+ ) { targetSearchActive ->
169+ if (targetSearchActive) {
170+ IconButton (onClick = {
171+ focusManager.clearFocus()
172+ onSearchActiveChange(false )
173+ onSearchQueryChange(" " )
174+ }) {
175+ Icon (
176+ Icons .AutoMirrored .Rounded .ArrowBack ,
177+ contentDescription = " Back"
178+ )
171179 }
172- }) {
173- Icon (
174- Icons .AutoMirrored .Rounded .ArrowBack ,
175- contentDescription = " Back"
176- )
180+ } else {
181+ Icon (Icons .Rounded .Search , contentDescription = " Search Icon" )
177182 }
178183 }
179-
180-
181- AnimatedVisibility (
182- visible = ! searchActive,
183- enter = expandVertically(
184- animationSpec = tween(delayMillis = 200 )
185- ) + fadeIn(
186- animationSpec = tween(delayMillis = 200 )
187- ),
188- exit = shrinkVertically(
189- animationSpec = tween(durationMillis = 0 )
190- ) + fadeOut(
191- animationSpec = tween(durationMillis = 0 )
192- )
193- ) {
194- Icon (Icons .Rounded .Search , contentDescription = " Search Icon" )
195- }
196184 },
197185 trailingIcon = {
198186 AnimatedVisibility (
@@ -223,7 +211,7 @@ private fun SearchScreenContent(
223211 windowInsets = SearchBarDefaults .windowInsets,
224212 ) {
225213 SearchViewContent (
226- searchHints = searchHints,
214+ searchHints = state. searchHints,
227215 onHistoryItemRemoveClicked = onHistoryItemRemoveClicked,
228216 onSearchQueryChange = onSearchQueryChange,
229217 onSearch = onSearch,
@@ -233,12 +221,23 @@ private fun SearchScreenContent(
233221 }
234222 }
235223 ) { innerPadding ->
236- Box (modifier = Modifier .padding(innerPadding)) {
237- if (! searchActive) {
238- SearchResultsContent (searchResults, searchQuery)
224+ AnimatedContent (
225+ targetState = state.loading,
226+ modifier = Modifier
227+ .fillMaxSize()
228+ .padding(innerPadding)
229+ ) {
230+ if (it) {
231+ Box (modifier = Modifier .fillMaxSize()) {
232+ CircularProgressIndicator (modifier = Modifier .align(Alignment .Center ))
233+ }
234+ } else {
235+ SearchResultsContent (
236+ searchResults = state.searchResults,
237+ searchQuery = searchQuery,
238+ onParamClicked = onParamClicked
239+ )
239240 }
240-
241- CircularProgressIndicator (modifier = Modifier .align(Alignment .Center ))
242241 }
243242 }
244243}
@@ -268,12 +267,12 @@ private fun SearchViewContent(
268267 .padding(horizontal = 16 .dp, vertical = 12 .dp)
269268 )
270269 }
271- items(historyHints, key = { it.hint }) { hintItem ->
270+ items(historyHints, key = { " history: ${ it.hint} " }) { historyItem ->
272271 ListItem (
273272 colors = ListItemDefaults .colors(
274273 containerColor = MaterialTheme .colorScheme.surfaceContainerHigh
275274 ),
276- headlineContent = { Text (hintItem .hint) },
275+ headlineContent = { Text (historyItem .hint) },
277276 leadingContent = {
278277 Icon (
279278 painter = painterResource(R .drawable.ic_history),
@@ -282,7 +281,7 @@ private fun SearchViewContent(
282281 },
283282 trailingContent = {
284283 IconButton (
285- onClick = { onHistoryItemRemoveClicked(hintItem ) },
284+ onClick = { onHistoryItemRemoveClicked(historyItem ) },
286285 modifier = Modifier .offset(16 .dp)
287286 ) {
288287 Icon (
@@ -293,8 +292,8 @@ private fun SearchViewContent(
293292 },
294293 modifier = Modifier
295294 .clickable {
296- onSearchQueryChange(hintItem .hint)
297- onSearch(hintItem .hint)
295+ onSearchQueryChange(historyItem .hint)
296+ onSearch(historyItem .hint)
298297 onSearchActiveChange(false )
299298 }
300299 .animateItem()
@@ -317,7 +316,7 @@ private fun SearchViewContent(
317316 modifier = Modifier .padding(horizontal = 16 .dp, vertical = 12 .dp)
318317 )
319318 }
320- items(suggestionHints, key = { it.hint }) { hintItem ->
319+ items(suggestionHints, key = { " hint: ${ it.hint} " }) { hintItem ->
321320 ListItem (
322321 colors = ListItemDefaults .colors(
323322 containerColor = MaterialTheme .colorScheme.surfaceContainerHigh
@@ -351,7 +350,11 @@ private fun SearchViewContent(
351350}
352351
353352@Composable
354- private fun SearchResultsContent (searchResults : List <UiKernelParam >, searchQuery : String ) {
353+ private fun SearchResultsContent (
354+ searchResults : List <UiKernelParam >,
355+ searchQuery : String ,
356+ onParamClicked : (UiKernelParam ) -> Unit
357+ ) {
355358 if (searchResults.isNotEmpty()) {
356359 LazyColumn (
357360 modifier = Modifier
@@ -363,7 +366,7 @@ private fun SearchResultsContent(searchResults: List<UiKernelParam>, searchQuery
363366 modifier = Modifier .animateItem(),
364367 param = param,
365368 showFullName = true ,
366- onParamClicked = {}
369+ onParamClicked = onParamClicked
367370 )
368371
369372 if (index < searchResults.lastIndex) {
@@ -448,15 +451,17 @@ private fun SearchScreenPreview() {
448451 onSearchQueryChange = { searchQuery = it },
449452 searchActive = searchActive,
450453 onSearchActiveChange = { searchActive = it },
451- searchHints = searchHints,
452- searchResults = searchResults,
453- onNavigateBack = {},
454+ state = SearchViewState (
455+ searchHints = searchHints,
456+ searchResults = searchResults
457+ ),
454458 onHistoryItemRemoveClicked = { searchHints = searchHints - it },
459+ onParamClicked = {},
455460 onSearch = {
456461 searchResults = searchResults.filter {
457462 it.name.contains(searchQuery, ignoreCase = true )
458463 }
459- }
464+ },
460465 )
461466 }
462467}
0 commit comments