11package org.schabi.newpipe.ui
22
3+ import androidx.compose.foundation.clickable
34import androidx.compose.foundation.layout.Box
45import androidx.compose.foundation.layout.Column
56import androidx.compose.foundation.layout.RowScope
6- import androidx.compose.foundation.layout.fillMaxHeight
7+ import androidx.compose.foundation.layout.fillMaxSize
78import androidx.compose.foundation.layout.fillMaxWidth
89import androidx.compose.foundation.layout.padding
10+ import androidx.compose.foundation.lazy.LazyColumn
11+ import androidx.compose.foundation.lazy.items
12+ import androidx.compose.foundation.text.input.rememberTextFieldState
913import androidx.compose.material.icons.Icons
1014import androidx.compose.material.icons.automirrored.filled.ArrowBack
1115import androidx.compose.material3.ExperimentalMaterial3Api
1216import androidx.compose.material3.Icon
1317import androidx.compose.material3.IconButton
18+ import androidx.compose.material3.ListItem
1419import androidx.compose.material3.MaterialTheme
1520import androidx.compose.material3.SearchBar
21+ import androidx.compose.material3.SearchBarDefaults
1622import androidx.compose.material3.Text
1723import androidx.compose.material3.TopAppBar
24+ import androidx.compose.material3.TopAppBarDefaults
1825import androidx.compose.runtime.Composable
1926import androidx.compose.runtime.getValue
2027import androidx.compose.runtime.mutableStateOf
2128import androidx.compose.runtime.remember
29+ import androidx.compose.runtime.saveable.rememberSaveable
2230import androidx.compose.runtime.setValue
2331import androidx.compose.ui.Alignment
2432import androidx.compose.ui.Modifier
2533import androidx.compose.ui.res.painterResource
2634import androidx.compose.ui.res.stringResource
35+ import androidx.compose.ui.semantics.isTraversalGroup
36+ import androidx.compose.ui.semantics.semantics
37+ import androidx.compose.ui.semantics.traversalIndex
2738import androidx.compose.ui.tooling.preview.Preview
2839import org.schabi.newpipe.R
2940import org.schabi.newpipe.ui.theme.AppTheme
3041import org.schabi.newpipe.ui.theme.SizeTokens
42+ import org.schabi.newpipe.ui.theme.SizeTokens.SpacingExtraSmall
3143
3244@Composable
3345fun TextAction (text : String , modifier : Modifier = Modifier ) {
34- Text (text = text, color = MaterialTheme .colorScheme.onSurface , modifier = modifier)
46+ Text (text = text, color = MaterialTheme .colorScheme.onPrimary , modifier = modifier)
3547}
3648
3749@Composable
38- fun NavigationIcon () {
39- Icon (
40- imageVector = Icons .AutoMirrored .Filled .ArrowBack , contentDescription = " Back" ,
41- modifier = Modifier .padding(horizontal = SizeTokens .SpacingExtraSmall )
42- )
50+ fun NavigationIcon (navigateBack : () -> Unit ) {
51+ IconButton (onClick = navigateBack) {
52+ Icon (
53+ imageVector = Icons .AutoMirrored .Filled .ArrowBack ,
54+ contentDescription = " Back" ,
55+ modifier = Modifier .padding(horizontal = SizeTokens .SpacingExtraSmall )
56+ )
57+ }
4358}
4459
4560@Composable
@@ -53,60 +68,95 @@ fun SearchSuggestionItem(text: String) {
5368fun Toolbar (
5469 title : String ,
5570 modifier : Modifier = Modifier ,
56- hasNavigationIcon : Boolean = true ,
71+ onNavigateBack : (() -> Unit ) ? = null ,
5772 hasSearch : Boolean = false,
58- onSearchQueryChange : ((String ) -> List <String >)? = null,
73+ onSearch : (String ) -> Unit ,
74+ searchResults : List <String >,
5975 actions : @Composable RowScope .() -> Unit = {}
6076) {
6177 var isSearchActive by remember { mutableStateOf(false ) }
62- var query by remember { mutableStateOf(" " ) }
78+ var expanded by rememberSaveable { mutableStateOf(false ) }
79+ val textFieldState = rememberTextFieldState()
6380
6481 Column {
6582 TopAppBar (
6683 title = { Text (text = title) },
6784 modifier = modifier,
68- navigationIcon = { if (hasNavigationIcon) NavigationIcon () },
85+ colors = TopAppBarDefaults .topAppBarColors(
86+ containerColor = MaterialTheme .colorScheme.primary,
87+ titleContentColor = MaterialTheme .colorScheme.onPrimary,
88+ ),
89+ navigationIcon = {
90+ onNavigateBack?.let { NavigationIcon (onNavigateBack) }
91+ },
6992 actions = {
7093 actions()
7194 if (hasSearch) {
7295 IconButton (onClick = { isSearchActive = true }) {
7396 Icon (
7497 painterResource(id = R .drawable.ic_search),
7598 contentDescription = stringResource(id = R .string.search),
76- tint = MaterialTheme .colorScheme.onSurface
99+ tint = MaterialTheme .colorScheme.onPrimary
77100 )
78101 }
79102 }
80103 }
81104 )
82105 if (isSearchActive) {
83- SearchBar (
84- query = query,
85- onQueryChange = { query = it },
86- onSearch = {},
87- placeholder = {
88- Text (text = stringResource(id = R .string.search))
89- },
90- active = true ,
91- onActiveChange = {
92- isSearchActive = it
93- }
106+ Box (
107+ modifier
108+ .fillMaxSize()
109+ .semantics { isTraversalGroup = true }
94110 ) {
95- onSearchQueryChange?.invoke(query)?.takeIf { it.isNotEmpty() }
96- ?.map { suggestionText -> SearchSuggestionItem (text = suggestionText) }
97- ? : run {
111+ SearchBar (
112+ modifier = Modifier
113+ .align(Alignment .TopCenter )
114+ .semantics { traversalIndex = 0f },
115+ inputField = {
116+ SearchBarDefaults .InputField (
117+ query = textFieldState.text.toString(),
118+ onQueryChange = { textFieldState.edit { replace(0 , length, it) } },
119+ onSearch = {
120+ onSearch(textFieldState.text.toString())
121+ expanded = false
122+ },
123+ expanded = expanded,
124+ onExpandedChange = { expanded = it },
125+ placeholder = { Text (text = stringResource(id = R .string.search)) },
126+ modifier = Modifier .padding(horizontal = SpacingExtraSmall )
127+ )
128+ },
129+ expanded = expanded,
130+ onExpandedChange = { expanded = it },
131+ ) {
132+ if (searchResults.isEmpty()) {
98133 Box (
99134 modifier = Modifier
100- .fillMaxHeight ()
101- .fillMaxWidth( ),
102- contentAlignment = Alignment .Center
135+ .fillMaxSize ()
136+ .padding( SpacingExtraSmall ),
137+ contentAlignment = Alignment .Center ,
103138 ) {
104139 Column {
105140 Text (text = " ╰(°●°╰)" )
106141 Text (text = stringResource(id = R .string.search_no_results))
107142 }
108143 }
144+ } else {
145+ LazyColumn {
146+ items(searchResults) { result ->
147+ ListItem (
148+ headlineContent = { SearchSuggestionItem (result) },
149+ modifier = Modifier
150+ .clickable {
151+ textFieldState.edit { replace(0 , length, result) }
152+ expanded = false
153+ }
154+ .fillMaxWidth()
155+ )
156+ }
157+ }
109158 }
159+ }
110160 }
111161 }
112162 }
@@ -119,7 +169,8 @@ fun ToolbarPreview() {
119169 Toolbar (
120170 title = " Title" ,
121171 hasSearch = true ,
122- onSearchQueryChange = { emptyList() },
172+ onSearch = {},
173+ searchResults = emptyList(),
123174 actions = {
124175 TextAction (text = " Action1" )
125176 TextAction (text = " Action2" )
0 commit comments