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

Commit 28a5eb9d authored by tom hsu's avatar tom hsu
Browse files

[Expressive UI] Update ZeroStatePreference and AppList

 - Centralize the ZeroStatePreference UI
 - Add ZeroStatePrefence into AppList

Flag: com.android.settingslib.widget.theme.flags.is_expressive_design_enabled
Fix: b/405223277
Fix: b/405229936
Test: atest pass
Test: Visual
Change-Id: Ic6e7693a970dbc8610acec6c4cfd6f2edee9cdda
parent c6a5b344
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settingslib.spa.widget.preference
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
@@ -62,7 +63,7 @@ fun ZeroStatePreference(icon: ImageVector, text: String? = null, description: St
    val clip = remember(zeroStateShape) {
        RoundedPolygonShape(polygon = zeroStateShape)
    }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
    Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
        Box(
            modifier = Modifier
                .clip(clip)
+21 −4
Original line number Diff line number Diff line
@@ -23,12 +23,15 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Apps
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -38,6 +41,7 @@ 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.theme.isSpaExpressiveEnabled
import com.android.settingslib.spa.widget.preference.ZeroStatePreference
import com.android.settingslib.spa.widget.ui.CategoryTitle
import com.android.settingslib.spa.widget.ui.LazyCategory
import com.android.settingslib.spa.widget.ui.PlaceholderTitle
@@ -73,6 +77,13 @@ data class AppListInput<T : AppRecord>(
    val header: @Composable () -> Unit,
    val noItemMessage: String? = null,
    val bottomPadding: Dp,
    val noAppInfo: NoAppInfo = NoAppInfo(),
)

data class NoAppInfo(
    val icon: ImageVector = Icons.Filled.Apps,
    val title: Int = R.string.no_applications,
    val description: Int? = null,
)

/**
@@ -81,12 +92,13 @@ data class AppListInput<T : AppRecord>(
 * This UI element will take the remaining space on the screen to show the App List.
 */
@Composable
fun <T : AppRecord> AppListInput<T>.AppList() {
    AppListImpl { rememberViewModel(config, listModel, state) }
fun <T : AppRecord> AppListInput<T>.AppList(noAppInfo: NoAppInfo = NoAppInfo()) {
    AppListImpl(noAppInfo) { rememberViewModel(config, listModel, state) }
}

@Composable
internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
    noAppInfo: NoAppInfo = NoAppInfo(),
    viewModelSupplier: @Composable () -> IAppListViewModel<T>
) {
    LogCompositions(TAG, config.userIds.toString())
@@ -95,7 +107,7 @@ internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
        val optionsState = viewModel.spinnerOptionsFlow.collectAsStateWithLifecycle(null)
        SpinnerOptions(optionsState, viewModel.optionFlow)
        val appListData = viewModel.appListDataFlow.collectAsStateWithLifecycle(null)
        listModel.AppListWidget(appListData, header, bottomPadding, noItemMessage)
        listModel.AppListWidget(appListData, header, bottomPadding, noItemMessage, noAppInfo)
    }
}

@@ -123,13 +135,18 @@ private fun <T : AppRecord> AppListModel<T>.AppListWidget(
    header: @Composable () -> Unit,
    bottomPadding: Dp,
    noItemMessage: String?,
    noAppInfo: NoAppInfo = NoAppInfo(),
) {
    val timeMeasurer = rememberTimeMeasurer(TAG)
    appListData.value?.let { (list, option) ->
        timeMeasurer.logFirst("app list first loaded")
        if (list.isEmpty()) {
            header()
            if (isSpaExpressiveEnabled) {
                ZeroStatePreference(noAppInfo.icon, stringResource(noAppInfo.title))
            } else {
                PlaceholderTitle(noItemMessage ?: stringResource(R.string.no_applications))
            }
            return
        }
        if (isSpaExpressiveEnabled) {