11package com.enaboapps.switchify.components
22
3- import androidx.compose.foundation.clickable
3+ import androidx.compose.foundation.layout.Arrangement
44import androidx.compose.foundation.layout.Column
5+ import androidx.compose.foundation.layout.Row
6+ import androidx.compose.foundation.layout.fillMaxSize
57import androidx.compose.foundation.layout.fillMaxWidth
6- import androidx.compose.foundation.layout.heightIn
78import androidx.compose.foundation.layout.padding
89import androidx.compose.foundation.lazy.LazyColumn
910import androidx.compose.foundation.lazy.items
10- import androidx.compose.material3.AlertDialog
11+ import androidx.compose.material.icons.Icons
12+ import androidx.compose.material.icons.filled.Close
13+ import androidx.compose.material.icons.filled.Search
1114import androidx.compose.material3.CircularProgressIndicator
12- import androidx.compose.material3.OutlinedTextField
15+ import androidx.compose.material3.HorizontalDivider
16+ import androidx.compose.material3.Icon
17+ import androidx.compose.material3.IconButton
18+ import androidx.compose.material3.MaterialTheme
19+ import androidx.compose.material3.Surface
1320import androidx.compose.material3.Text
14- import androidx.compose.material3.TextButton
1521import androidx.compose.runtime.Composable
1622import androidx.compose.runtime.LaunchedEffect
1723import androidx.compose.runtime.getValue
1824import androidx.compose.runtime.mutableStateOf
1925import androidx.compose.runtime.remember
2026import androidx.compose.runtime.saveable.rememberSaveable
2127import androidx.compose.runtime.setValue
28+ import androidx.compose.ui.Alignment
2229import androidx.compose.ui.Modifier
2330import androidx.compose.ui.platform.LocalContext
2431import androidx.compose.ui.res.stringResource
2532import androidx.compose.ui.unit.dp
33+ import androidx.compose.ui.window.Dialog
34+ import androidx.compose.ui.window.DialogProperties
2635import com.enaboapps.switchify.R
2736import com.enaboapps.switchify.service.utils.FavouriteAppsManager
37+ import com.enaboapps.switchify.service.utils.FavouriteAppsManager.FavouriteApp
38+
39+ internal object AppPickerFilter {
40+ fun filter (apps : List <FavouriteApp >, query : String , excludedPackages : Set <String >): List <FavouriteApp > =
41+ apps.filter { it.packageName !in excludedPackages && it.appName.contains(query.trim(), true ) }
42+ }
2843
2944@Composable
30- fun LaunchableAppPicker (onDismiss : () -> Unit , onSelect : (String ) -> Unit ) {
45+ fun LaunchableAppPicker (
46+ onDismiss : () -> Unit ,
47+ onSelect : (String ) -> Unit ,
48+ titleResId : Int = R .string.choose_app,
49+ excludedPackages : Set <String > = emptySet()
50+ ) {
3151 val context = LocalContext .current
32- var apps by remember { mutableStateOf<List <FavouriteAppsManager . FavouriteApp >? > (null ) }
52+ var apps by remember { mutableStateOf<List <FavouriteApp >? > (null ) }
3353 var query by rememberSaveable { mutableStateOf(" " ) }
3454 LaunchedEffect (context) {
3555 apps = FavouriteAppsManager (context).getAllLaunchableApps()
3656 }
37- AlertDialog (
38- onDismissRequest = onDismiss,
39- title = { Text (stringResource(R .string.choose_app)) },
40- confirmButton = {},
41- dismissButton = { TextButton (onClick = onDismiss) { Text (stringResource(android.R .string.cancel)) } },
42- text = {
43- Column {
44- OutlinedTextField (value = query, onValueChange = { query = it },
45- label = { Text (stringResource(R .string.search_apps)) }, modifier = Modifier .fillMaxWidth())
46- val matches = apps?.filter {
47- it.appName.contains(query, true ) || it.packageName.contains(query, true )
57+ val matches = remember(apps, query, excludedPackages) {
58+ apps?.let { AppPickerFilter .filter(it, query, excludedPackages) }
59+ }
60+ Dialog (onDismissRequest = onDismiss, properties = DialogProperties (usePlatformDefaultWidth = false )) {
61+ Surface (
62+ modifier = Modifier .fillMaxSize().padding(16 .dp),
63+ shape = MaterialTheme .shapes.large,
64+ tonalElevation = 6 .dp
65+ ) {
66+ Column (Modifier .fillMaxSize()) {
67+ Row (Modifier .fillMaxWidth().padding(16 .dp), verticalAlignment = Alignment .CenterVertically ) {
68+ Text (stringResource(titleResId), modifier = Modifier .weight(1f ),
69+ style = MaterialTheme .typography.titleLarge)
70+ IconButton (onClick = onDismiss) {
71+ Icon (Icons .Default .Close , contentDescription = stringResource(R .string.button_close))
72+ }
4873 }
49- if (matches == null ) CircularProgressIndicator ()
50- else if (matches.isEmpty()) Text (stringResource(R .string.no_matching_apps))
51- else LazyColumn (Modifier .heightIn(max = 400 .dp)) {
52- items(matches, key = { it.packageName }) { app ->
53- Column (Modifier .fillMaxWidth().clickable { onSelect(app.packageName) }.padding(12 .dp)) {
54- Text (app.appName)
55- Text (app.packageName)
74+ SwitchifyTextField (
75+ value = query,
76+ onValueChange = { query = it },
77+ modifier = Modifier .fillMaxWidth().padding(horizontal = 16 .dp),
78+ placeholder = { Text (stringResource(R .string.search_apps)) },
79+ leadingIcon = { Icon (Icons .Default .Search , contentDescription = null ) },
80+ singleLine = true
81+ )
82+ if (matches == null ) {
83+ Column (Modifier .fillMaxSize().padding(32 .dp),
84+ horizontalAlignment = Alignment .CenterHorizontally ,
85+ verticalArrangement = Arrangement .Center ) {
86+ CircularProgressIndicator ()
87+ }
88+ } else if (matches.isEmpty()) {
89+ Text (stringResource(R .string.no_matching_apps), modifier = Modifier .padding(24 .dp))
90+ } else {
91+ LazyColumn (Modifier .weight(1f )) {
92+ items(matches, key = { it.packageName }) { app ->
93+ AppNameRow (name = app.appName, onClick = { onSelect(app.packageName) })
94+ HorizontalDivider ()
5695 }
5796 }
5897 }
5998 }
6099 }
61- )
62- }
100+ }
101+ }
0 commit comments