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

Commit e30c356a authored by 0's avatar 0
Browse files

[flexiglass] Add Shade Header clock text scaling transition and click behavior

Makes the Shade Header clock a shared element that scales up during Shade -> QS transition. Also adds the onclick action for the clock (launching the clock activity)

Bug: 299141272
Test: forthcoming
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: I5108b630017464ff462fa318be4a25ab978803b0
parent d30c373b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ fun TransitionBuilder.goneToShadeTransition(
) {
    spec = tween(durationMillis = DefaultDuration.times(durationScale).inWholeMilliseconds.toInt())

    fractionRange(start = .58f) { fade(ShadeHeader.Elements.Clock) }
    fractionRange(start = .58f) { fade(ShadeHeader.Elements.CollapsedContentStart) }
    fractionRange(start = .58f) { fade(ShadeHeader.Elements.CollapsedContentEnd) }
    fractionRange(start = .58f) { fade(ShadeHeader.Elements.PrivacyChip) }
+6 −1
Original line number Diff line number Diff line
@@ -18,10 +18,15 @@ fun TransitionBuilder.shadeToQuickSettingsTransition() {
        y = ShadeHeader.Dimensions.CollapsedHeight
    )
    translate(ShadeHeader.Elements.CollapsedContentEnd, y = ShadeHeader.Dimensions.CollapsedHeight)
    translate(ShadeHeader.Elements.ExpandedContent, y = (-ShadeHeader.Dimensions.ExpandedHeight))
    translate(
        ShadeHeader.Elements.ExpandedContent,
        y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight)
    )
    translate(ShadeHeader.Elements.ShadeCarrierGroup, y = -ShadeHeader.Dimensions.CollapsedHeight)

    fractionRange(end = .14f) { fade(ShadeHeader.Elements.CollapsedContentStart) }
    fractionRange(end = .14f) { fade(ShadeHeader.Elements.CollapsedContentEnd) }

    fractionRange(start = .58f) { fade(ShadeHeader.Elements.ExpandedContent) }
    fractionRange(start = .58f) { fade(ShadeHeader.Elements.ShadeCarrierGroup) }
}
+69 −38
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.shade.ui.composable

