Merge "Support grouping in the New App List"

This commit is contained in:
Chaohui Wang
2022-11-16 02:16:50 +00:00
committed by Android (Google) Code Review
3 changed files with 74 additions and 13 deletions

View File

@@ -53,6 +53,14 @@ interface AppListModel<T : AppRecord> {
{ it.record.app.uid },
)
/**
* Gets the group title of this item.
*
* Note: Items should be sorted by group in [getComparator] first, this [getGroupTitle] will not
* change the list order.
*/
fun getGroupTitle(option: Int, record: T): String? = null
/**
* Gets the summary for the given app record.
*

View File

@@ -34,9 +34,11 @@ import com.android.settingslib.spa.framework.compose.LogCompositions
import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer
import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll
import com.android.settingslib.spa.framework.compose.toState
import com.android.settingslib.spa.widget.ui.CategoryTitle
import com.android.settingslib.spa.widget.ui.PlaceholderTitle
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser
import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListConfig
import com.android.settingslib.spaprivileged.model.app.AppListData
import com.android.settingslib.spaprivileged.model.app.AppListModel
@@ -100,17 +102,28 @@ private fun <T : AppRecord> AppListWidget(
}
items(count = list.size, key = { option to list[it].record.app.packageName }) {
remember(list) { listModel.getGroupTitleIfFirst(option, list, it) }
?.let { group -> CategoryTitle(title = group) }
val appEntry = list[it]
val summary = listModel.getSummary(option, appEntry.record) ?: "".toState()
val itemModel = remember(appEntry) {
appItem(remember(appEntry) {
AppListItemModel(appEntry.record, appEntry.label, summary)
}
appItem(itemModel)
})
}
}
}
}
/** Returns group title if this is the first item of the group. */
private fun <T : AppRecord> AppListModel<T>.getGroupTitleIfFirst(
option: Int,
list: List<AppEntry<T>>,
index: Int,
): String? = getGroupTitle(option, list[index].record)?.takeIf {
index == 0 || it != getGroupTitle(option, list[index - 1].record)
}
@Composable
private fun <T : AppRecord> loadAppListData(
config: AppListConfig,

View File

@@ -58,26 +58,43 @@ class AppListTest {
@Test
fun couldShowAppItem() {
setContent(appEntries = listOf(APP_ENTRY))
setContent(appEntries = listOf(APP_ENTRY_A))
composeTestRule.onNodeWithText(APP_ENTRY.label).assertIsDisplayed()
composeTestRule.onNodeWithText(APP_ENTRY_A.label).assertIsDisplayed()
}
@Test
fun couldShowHeader() {
setContent(header = { Text(HEADER) }, appEntries = listOf(APP_ENTRY))
setContent(appEntries = listOf(APP_ENTRY_A), header = { Text(HEADER) })
composeTestRule.onNodeWithText(HEADER).assertIsDisplayed()
}
@Test
fun whenNotGrouped_groupTitleDoesNotExist() {
setContent(appEntries = listOf(APP_ENTRY_A, APP_ENTRY_B), enableGrouping = false)
composeTestRule.onNodeWithText(GROUP_A).assertDoesNotExist()
composeTestRule.onNodeWithText(GROUP_B).assertDoesNotExist()
}
@Test
fun whenGrouped_groupTitleDisplayed() {
setContent(appEntries = listOf(APP_ENTRY_A, APP_ENTRY_B), enableGrouping = true)
composeTestRule.onNodeWithText(GROUP_A).assertIsDisplayed()
composeTestRule.onNodeWithText(GROUP_B).assertIsDisplayed()
}
private fun setContent(
header: @Composable () -> Unit = {},
appEntries: List<AppEntry<TestAppRecord>>,
header: @Composable () -> Unit = {},
enableGrouping: Boolean = false,
) {
composeTestRule.setContent {
AppList(
config = AppListConfig(userId = USER_ID, showInstantApps = false),
listModel = TestAppListModel(),
listModel = TestAppListModel(enableGrouping),
state = AppListState(
showSystem = false.toState(),
option = 0.toState(),
@@ -96,17 +113,37 @@ class AppListTest {
private companion object {
const val USER_ID = 0
const val HEADER = "Header"
val APP_ENTRY = AppEntry(
record = TestAppRecord(ApplicationInfo()),
label = "AAA",
const val GROUP_A = "Group A"
const val GROUP_B = "Group B"
val APP_ENTRY_A = AppEntry(
record = TestAppRecord(
app = ApplicationInfo().apply {
packageName = "package.name.a"
},
group = GROUP_A,
),
label = "Label A",
labelCollationKey = CollationKey("", byteArrayOf()),
)
val APP_ENTRY_B = AppEntry(
record = TestAppRecord(
app = ApplicationInfo().apply {
packageName = "package.name.b"
},
group = GROUP_B,
),
label = "Label B",
labelCollationKey = CollationKey("", byteArrayOf()),
)
}
}
private data class TestAppRecord(override val app: ApplicationInfo) : AppRecord
private data class TestAppRecord(
override val app: ApplicationInfo,
val group: String? = null,
) : AppRecord
private class TestAppListModel : AppListModel<TestAppRecord> {
private class TestAppListModel(val enableGrouping: Boolean) : AppListModel<TestAppRecord> {
override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
appListFlow.asyncMapItem { TestAppRecord(it) }
@@ -118,4 +155,7 @@ private class TestAppListModel : AppListModel<TestAppRecord> {
option: Int,
recordListFlow: Flow<List<TestAppRecord>>,
) = recordListFlow
override fun getGroupTitle(option: Int, record: TestAppRecord) =
if (enableGrouping) record.group else null
}