@@ -17,17 +17,28 @@ import androidx.compose.foundation.layout.width
1717import androidx.compose.foundation.lazy.LazyColumn
1818import androidx.compose.foundation.lazy.items
1919import 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
2025import androidx.compose.material3.MaterialTheme
26+ import androidx.compose.material3.OutlinedTextField
2127import androidx.compose.material3.Scaffold
2228import androidx.compose.material3.Text
2329import androidx.compose.runtime.Composable
2430import androidx.compose.runtime.LaunchedEffect
2531import androidx.compose.runtime.MutableState
32+ import androidx.compose.runtime.getValue
2633import androidx.compose.runtime.mutableStateOf
2734import androidx.compose.runtime.remember
2835import androidx.compose.runtime.rememberCoroutineScope
36+ import androidx.compose.runtime.setValue
2937import androidx.compose.ui.Modifier
38+ import androidx.compose.ui.focus.FocusRequester
39+ import androidx.compose.ui.focus.focusRequester
3040import androidx.compose.ui.platform.LocalContext
41+ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
3142import androidx.compose.ui.text.style.TextAlign
3243import androidx.compose.ui.unit.dp
3344import androidx.compose.ui.unit.sp
@@ -37,6 +48,7 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
3748import androidx.lifecycle.repeatOnLifecycle
3849import androidx.navigation.NavController
3950import kotlinx.coroutines.Dispatchers
51+ import kotlinx.coroutines.delay
4052import kotlinx.coroutines.launch
4153import kotlinx.coroutines.withContext
4254import 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