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

Commit 1761fcf9 authored by Darrell Shi's avatar Darrell Shi Committed by Android (Google) Code Review
Browse files

Merge "Reimplement CommunalHub with LazyHorizontalGrid" into main

parents 1857f387 b8a2ee16
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ systemui_compose_java_defaults {
            // except for SystemUI-core.
            // Copied from compose/features/Android.bp.
            static_libs: [
                "CommunalLayoutLib",
                "PlatformComposeCore",
                "PlatformComposeSceneTransitionLayout",

+86 −61
Original line number Diff line number Diff line
@@ -4,8 +4,14 @@ import android.appwidget.AppWidgetHostView
import android.os.Bundle
import android.util.SizeF
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
import androidx.compose.material3.Card
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@@ -13,16 +19,12 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.integerResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.android.systemui.communal.layout.ui.compose.CommunalGridLayout
import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard
import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutConfig
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.ui.model.CommunalContentUiModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.res.R

@Composable
fun CommunalHub(
@@ -34,68 +36,91 @@ fun CommunalHub(
    Box(
        modifier = modifier.fillMaxSize().background(Color.White),
    ) {
        CommunalGridLayout(
            modifier = Modifier.align(Alignment.CenterStart),
            layoutConfig =
                CommunalGridLayoutConfig(
                    gridColumnSize = dimensionResource(R.dimen.communal_grid_column_size),
                    gridGutter = dimensionResource(R.dimen.communal_grid_gutter_size),
                    gridHeight = dimensionResource(R.dimen.communal_grid_height),
                    gridColumnsPerCard = integerResource(R.integer.communal_grid_columns_per_card),
                ),
            communalCards = if (showTutorial) tutorialContent else widgetContent.map(::contentCard),
        LazyHorizontalGrid(
            modifier = modifier.height(Dimensions.GridHeight).align(Alignment.CenterStart),
            rows = GridCells.Fixed(CommunalContentSize.FULL.span),
            horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
            verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
        ) {
            if (showTutorial) {
                items(
                    count = tutorialContentSizes.size,
                    // TODO(b/308148193): a more scalable solution for unique ids.
                    key = { index -> "tutorial_$index" },
                    span = { index -> GridItemSpan(tutorialContentSizes[index].span) },
                ) { index ->
                    TutorialCard(
                        modifier =
                            Modifier.size(Dimensions.CardWidth, tutorialContentSizes[index].dp()),
                    )
                }
}

private val tutorialContent =
    listOf(
        tutorialCard(CommunalGridLayoutCard.Size.FULL),
        tutorialCard(CommunalGridLayoutCard.Size.THIRD),
        tutorialCard(CommunalGridLayoutCard.Size.THIRD),
        tutorialCard(CommunalGridLayoutCard.Size.THIRD),
        tutorialCard(CommunalGridLayoutCard.Size.HALF),
        tutorialCard(CommunalGridLayoutCard.Size.HALF),
        tutorialCard(CommunalGridLayoutCard.Size.HALF),
        tutorialCard(CommunalGridLayoutCard.Size.HALF),
            } else {
                items(
                    count = widgetContent.size,
                    key = { index -> widgetContent[index].id },
                    span = { index -> GridItemSpan(widgetContent[index].size.span) },
                ) { index ->
                    val widget = widgetContent[index]
                    ContentCard(
                        modifier = Modifier.size(Dimensions.CardWidth, widget.size.dp()),
                        model = widget,
                    )

private fun tutorialCard(size: CommunalGridLayoutCard.Size): CommunalGridLayoutCard {
    return object : CommunalGridLayoutCard() {
        override val supportedSizes = listOf(size)

        @Composable
        override fun Content(modifier: Modifier, size: SizeF) {
            Card(modifier = modifier, content = {})
                }
            }
        }
    }
}

private fun contentCard(model: CommunalContentUiModel): CommunalGridLayoutCard {
    return object : CommunalGridLayoutCard() {
        override val supportedSizes = listOf(convertToCardSize(model.size))
        override val priority = model.priority
// A placeholder for tutorial content.
@Composable
private fun TutorialCard(modifier: Modifier = Modifier) {
    Card(modifier = modifier, content = {})
}

@Composable
        override fun Content(modifier: Modifier, size: SizeF) {
private fun ContentCard(
    model: CommunalContentUiModel,
    modifier: Modifier = Modifier,
) {
    AndroidView(
        modifier = modifier,
        factory = {
            model.view.apply {
                if (this is AppWidgetHostView) {
                            updateAppWidgetSize(Bundle(), listOf(size))
                    val size = SizeF(Dimensions.CardWidth.value, model.size.dp().value)
                    updateAppWidgetSize(Bundle.EMPTY, listOf(size))
                }
            }
        },
    )
}

private fun CommunalContentSize.dp(): Dp {
    return when (this) {
        CommunalContentSize.FULL -> Dimensions.CardHeightFull
        CommunalContentSize.HALF -> Dimensions.CardHeightHalf
        CommunalContentSize.THIRD -> Dimensions.CardHeightThird
    }
}

private fun convertToCardSize(size: CommunalContentSize): CommunalGridLayoutCard.Size {
    return when (size) {
        CommunalContentSize.FULL -> CommunalGridLayoutCard.Size.FULL
        CommunalContentSize.HALF -> CommunalGridLayoutCard.Size.HALF
        CommunalContentSize.THIRD -> CommunalGridLayoutCard.Size.THIRD
    }
// Sizes for the tutorial placeholders.
private val tutorialContentSizes =
    listOf(
        CommunalContentSize.FULL,
        CommunalContentSize.THIRD,
        CommunalContentSize.THIRD,
        CommunalContentSize.THIRD,
        CommunalContentSize.HALF,
        CommunalContentSize.HALF,
        CommunalContentSize.HALF,
        CommunalContentSize.HALF,
    )

private object Dimensions {
    val CardWidth = 464.dp
    val CardHeightFull = 630.dp
    val CardHeightHalf = 307.dp
    val CardHeightThird = 199.dp
    val GridHeight = CardHeightFull
    val Spacing = 16.dp
}
+10 −5
Original line number Diff line number Diff line
@@ -16,14 +16,19 @@

package com.android.systemui.communal.shared.model

/** Supported sizes for communal content in the layout grid. */
enum class CommunalContentSize {
/**
 * Supported sizes for communal content in the layout grid.
 *
 * @param span The span of the content in a column. For example, if FULL is 6, then 3 represents
 *   HALF, 2 represents THIRD, and 1 represents SIXTH.
 */
enum class CommunalContentSize(val span: Int) {
    /** Content takes the full height of the column. */
    FULL,
    FULL(6),

    /** Content takes half of the height of the column. */
    HALF,
    HALF(3),

    /** Content takes a third of the height of the column. */
    THIRD,
    THIRD(2),
}
+2 −2
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ import com.android.systemui.communal.shared.model.CommunalContentSize
 * This model stays in the UI layer.
 */
data class CommunalContentUiModel(
    val id: String,
    val view: View,
    val size: CommunalContentSize,
    val priority: Int,
    val size: CommunalContentSize = CommunalContentSize.HALF,
)
+7 −8
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import android.appwidget.AppWidgetHost
import android.content.Context
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalTutorialInteractor
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.ui.model.CommunalContentUiModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -42,16 +41,16 @@ constructor(

    /** List of widgets to be displayed in the communal hub. */
    val widgetContent: Flow<List<CommunalContentUiModel>> =
        communalInteractor.widgetContent.map {
            it.map {
        communalInteractor.widgetContent.map { widgets ->
            widgets.map Widget@{ widget ->
                // TODO(b/306406256): As adding and removing widgets functionalities are
                // supported, cache the host views so they're not recreated each time.
                val hostView = appWidgetHost.createView(context, it.appWidgetId, it.providerInfo)
                return@map CommunalContentUiModel(
                val hostView =
                    appWidgetHost.createView(context, widget.appWidgetId, widget.providerInfo)
                return@Widget CommunalContentUiModel(
                    // TODO(b/308148193): a more scalable solution for unique ids.
                    id = "widget_${widget.appWidgetId}",
                    view = hostView,
                    priority = it.priority,
                    // All widgets have HALF size.
                    size = CommunalContentSize.HALF,
                )
            }
        }