Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CircularProgressIndicator
Expand All @@ -23,6 +26,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
Expand All @@ -49,6 +53,8 @@ fun SplitTunnelAppPickerView(
model: SplitTunnelAppPickerViewModel = viewModel(),
) {
val installedApps by model.installedApps.collectAsState()
val filteredApps by model.filteredApps.collectAsState()
val searchQuery by model.searchQuery.collectAsState()
val selectedPackageNames by model.selectedPackageNames.collectAsState()
val allowSelected by model.allowSelected.collectAsState()
val builtInDisallowedPackageNames: List<String> = App.get().builtInDisallowedPackageNames
Expand Down Expand Up @@ -118,6 +124,28 @@ fun SplitTunnelAppPickerView(
selectedPackageNames.count(),
))
}
item("searchBar") {
OutlinedTextField(
value = searchQuery,
onValueChange = { model.updateSearchQuery(it) },
placeholder = { Text(stringResource(R.string.search_ellipsis)) },
leadingIcon = {
Icon(Icons.Default.Search, contentDescription = null)
},
trailingIcon = {
if (searchQuery.isNotEmpty()) {
IconButton(onClick = { model.updateSearchQuery("") }) {
Icon(
Icons.Default.Close,
contentDescription = stringResource(R.string.clear_search))
}
}
},
singleLine = true,
modifier =
Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 4.dp),
)
}
if (installedApps.isEmpty()) {
item("spinner") {
Box(
Expand All @@ -132,7 +160,7 @@ fun SplitTunnelAppPickerView(
}
}
} else {
items(installedApps, key = { it.packageName }) { app ->
items(filteredApps, key = { it.packageName }) { app ->
ListItem(
headlineContent = { Text(app.name, fontWeight = FontWeight.SemiBold) },
leadingContent = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
Expand All @@ -38,6 +39,28 @@ class SplitTunnelAppPickerViewModel : ViewModel() {
)
val selectedPackageNames: StateFlow<List<String>> = MutableStateFlow(listOf())

private val _searchQuery = MutableStateFlow("")
val searchQuery: StateFlow<String> = _searchQuery

val filteredApps: StateFlow<List<InstalledApp>> =
combine(installedApps, _searchQuery) { apps, query ->
if (query.isBlank()) apps
else
apps.filter { app ->
app.name.contains(query, ignoreCase = true) ||
app.packageName.contains(query, ignoreCase = true)
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = listOf(),
)

fun updateSearchQuery(query: String) {
_searchQuery.value = query
}

val allowSelected: StateFlow<Boolean> = MutableStateFlow(App.get().allowSelectedPackages())
val showHeaderMenu: StateFlow<Boolean> = MutableStateFlow(false)
val showSwitchDialog: StateFlow<Boolean> = MutableStateFlow(false)
Expand Down