Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25773378 authored by George Chan's avatar George Chan
Browse files

Updated AppList to allow custom message and display summary for empty list,...

Updated AppList to allow custom message and display summary for empty list, added a button appItem as part of requirements for background install control feature.

Change-Id: I3f2129e4787d3143c61377679d6b4f0c02d5133e
Test: Manually tested with Settings app
Bug: 238451991
parent e71b1d48
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.spa.widget.preference

import com.android.settingslib.spa.framework.util.EntryHighlight
import androidx.compose.material3.IconButton
import androidx.compose.runtime.State
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.material3.Icon

@Composable
fun TwoTargetButtonPreference(
        title: String,
        summary: State<String>,
        icon: @Composable (() -> Unit)? = null,
        onClick: () -> Unit,
        buttonIcon: ImageVector,
        buttonIconDescription: String,
        onButtonClick: () -> Unit
) {
    EntryHighlight {
        TwoTargetPreference(
                title = title,
                summary = summary,
                onClick = onClick,
                icon = icon) {
            IconButton(onClick = onButtonClick) {
                Icon(imageVector = buttonIcon, contentDescription = buttonIconDescription)
            }
        }
    }
}
 No newline at end of file
+73 −0
Original line number Diff line number Diff line
package com.android.settingslib.spa.widget.preference

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.compose.toState
import com.google.common.truth.Truth
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

private const val TEST_MODEL_TITLE = "TwoTargetButtonPreference"
private const val TEST_MODEL_SUMMARY = "TestSummary"
private const val TEST_BUTTON_ICON_DESCRIPTION = "TestButtonIconDescription"
private val TEST_BUTTON_ICON = Icons.Outlined.Delete

@RunWith(AndroidJUnit4::class)
class TwoTargetButtonPreferenceTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun title_displayed() {
        composeTestRule.setContent {
            testTwoTargetButtonPreference()
        }

        composeTestRule.onNodeWithText(TEST_MODEL_TITLE).assertIsDisplayed()
    }

    @Test
    fun clickable_label_canBeClicked() {
        var clicked = false
        composeTestRule.setContent {
            testTwoTargetButtonPreference(onClick = { clicked = true })
        }

        composeTestRule.onNodeWithText(TEST_MODEL_TITLE).performClick()
        Truth.assertThat(clicked).isTrue()
    }

    @Test
    fun clickable_button_label_canBeClicked() {
        var clicked = false
        composeTestRule.setContent {
            testTwoTargetButtonPreference(onButtonClick = { clicked = true })
        }

        composeTestRule.onNodeWithContentDescription(TEST_BUTTON_ICON_DESCRIPTION).performClick()
        Truth.assertThat(clicked).isTrue()
    }
}

@Composable
private fun testTwoTargetButtonPreference(
    onClick: () -> Unit = {},
    onButtonClick: () -> Unit = {},
) {
    TwoTargetButtonPreference(
        title = TEST_MODEL_TITLE,
        summary = TEST_MODEL_SUMMARY.toState(),
        onClick = onClick,
        buttonIcon = TEST_BUTTON_ICON,
        buttonIconDescription = TEST_BUTTON_ICON_DESCRIPTION,
        onButtonClick = onButtonClick
    )
}
 No newline at end of file
+6 −3
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ data class AppListInput<T : AppRecord>(
    val listModel: AppListModel<T>,
    val state: AppListState,
    val header: @Composable () -> Unit,
    val noItemMessage: String? = null,
    val bottomPadding: Dp,
)

@@ -79,7 +80,7 @@ internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
) {
    LogCompositions(TAG, config.userId.toString())
    val appListData = appListDataSupplier()
    listModel.AppListWidget(appListData, header, bottomPadding)
    listModel.AppListWidget(appListData, header, bottomPadding, noItemMessage)
}

@Composable
@@ -87,12 +88,14 @@ private fun <T : AppRecord> AppListModel<T>.AppListWidget(
    appListData: State<AppListData<T>?>,
    header: @Composable () -> Unit,
    bottomPadding: Dp,
    noItemMessage: String?
) {
    val timeMeasurer = rememberTimeMeasurer(TAG)
    appListData.value?.let { (list, option) ->
        timeMeasurer.logFirst("app list first loaded")
        if (list.isEmpty()) {
            PlaceholderTitle(stringResource(R.string.no_applications))
            header()
            PlaceholderTitle(noItemMessage ?: stringResource(R.string.no_applications))
            return
        }
        LazyColumn(
+41 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.spaprivileged.template.app

import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spa.widget.preference.TwoTargetButtonPreference

@Composable
fun <T : AppRecord> AppListItemModel<T>.AppListButtonItem (
    onClick: () -> Unit,
    onButtonClick: () -> Unit,
    buttonIcon: ImageVector,
    buttonIconDescription: String,
) {
        TwoTargetButtonPreference(
                title = label,
                summary = this@AppListButtonItem.summary,
                icon = { AppIcon(record.app, SettingsDimension.appIconItemSize) },
                onClick = onClick,
                buttonIcon = buttonIcon,
                buttonIconDescription = buttonIconDescription,
                onButtonClick = onButtonClick
        )
}
+2 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ fun <T : AppRecord> AppListPage(
    listModel: AppListModel<T>,
    showInstantApps: Boolean = false,
    primaryUserOnly: Boolean = false,
    noItemMessage: String? = null,
    moreOptions: @Composable MoreOptionsScope.() -> Unit = {},
    header: @Composable () -> Unit = {},
    appList: @Composable AppListInput<T>.() -> Unit = { AppList() },
@@ -77,6 +78,7 @@ fun <T : AppRecord> AppListPage(
                    ),
                    header = header,
                    bottomPadding = bottomPadding,
                    noItemMessage = noItemMessage,
                )
                appList(appListInput)
            }