实现 filter() 方法,该方法接收来自 AppListViewModel 的、已经经过“显示/隐藏系统应用”初步过滤的应用列表,然后根据 Spinner 的当前选定 option 来进一步筛选这些应用。
AppListPage.kt - 页面结构和选项菜单状态管理
// AppListPage.kt
@Composable
fun
// ...
listModel: AppListModel
// ...
appList: @Composable AppListInput
) {
var showSystem by rememberSaveable { mutableStateOf(false) } // 选项菜单控制的状态
SearchScaffold(
title = title,
actions = {
if (!noMoreOptions) {
MoreOptionsAction { // 右上角三个点菜单
ShowSystemAction(showSystem) { showSystem = it } // 切换 showSystem 状态
moreOptions()
}
}
},
) { /* ... */
UserProfilePager { userGroup ->
val appListInput = AppListInput( // 将状态和模型打包
// ...
listModel = listModel, // 来自 AllAppList.kt
state = AppListState(
showSystem = { showSystem }, // 传递选项菜单的状态
searchQuery = searchQuery,
),
// ...
)
appList(appListInput) // 调用 AppList.kt 中的 AppList()
}
}
}
组成: AppListPage 创建了 showSystem 状态,并将其与 listModel (来自 AllAppList.kt) 打包到 AppListInput 中,传递给 AppList.kt。
AppList.kt - 连接 UI 和 ViewModel
// AppList.kt
@Composable
internal fun
viewModelSupplier: @Composable () -> IAppListViewModel
) {
val viewModel = viewModelSupplier() // 获取 ViewModel 实例
Column {
val optionsState = viewModel.spinnerOptionsFlow.collectAsStateWithLifecycle(null)
SpinnerOptions(optionsState, viewModel.optionFlow) // 渲染 Spinner
val appListData = viewModel.appListDataFlow.collectAsStateWithLifecycle(null)
listModel.AppListWidget(appListData, /*...*/) // 渲染列表项, listModel 来自 AppListInput
}
}
@Composable
private fun
config: AppListConfig,
listModel: AppListModel
state: AppListState, // 接收来自 AppListPage 的 AppListInput.state
): AppListViewModel
val viewModel: AppListViewModel
// ...
viewModel.listModel.setIfAbsent(listModel) // 将 AllAppListModel 设给 ViewModel
viewModel.showSystem.Sync(state.showSystem) // **核心**: 同步选项菜单的 showSystem 状态到 ViewModel
viewModel.searchQuery.Sync(state.searchQuery) // 同步搜索词
// ...
return viewModel
}
组成: AppList.kt 从 AppListInput 中获取 state 和 listModel。它初始化 AppListViewModel,并将 state.showSystem 和 listModel (即 AllAppListModel) 设置给 ViewModel。然后它观察 ViewModel 的数据流来更新 UI。
AppListViewModel.kt - 核心过滤逻辑
// AppListViewModel.kt (内部类 UserSubGraph)
private inner class UserSubGraph(/* ... */) {
// ...
val recordListFlow = listModel.flow // listModel 是 AllAppListModel
.flatMapLatest { it.transform(userIdFlow, appsStateFlow.filterNotNull()) }
// ...
private val systemFilteredFlow = // **第一层过滤:基于选项菜单的 showSystem**
appListRepository.showSystemPredicate(userIdFlow, this@AppListViewModelImpl.showSystem.flow) // this.showSystem 来自 AppList.kt 同步过来的选项菜单状态
.combine(recordListFlow) { showAppPredicate, recordList ->
// --- Logging modification by AI Assistant --- (这是我们加的,可以忽略)
println("[AppListViewModel][systemFilteredFlow] OptionsMenu showSystem state: ${this@AppListViewModelImpl.showSystem.flow.value}") // 示例日志
// --------------------------------------------
recordList.filter { record -> // 对原始列表进行过滤
val appInfo = record.app
// 对于通用流程,这里是:
showAppPredicate(appInfo) // 使用 AppListRepository 提供的标准谓词
}
}
// ...
val listModelFilteredFlow = optionFlow.filterNotNull().flatMapLatest { option -> // option 是 Spinner 的当前选项
listModel.flow.flatMapLatest { listModel -> // listModel 是 AllAppListModel
// **第二层过滤:基于 Spinner 选项**
listModel.filter(this.userIdFlow, option, this.systemFilteredFlow) // 调用 AllAppListModel.filter,传入上一阶段已过滤的 systemFilteredFlow
}
}
// ...
}
// ViewModel 主类中
override val appListDataFlow = // 最终暴露给 UI 的数据流
combine(
appEntryListFlow, // 它基于 listModelFilteredFlow (已包含两层过滤)
// ...
) { /* ... */ }
.combine(searchQuery.flow) { appListData, searchQuery -> // **第三层过滤:基于搜索词**
appListData.filter {
it.label.contains(other = searchQuery, ignoreCase = true)
}
}
// ...
组成: AppListViewModel 接收同步过来的 showSystem 状态。在 systemFilteredFlow 中,它使用这个状态和 AppListRepository 的逻辑进行第一次过滤。然后,它将这个结果 (systemFilteredFlow) 和当前的 Spinner option 传递给 listModel.filter() (即 AllAppListModel.filter) 进行第二次过滤。最后,应用搜索词过滤。
AllAppList.kt - 定义 Spinner 行为
// AllAppList.kt (class AllAppListModel)
override fun filter(
userIdFlow: Flow
option: Int, // 当前 Spinner 选项
recordListFlow: Flow>, // **注意**: 这里的 recordListFlow 是 AppListViewModel 中已经经过 systemFilteredFlow 处理的列表
): Flow> = recordListFlow.filterItem { record ->
val app = record.app
val selectedOption = SpinnerItem.entries.getOrNull(option)
// --- Logging modification by AI Assistant --- (这是我们加的,可以忽略)
// println("[AllAppListFilter-Reverted] Processing app: ${app.packageName}, Spinner Option: $selectedOption")
// --------------------------------------------
// 只根据 Spinner 选项进行基本过滤
when (selectedOption) {
SpinnerItem.Enabled -> app.enabled && !app.isInstantApp
SpinnerItem.Disabled -> isDisabled(record)
SpinnerItem.Instant -> isInstant(record)
else -> true // 包括 SpinnerItem.All (全部应用)
}
}
组成: AllAppListModel 的 filter 方法接收 AppListViewModel 传递过来的、已经根据“选项菜单”状态过滤过的应用列表。然后,它纯粹根据当前的 Spinner 选项 (option) 对这个列表执行进一步的筛选。
总结:
这四个文件形成了一个清晰的分层结构: