Skip to content

Commit 6614941

Browse files
committed
add search bar
1 parent e1caecd commit 6614941

File tree

1 file changed

+67
-1
lines changed
  • app/src/main/java/neth/iecal/questphone/ui/screens/launcher

1 file changed

+67
-1
lines changed

app/src/main/java/neth/iecal/questphone/ui/screens/launcher/AppList.kt

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,28 @@ import androidx.compose.foundation.layout.width
1717
import androidx.compose.foundation.lazy.LazyColumn
1818
import androidx.compose.foundation.lazy.items
1919
import androidx.compose.foundation.lazy.rememberLazyListState
20+
import androidx.compose.material.icons.Icons
21+
import androidx.compose.material.icons.filled.Clear
22+
import androidx.compose.material.icons.filled.Search
23+
import androidx.compose.material3.Icon
24+
import androidx.compose.material3.IconButton
2025
import androidx.compose.material3.MaterialTheme
26+
import androidx.compose.material3.OutlinedTextField
2127
import androidx.compose.material3.Scaffold
2228
import androidx.compose.material3.Text
2329
import androidx.compose.runtime.Composable
2430
import androidx.compose.runtime.LaunchedEffect
2531
import androidx.compose.runtime.MutableState
32+
import androidx.compose.runtime.getValue
2633
import androidx.compose.runtime.mutableStateOf
2734
import androidx.compose.runtime.remember
2835
import androidx.compose.runtime.rememberCoroutineScope
36+
import androidx.compose.runtime.setValue
2937
import androidx.compose.ui.Modifier
38+
import androidx.compose.ui.focus.FocusRequester
39+
import androidx.compose.ui.focus.focusRequester
3040
import androidx.compose.ui.platform.LocalContext
41+
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
3142
import androidx.compose.ui.text.style.TextAlign
3243
import androidx.compose.ui.unit.dp
3344
import androidx.compose.ui.unit.sp
@@ -37,6 +48,7 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
3748
import androidx.lifecycle.repeatOnLifecycle
3849
import androidx.navigation.NavController
3950
import kotlinx.coroutines.Dispatchers
51+
import kotlinx.coroutines.delay
4052
import kotlinx.coroutines.launch
4153
import kotlinx.coroutines.withContext
4254
import neth.iecal.questphone.data.AppInfo
@@ -68,6 +80,23 @@ fun AppList(navController: NavController) {
6880
val lifecycleOwner = LocalLifecycleOwner.current
6981

7082
var distractions = emptySet<String>()
83+
84+
85+
val focusRequester = remember { FocusRequester() }
86+
val keyboardController = LocalSoftwareKeyboardController.current
87+
88+
var searchQuery by remember { mutableStateOf("") }
89+
LaunchedEffect(searchQuery) {
90+
val filteredAppsListRaw = appsState.value.filter { it.name.contains(searchQuery,ignoreCase = true) }
91+
groupedAppsState.value = groupAppsByLetter(filteredAppsListRaw)
92+
}
93+
LaunchedEffect(Unit) {
94+
delay(1000)
95+
focusRequester.requestFocus()
96+
// Optional slight delay to ensure keyboard shows after focus
97+
keyboardController?.show()
98+
}
99+
71100
LaunchedEffect(lifecycleOwner) {
72101
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
73102
distractions = sp.getStringSet("distracting_apps", emptySet<String>()) ?: emptySet()
@@ -91,6 +120,9 @@ fun AppList(navController: NavController) {
91120
}
92121

93122
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
123+
124+
125+
94126
AppListWithScrollbar(
95127
groupedApps = groupedAppsState.value,
96128
isLoading = isLoading.value,
@@ -110,6 +142,37 @@ fun AppList(navController: NavController) {
110142
// Not a distraction - launch directly
111143
launchApp(context, packageName)
112144
}
145+
},
146+
searchBar = {
147+
OutlinedTextField(
148+
value = searchQuery,
149+
150+
onValueChange = { searchQuery = it },
151+
label = { Text("Search Apps") },
152+
placeholder = { Text("Type app name...") },
153+
leadingIcon = {
154+
Icon(
155+
imageVector = Icons.Default.Search,
156+
contentDescription = "Search"
157+
)
158+
},
159+
trailingIcon = {
160+
if (searchQuery.isNotEmpty()) {
161+
IconButton(onClick = { searchQuery = "" }) {
162+
Icon(
163+
imageVector = Icons.Default.Clear,
164+
contentDescription = "Clear search"
165+
)
166+
}
167+
}
168+
},
169+
modifier = Modifier
170+
.fillMaxWidth()
171+
.padding(16.dp)
172+
.focusRequester(focusRequester)
173+
,
174+
singleLine = true
175+
)
113176
}
114177
)
115178

@@ -171,7 +234,8 @@ private fun AppListWithScrollbar(
171234
isLoading: Boolean,
172235
error: String?,
173236
innerPadding: PaddingValues,
174-
onAppClick: (String) -> Unit
237+
onAppClick: (String) -> Unit,
238+
searchBar: @Composable () -> Unit
175239
) {
176240
val listState = rememberLazyListState()
177241
val coroutineScope = rememberCoroutineScope()
@@ -212,6 +276,8 @@ private fun AppListWithScrollbar(
212276
}
213277
else -> {
214278
LazyColumn(state = listState) {
279+
item { searchBar() }
280+
215281
groupedApps.forEach { group ->
216282
stickyHeader {
217283
Text(

0 commit comments

Comments
 (0)