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

Commit 85694cab authored by Danny Burakov's avatar Danny Burakov Committed by Android (Google) Code Review
Browse files

Merge "[flexiglass] Implement dual shade Shade Header chips" into main

parents 0722b663 c5d2ffd5
Loading
Loading
Loading
Loading
+21 −15
Original line number Diff line number Diff line
@@ -41,9 +41,10 @@ import com.android.systemui.res.R
import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.ui.composable.Overlay
import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.composable.OverlayShadeHeader
import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
@@ -60,6 +61,8 @@ constructor(
    private val tintedIconManagerFactory: TintedIconManager.Factory,
    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
    private val statusBarIconController: StatusBarIconController,
    private val notificationIconContainerStatusBarViewBinder:
        NotificationIconContainerStatusBarViewBinder,
    private val shadeSession: SaveableSession,
    private val stackScrollView: Lazy<NotificationScrollView>,
    private val clockSection: DefaultClockSection,
@@ -79,7 +82,6 @@ constructor(

    @Composable
    override fun ContentScope.Content(modifier: Modifier) {

        val notificationStackPadding = dimensionResource(id = R.dimen.notification_side_paddings)

        val viewModel =
@@ -92,25 +94,28 @@ constructor(
            }

        OverlayShade(
            isShadeLayoutWide = viewModel.isShadeLayoutWide,
            panelAlignment = Alignment.TopStart,
            modifier = modifier,
            onScrimClicked = viewModel::onScrimClicked,
        ) {
            Box {
                Column {
                    if (viewModel.showHeader) {
                        val burnIn = rememberBurnIn(clockInteractor)

                        CollapsedShadeHeader(
            header = {
                OverlayShadeHeader(
                    viewModelFactory = viewModel.shadeHeaderViewModelFactory,
                    createTintedIconManager = tintedIconManagerFactory::create,
                            createBatteryMeterViewController =
                                batteryMeterViewControllerFactory::create,
                    createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
                    statusBarIconController = statusBarIconController,
                    notificationIconContainerStatusBarViewBinder =
                        notificationIconContainerStatusBarViewBinder,
                    modifier =
                        Modifier.element(NotificationsShade.Elements.StatusBar)
                            .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader),
                )
            },
        ) {
            Box {
                Column {
                    if (viewModel.showHeader) {
                        val burnIn = rememberBurnIn(clockInteractor)

                        with(clockSection) {
                            SmallClock(
@@ -126,16 +131,17 @@ constructor(
                        stackScrollView = stackScrollView.get(),
                        viewModel = placeholderViewModel,
                        maxScrimTop = { 0f },
                        shouldPunchHoleBehindScrim = false,
                        stackTopPadding = notificationStackPadding,
                        stackBottomPadding = notificationStackPadding,
                        shouldPunchHoleBehindScrim = false,
                        shouldFillMaxSize = false,
                        shouldShowScrim = false,
                        supportNestedScrolling = false,
                        modifier = Modifier.fillMaxWidth(),
                    )
                }
                // Communicates the bottom position of the drawable area within the shade to NSSL.
                // Communicates the bottom position of the drawable area within the shade to
                // NSSL.
                NotificationStackCutoffGuideline(
                    stackScrollView = stackScrollView.get(),
                    viewModel = placeholderViewModel,
+74 −42
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
@@ -49,6 +50,7 @@ import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.notifications.ui.composable.NotificationsShade
import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace
import com.android.systemui.qs.composefragment.ui.GridAnchor
import com.android.systemui.qs.flags.QsDetailedView
@@ -61,8 +63,11 @@ import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayActionsView
import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayContentViewModel
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.ui.composable.Overlay
import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.composable.OverlayShadeHeader
import com.android.systemui.shade.ui.composable.QuickSettingsOverlayHeader
import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
@@ -82,6 +87,8 @@ constructor(
    private val tintedIconManagerFactory: TintedIconManager.Factory,
    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
    private val statusBarIconController: StatusBarIconController,
    private val notificationIconContainerStatusBarViewBinder:
        NotificationIconContainerStatusBarViewBinder,
    private val notificationStackScrollView: Lazy<NotificationScrollView>,
    private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
) : Overlay {
@@ -108,12 +115,35 @@ constructor(
        // set the bounds to null when the QuickSettings overlay disappears
        DisposableEffect(Unit) { onDispose { viewModel.onPanelShapeChanged(null) } }

        Box(modifier = modifier) {
            SnoozeableHeadsUpNotificationSpace(
                stackScrollView = notificationStackScrollView.get(),
                viewModel =
                    rememberViewModel("QuickSettingsShadeOverlay") {
                        notificationsPlaceholderViewModelFactory.create()
                    },
            )
            OverlayShade(
                isShadeLayoutWide = viewModel.isShadeLayoutWide,
                panelAlignment = Alignment.TopEnd,
            modifier = modifier,
                onScrimClicked = viewModel::onScrimClicked,
                header = {
                    OverlayShadeHeader(
                        viewModelFactory = viewModel.shadeHeaderViewModelFactory,
                        createTintedIconManager = tintedIconManagerFactory::create,
                        createBatteryMeterViewController =
                            batteryMeterViewControllerFactory::create,
                        statusBarIconController = statusBarIconController,
                        notificationIconContainerStatusBarViewBinder =
                            notificationIconContainerStatusBarViewBinder,
                        modifier =
                            Modifier.element(NotificationsShade.Elements.StatusBar)
                                .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader),
                    )
                },
            ) {
            Column(
                ShadeBody(
                    viewModel = viewModel.quickSettingsContainerViewModel,
                    modifier =
                        Modifier.onPlaced { coordinates ->
                            val boundsInWindow = coordinates.boundsInWindow()
@@ -131,30 +161,23 @@ constructor(
                                    bottomRadius = panelCornerRadius,
                                )
                            viewModel.onPanelShapeChanged(shape)
                    }
            ) {
                if (viewModel.showHeader) {
                    CollapsedShadeHeader(
                        },
                    header = {
                        if (viewModel.isShadeLayoutWide) {
                            QuickSettingsOverlayHeader(
                                viewModelFactory = viewModel.shadeHeaderViewModelFactory,
                        createTintedIconManager = tintedIconManagerFactory::create,
                                createBatteryMeterViewController =
                                    batteryMeterViewControllerFactory::create,
                        statusBarIconController = statusBarIconController,
                                modifier =
                                    Modifier.padding(top = QuickSettingsShade.Dimensions.Padding),
                            )
                        }
                ShadeBody(viewModel = viewModel.quickSettingsContainerViewModel)
            }

            SnoozeableHeadsUpNotificationSpace(
                stackScrollView = notificationStackScrollView.get(),
                viewModel =
                    rememberViewModel("QuickSettingsShadeOverlay") {
                        notificationsPlaceholderViewModelFactory.create()
                    },
                )
            }
        }
    }
}

// The possible states of the `ShadeBody`.
sealed interface ShadeBodyState {
@@ -166,7 +189,11 @@ sealed interface ShadeBodyState {
}

@Composable
fun ContentScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) {
fun ContentScope.ShadeBody(
    viewModel: QuickSettingsContainerViewModel,
    modifier: Modifier = Modifier,
    header: @Composable () -> Unit,
) {
    val isEditing by viewModel.editModeViewModel.isEditing.collectAsStateWithLifecycle()
    val tileDetails =
        if (QsDetailedView.isEnabled) viewModel.detailsViewModel.activeTileDetails else null
@@ -185,16 +212,19 @@ fun ContentScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) {
                EditMode(
                    viewModel = viewModel.editModeViewModel,
                    modifier =
                        Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding),
                        modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding),
                )
            }

            ShadeBodyState.TileDetails -> {
                TileDetails(viewModel.detailsViewModel)
                TileDetails(modifier = modifier, viewModel.detailsViewModel)
            }

            else -> {
                QuickSettingsLayout(
                    viewModel = viewModel,
                    modifier = Modifier.sysuiResTag("quick_settings_panel"),
                    modifier = modifier.sysuiResTag("quick_settings_panel"),
                    header = header,
                )
            }
        }
@@ -206,6 +236,7 @@ fun ContentScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) {
fun ContentScope.QuickSettingsLayout(
    viewModel: QuickSettingsContainerViewModel,
    modifier: Modifier = Modifier,
    header: @Composable () -> Unit,
) {
    Column(
        verticalArrangement = Arrangement.spacedBy(QuickSettingsShade.Dimensions.Padding),
@@ -217,6 +248,7 @@ fun ContentScope.QuickSettingsLayout(
                bottom = QuickSettingsShade.Dimensions.Padding,
            ),
    ) {
        header()
        Toolbar(
            modifier =
                Modifier.fillMaxWidth().requiredHeight(QuickSettingsShade.Dimensions.ToolbarHeight),
+24 −4
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ package com.android.systemui.shade.ui.composable
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
@@ -57,9 +58,11 @@ import com.android.systemui.res.R
/** Renders a lightweight shade UI container, as an overlay. */
@Composable
fun ContentScope.OverlayShade(
    isShadeLayoutWide: Boolean,
    panelAlignment: Alignment,
    onScrimClicked: () -> Unit,
    modifier: Modifier = Modifier,
    header: @Composable () -> Unit,
    content: @Composable () -> Unit,
) {
    Box(modifier) {
@@ -67,13 +70,19 @@ fun ContentScope.OverlayShade(

        Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = panelAlignment) {
            Panel(
                isShadeLayoutWide = isShadeLayoutWide,
                modifier =
                    Modifier.overscroll(verticalOverscrollEffect)
                        .element(OverlayShade.Elements.Panel)
                        .panelSize(),
                header = header,
                content = content,
            )
        }

        if (isShadeLayoutWide) {
            header()
        }
    }
}

@@ -90,7 +99,12 @@ private fun ContentScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modif
}

@Composable
private fun ContentScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
private fun ContentScope.Panel(
    isShadeLayoutWide: Boolean,
    modifier: Modifier = Modifier,
    header: @Composable () -> Unit,
    content: @Composable () -> Unit,
) {
    Box(modifier = modifier.clip(OverlayShade.Shapes.RoundedCornerPanel)) {
        Spacer(
            modifier =
@@ -102,11 +116,17 @@ private fun ContentScope.Panel(modifier: Modifier = Modifier, content: @Composab
                    )
        )

        // This content is intentionally rendered as a separate element from the background in order
        // to allow for more flexibility when defining transitions.
        Column {
            if (!isShadeLayoutWide) {
                header()
            }

            // This content is intentionally rendered as a separate element from the background in
            // order to allow for more flexibility when defining transitions.
            content()
        }
    }
}

@Composable
private fun Modifier.panelSize(): Modifier {
+372 −146

File changed.

Preview size limit exceeded, changes collapsed.

+8 −7
Original line number Diff line number Diff line
@@ -6,17 +6,18 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.shadeHeaderText
import com.android.compose.theme.colorAttr
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel

@Composable
fun VariableDayDate(
    viewModel: ShadeHeaderViewModel,
    modifier: Modifier = Modifier,
) {
fun VariableDayDate(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) {
    val longerText = viewModel.longerDateText.collectAsStateWithLifecycle()
    val shorterText = viewModel.shorterDateText.collectAsStateWithLifecycle()

    val textColor =
        if (viewModel.highlightNotificationIcons) colorAttr(android.R.attr.textColorPrimaryInverse)
        else colorAttr(android.R.attr.textColorPrimary)

    Layout(
        contents =
            listOf(
@@ -24,7 +25,7 @@ fun VariableDayDate(
                    Text(
                        text = longerText.value,
                        style = MaterialTheme.typography.bodyMedium,
                        color = MaterialTheme.colorScheme.shadeHeaderText,
                        color = textColor,
                        maxLines = 1,
                    )
                },
@@ -32,7 +33,7 @@ fun VariableDayDate(
                    Text(
                        text = shorterText.value,
                        style = MaterialTheme.typography.bodyMedium,
                        color = MaterialTheme.colorScheme.shadeHeaderText,
                        color = textColor,
                        maxLines = 1,
                    )
                },
Loading