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.rememberScrollState
11+ import androidx.compose.foundation.text.input.rememberTextFieldState
12+ import androidx.compose.foundation.verticalScroll
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 ) {
3446 Text (text = text, color = MaterialTheme .colorScheme.onSurface, 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,19 +68,28 @@ 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.primaryContainer,
87+ titleContentColor = MaterialTheme .colorScheme.onPrimaryContainer,
88+ actionIconContentColor = MaterialTheme .colorScheme.onPrimaryContainer
89+ ),
90+ navigationIcon = {
91+ onNavigateBack?.let { NavigationIcon (onNavigateBack) }
92+ },
6993 actions = {
7094 actions()
7195 if (hasSearch) {
@@ -80,33 +104,62 @@ fun Toolbar(
80104 }
81105 )
82106 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- }
107+ Box (
108+ modifier
109+ .fillMaxSize()
110+ .semantics { isTraversalGroup = true }
94111 ) {
95- onSearchQueryChange?.invoke(query)?.takeIf { it.isNotEmpty() }
96- ?.map { suggestionText -> SearchSuggestionItem (text = suggestionText) }
97- ? : run {
112+ SearchBar (
113+ modifier = Modifier
114+ .align(Alignment .TopCenter )
115+ .semantics { traversalIndex = 0f },
116+ inputField = {
117+ SearchBarDefaults .InputField (
118+ query = textFieldState.text.toString(),
119+ onQueryChange = { textFieldState.edit { replace(0 , length, it) } },
120+ onSearch = {
121+ onSearch(textFieldState.text.toString())
122+ expanded = false
123+ },
124+ expanded = expanded,
125+ onExpandedChange = { expanded = it },
126+ placeholder = { Text (text = stringResource(id = R .string.search)) },
127+ modifier = Modifier .padding(horizontal = SpacingExtraSmall )
128+ )
129+ },
130+ expanded = expanded,
131+ onExpandedChange = { expanded = it },
132+ ) {
133+ if (searchResults.isEmpty()) {
98134 Box (
99135 modifier = Modifier
100- .fillMaxHeight ()
101- .fillMaxWidth( ),
102- contentAlignment = Alignment .Center
136+ .fillMaxSize ()
137+ .padding( SpacingExtraSmall ),
138+ contentAlignment = Alignment .Center ,
103139 ) {
104140 Column {
105141 Text (text = " ╰(°●°╰)" )
106142 Text (text = stringResource(id = R .string.search_no_results))
107143 }
108144 }
145+ } else {
146+ Column (Modifier .verticalScroll(rememberScrollState())) {
147+ searchResults.forEach { result ->
148+ ListItem (
149+ headlineContent = {
150+ SearchSuggestionItem (result)
151+ },
152+ modifier = Modifier
153+ .clickable {
154+ textFieldState.edit { replace(0 , length, result) }
155+ expanded = false
156+ }
157+ .fillMaxWidth()
158+ )
159+ }
160+ }
109161 }
162+ }
110163 }
111164 }
112165 }
@@ -119,7 +172,8 @@ fun ToolbarPreview() {
119172 Toolbar (
120173 title = " Title" ,
121174 hasSearch = true ,
122- onSearchQueryChange = { emptyList() },
175+ onSearch = {},
176+ searchResults = emptyList(),
123177 actions = {
124178 TextAction (text = " Action1" )
125179 TextAction (text = " Action2" )
0 commit comments