import android.view.ContextThemeWrapper
import android.view.ViewGroup
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -52,6 +53,7 @@ import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.ValueKey
import com.android.compose.animation.scene.animateElementFloatAsState
import com.android.compose.animation.scene.animateSceneFloatAsState
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.settingslib.Utils
@@ -64,6 +66,7 @@ import com.android.systemui.res.R
import com.android.systemui.scene.ui.composable.QuickSettings
import com.android.systemui.scene.ui.composable.Shade as ShadeKey
import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight
import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
@@ -79,12 +82,18 @@ object ShadeHeader {
        val CollapsedContentStart = ElementKey("ShadeHeaderCollapsedContentStart")
        val CollapsedContentEnd = ElementKey("ShadeHeaderCollapsedContentEnd")
        val PrivacyChip = ElementKey("PrivacyChip", scenePicker = LowestZIndexScenePicker)
        val Clock = ElementKey("ShadeHeaderClock", scenePicker = LowestZIndexScenePicker)
        val ShadeCarrierGroup = ElementKey("ShadeCarrierGroup")
    }

    object Keys {
        val transitionProgress = ValueKey("ShadeHeaderTransitionProgress")
    }

    object Values {
        val ClockScale = ValueKey("ShadeHeaderClockScale")
    }

    object Dimensions {
        val CollapsedHeight = 48.dp
        val ExpandedHeight = 120.dp
@@ -121,20 +130,18 @@ fun SceneScope.CollapsedShadeHeader(
        contents =
            listOf(
                {
                    Row(modifier = Modifier.element(ShadeHeader.Elements.CollapsedContentStart)) {
                        AndroidView(
                            factory = { context ->
                    Row {
                        Clock(
                                    ContextThemeWrapper(context, R.style.TextAppearance_QS_Status),
                                    null
                                )
                            },
                            scale = 1f,
                            viewModel = viewModel,
                            modifier = Modifier.align(Alignment.CenterVertically),
                        )
                        Spacer(modifier = Modifier.width(5.dp))
                        VariableDayDate(
                            viewModel = viewModel,
                            modifier = Modifier.align(Alignment.CenterVertically),
                            modifier =
                                Modifier.element(ShadeHeader.Elements.CollapsedContentStart)
                                    .align(Alignment.CenterVertically),
                        )
                    }
                },
@@ -257,40 +264,29 @@ fun SceneScope.ExpandedShadeHeader(
        Column(
            verticalArrangement = Arrangement.Bottom,
            modifier =
                Modifier.element(ShadeHeader.Elements.ExpandedContent)
                    .fillMaxWidth()
                Modifier.fillMaxWidth()
                    .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight)
        ) {
            Row {
                AndroidView(
                    factory = { context ->
                        Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null)
                    },
                    modifier =
                        Modifier.align(Alignment.CenterVertically)
                            // use graphicsLayer instead of Modifier.scale to anchor transform to
                            // the (start, top) corner
                            .graphicsLayer(
                                scaleX = 2.57f,
                                scaleY = 2.57f,
                                transformOrigin =
                                    TransformOrigin(
                                        when (LocalLayoutDirection.current) {
                                            LayoutDirection.Ltr -> 0f
                                            LayoutDirection.Rtl -> 1f
                                        },
                                        0.5f
                                    )
                            ),
            Box(modifier = Modifier.fillMaxWidth()) {
                Box {
                    Clock(
                        scale = 2.57f,
                        viewModel = viewModel,
                        modifier = Modifier.align(Alignment.CenterStart),
                    )
                Spacer(modifier = Modifier.weight(1f))
                }
                Box(
                    modifier =
                        Modifier.element(ShadeHeader.Elements.ShadeCarrierGroup).fillMaxWidth()
                ) {
                    ShadeCarrierGroup(
                        viewModel = viewModel,
                    modifier = Modifier.align(Alignment.CenterVertically),
                        modifier = Modifier.align(Alignment.CenterEnd),
                    )
                }
            }
            Spacer(modifier = Modifier.width(5.dp))
            Row {
            Row(modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent)) {
                VariableDayDate(
                    viewModel = viewModel,
                    modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically),
@@ -318,6 +314,41 @@ fun SceneScope.ExpandedShadeHeader(
    }
}

@Composable
private fun SceneScope.Clock(
    scale: Float,
    viewModel: ShadeHeaderViewModel,
    modifier: Modifier,
) {
    val layoutDirection = LocalLayoutDirection.current

    Element(key = ShadeHeader.Elements.Clock, modifier = modifier) {
        val animatedScale by animateElementFloatAsState(scale, ClockScale, canOverflow = false)
        AndroidView(
            factory = { context ->
                Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null)
            },
            modifier =
                modifier
                    // use graphicsLayer instead of Modifier.scale to anchor transform
                    // to the (start, top) corner
                    .graphicsLayer {
                        scaleX = animatedScale
                        scaleY = animatedScale
                        transformOrigin =
                            TransformOrigin(
                                when (layoutDirection) {
                                    LayoutDirection.Ltr -> 0f
                                    LayoutDirection.Rtl -> 1f
                                },
                                0.5f
                            )
                    }
                    .clickable { viewModel.onClockClicked() }
        )
    }
}

@Composable
private fun BatteryIcon(
    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+6 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -42,6 +43,7 @@ import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.animateSceneFloatAsState
import com.android.compose.modifiers.thenIf
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -163,6 +165,7 @@ private fun SceneScope.ShadeScene(
    val maxNotifScrimTop = remember { mutableStateOf(0f) }
    val tileSquishiness by
        animateSceneFloatAsState(value = 1f, key = QuickSettings.SharedValues.TilesSquishiness)
    val isClickable by viewModel.isClickable.collectAsState()

    Box(
        modifier =
@@ -178,8 +181,9 @@ private fun SceneScope.ShadeScene(
                        Column(
                            horizontalAlignment = Alignment.CenterHorizontally,
                            modifier =
                                Modifier.fillMaxWidth()
                                    .clickable(onClick = { viewModel.onContentClicked() })
                                Modifier.fillMaxWidth().thenIf(isClickable) {
                                    Modifier.clickable(onClick = { viewModel.onContentClicked() })
                                }
                        ) {
                            CollapsedShadeHeader(
                                viewModel = viewModel.shadeHeaderViewModel,
+2 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.shared.model.UserActionResult
import com.android.systemui.shade.domain.interactor.privacyChipInteractor
import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
@@ -97,6 +98,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
                mobileIconsInteractor = mobileIconsInteractor,
                mobileIconsViewModel = mobileIconsViewModel,
                privacyChipInteractor = kosmos.privacyChipInteractor,
                clockInteractor = kosmos.shadeHeaderClockInteractor,
                broadcastDispatcher = fakeBroadcastDispatcher,
            )

Loading