diff --git a/android/app/src/main/java/github/tornaco/android/thanos/process/v2/AppSetFilterItem.kt b/android/app/src/main/java/github/tornaco/android/thanos/process/v2/AppSetFilterItem.kt index 0eeea1f2e..a905639b6 100644 --- a/android/app/src/main/java/github/tornaco/android/thanos/process/v2/AppSetFilterItem.kt +++ b/android/app/src/main/java/github/tornaco/android/thanos/process/v2/AppSetFilterItem.kt @@ -17,7 +17,34 @@ package github.tornaco.android.thanos.process.v2 +import android.content.Context +import github.tornaco.android.thanos.core.app.ThanosManager +import github.tornaco.android.thanos.core.pm.PackageSet import github.tornaco.android.thanos.module.compose.common.widget.FilterItem +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext data class AppSetFilterItem(override val label: String, override val isSelected: Boolean) : - FilterItem \ No newline at end of file + FilterItem + + +object Loader { + suspend fun loadAllFromAppSet( + context: Context, + selection: ((PackageSet) -> Boolean)? = null + ): List { + val thanos = ThanosManager.from(context) + return withContext(Dispatchers.IO) { + if (!thanos.isServiceInstalled) { + emptyList() + } else { + thanos.pkgManager.getAllPackageSets(false).mapIndexed { index, packageSet -> + AppSetFilterItem( + packageSet.label, + if (selection == null) index == 0 else selection(packageSet) + ) + } + } + } + } +} \ No newline at end of file diff --git a/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageScreen.kt b/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageScreen.kt index fccb4b663..26d946c93 100644 --- a/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageScreen.kt +++ b/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageScreen.kt @@ -24,6 +24,8 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.FilterAlt import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.* import androidx.compose.runtime.* @@ -93,44 +95,61 @@ fun ProcessManageScreen( ) } ) { - RunningAppList(state, contentPadding) + RunningAppList(state, contentPadding) { + viewModel.onFilterItemSelected(it) + } } } } @Composable -fun AppFilterDropDown() { +fun AppFilterDropDown(state: ProcessManageState, onFilterItemSelected: (AppSetFilterItem) -> Unit) { FilterDropDown( - allItems = listOf( - AppSetFilterItem("System", false), - AppSetFilterItem("Installed", true), - AppSetFilterItem("Media provider", false), - ) + icon = Icons.Filled.FilterAlt, + allItems = state.appFilterItems, + onItemSelected = onFilterItemSelected ) } @OptIn(ExperimentalFoundationApi::class) @Composable -fun RunningAppList(state: ProcessManageState, contentPadding: PaddingValues) { +fun RunningAppList( + state: ProcessManageState, + contentPadding: PaddingValues, + onFilterItemSelected: (AppSetFilterItem) -> Unit +) { LazyColumn( contentPadding = contentPadding, modifier = Modifier .background(color = MaterialTheme.colorScheme.surface) .fillMaxSize() ) { - items(state.runningAppStates) { - RunningAppItem(it) - } - item { - Spacer( + Row( modifier = Modifier - .size(24.dp) - ) + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + AppFilterDropDown(state, onFilterItemSelected) + Spacer(modifier = Modifier.size(16.dp)) + } + } + + if (state.runningAppStates.isNotEmpty()) { + item { GroupHeader(false, state.runningAppStates.size) } + items(state.runningAppStates) { + RunningAppItem(it) + } } - items(state.runningAppStatesBg) { - RunningAppItem(it) + if (state.runningAppStatesBg.isNotEmpty()) { + item { + Spacer(modifier = Modifier.size(24.dp)) + } + item { GroupHeader(true, state.runningAppStatesBg.size) } + items(state.runningAppStatesBg) { + RunningAppItem(it) + } } } } @@ -149,7 +168,7 @@ fun GroupHeader(isTotallyCached: Boolean, itemCount: Int) { else stringResource(id = R.string.running_process_running) Text( text = "$text $itemCount", - style = MaterialTheme.typography.headlineSmall + style = MaterialTheme.typography.titleMedium ) } } diff --git a/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageState.kt b/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageState.kt index 1660023b0..8168f9c65 100644 --- a/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageState.kt +++ b/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageState.kt @@ -3,5 +3,6 @@ package github.tornaco.android.thanos.process.v2 data class ProcessManageState( val isLoading: Boolean, val runningAppStates: List, - val runningAppStatesBg: List + val runningAppStatesBg: List, + val appFilterItems: List ) diff --git a/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageViewModel.kt b/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageViewModel.kt index 38ad49c11..77908eb4c 100644 --- a/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageViewModel.kt +++ b/android/app/src/main/java/github/tornaco/android/thanos/process/v2/ProcessManageViewModel.kt @@ -21,7 +21,8 @@ import javax.inject.Inject @HiltViewModel class ProcessManageViewModel @Inject constructor(@ApplicationContext private val context: Context) : ViewModel() { - private val _state = MutableStateFlow(ProcessManageState(true, emptyList(), emptyList())) + private val _state = + MutableStateFlow(ProcessManageState(true, emptyList(), emptyList(), emptyList())) val state = _state.asStateFlow() private val thanox by lazy { ThanosManager.from(context) } @@ -61,14 +62,21 @@ class ProcessManageViewModel @Inject constructor(@ApplicationContext private val val runningAppStatesGroupByCached = runningAppStates.groupBy { it.allProcessIsCached } XLog.d("startLoading: %s", runningAppStatesGroupByCached) + val appFilterListItems = Loader.loadAllFromAppSet(context) + _state.value = _state.value.copy( isLoading = false, runningAppStates = runningAppStatesGroupByCached[false] ?: emptyList(), - runningAppStatesBg = runningAppStatesGroupByCached[true] ?: emptyList() + runningAppStatesBg = runningAppStatesGroupByCached[true] ?: emptyList(), + appFilterItems = appFilterListItems ) } private fun updateLoadingState(isLoading: Boolean) { _state.value = _state.value.copy(isLoading = isLoading) } + + fun onFilterItemSelected(it: AppSetFilterItem) { + + } } \ No newline at end of file diff --git a/android/internal/Thanox-Internal b/android/internal/Thanox-Internal index b0c506b0f..762e99865 160000 --- a/android/internal/Thanox-Internal +++ b/android/internal/Thanox-Internal @@ -1 +1 @@ -Subproject commit b0c506b0f1e514f72e82f539e5cf60bb46e7e1ac +Subproject commit 762e998658d64d4b1862d7e249fcc3d2ec18ebfa diff --git a/android/modules/module_compose_common/src/main/java/github/tornaco/android/thanos/module/compose/common/widget/FilterDropDown.kt b/android/modules/module_compose_common/src/main/java/github/tornaco/android/thanos/module/compose/common/widget/FilterDropDown.kt index 5e4545d5c..64ed41085 100644 --- a/android/modules/module_compose_common/src/main/java/github/tornaco/android/thanos/module/compose/common/widget/FilterDropDown.kt +++ b/android/modules/module_compose_common/src/main/java/github/tornaco/android/thanos/module/compose/common/widget/FilterDropDown.kt @@ -19,19 +19,17 @@ package github.tornaco.android.thanos.module.compose.common.widget import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem -import androidx.compose.material3.FilledTonalButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp -import github.tornaco.android.thanos.module.compose.common.theme.ColorDefaults interface FilterItem { val label: String @@ -41,33 +39,44 @@ interface FilterItem { @Composable fun FilterDropDown( + icon: ImageVector? = null, allItems: List, onItemSelected: (T) -> Unit = {}, ) { - var expanded by remember { mutableStateOf(false) } - val selectedItem = allItems.find { it.isSelected } - requireNotNull(selectedItem) { "At least 1 selected item required." } - Box( - modifier = Modifier - .background(ColorDefaults.backgroundSurfaceColor()) - .fillMaxWidth() - .padding(8.dp) - .wrapContentSize(Alignment.TopStart) - ) { - FilledTonalButton(onClick = { expanded = true }) { - Text(text = selectedItem.label) - } - DropdownMenu( - modifier = Modifier.background(MaterialTheme.colorScheme.surface), - expanded = expanded, - onDismissRequest = { expanded = false } + if (allItems.isNotEmpty()) { + Box( + modifier = Modifier.wrapContentSize(Alignment.TopStart) ) { - allItems.forEach { item -> - DropdownMenuItem(onClick = { - onItemSelected(item) - expanded = false - }) { - Text(text = item.label) + var expanded by remember { mutableStateOf(false) } + val selectedItem = allItems.find { it.isSelected } + requireNotNull(selectedItem) { "At least 1 selected item required." } + FilledTonalButton( + onClick = { expanded = true }) { + icon?.let { + Icon( + it, + contentDescription = "FilterDropDown", + modifier = Modifier.size(ButtonDefaults.IconSize) + ) + Spacer(Modifier.size(4.dp)) + } + Text( + text = selectedItem.label, + style = MaterialTheme.typography.labelLarge + ) + } + DropdownMenu( + modifier = Modifier.background(MaterialTheme.colorScheme.surface), + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + allItems.forEach { item -> + DropdownMenuItem(onClick = { + onItemSelected(item) + expanded = false + }) { + Text(text = item.label) + } } } } diff --git a/android/modules/module_compose_common/src/main/java/github/tornaco/android/thanos/module/compose/common/widget/ThanoxScaffold.kt b/android/modules/module_compose_common/src/main/java/github/tornaco/android/thanos/module/compose/common/widget/ThanoxScaffold.kt index 4e838ebf1..3a2cacff3 100644 --- a/android/modules/module_compose_common/src/main/java/github/tornaco/android/thanos/module/compose/common/widget/ThanoxScaffold.kt +++ b/android/modules/module_compose_common/src/main/java/github/tornaco/android/thanos/module/compose/common/widget/ThanoxScaffold.kt @@ -80,7 +80,7 @@ private fun ThanoxSmallTopAppBar( scrolledContainerColor = Color.Transparent ) Surface(color = backgroundColor) { - SmallTopAppBar( + MediumTopAppBar( colors = foregroundColors, modifier = Modifier .padding(