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

Commit 785f5df0 authored by Sherry Zhou's avatar Sherry Zhou Committed by Android (Google) Code Review
Browse files

Merge "Implement weather clock blueprint layout for compose" into main

parents 029ad242 fd34b980
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -80,5 +80,14 @@ object ClockScenes {
object ClockElementKeys {
    val largeClockElementKey = ElementKey("large-clock")
    val smallClockElementKey = ElementKey("small-clock")
    val weatherSmallClockElementKey = ElementKey("weather-small-clock")
    val smartspaceElementKey = ElementKey("smart-space")
}

object WeatherClockElementKeys {
    val timeElementKey = ElementKey("weather-large-clock-time")
    val dateElementKey = ElementKey("weather-large-clock-date")
    val weatherIconElementKey = ElementKey("weather-large-clock-weather-icon")
    val temperatureElementKey = ElementKey("weather-large-clock-temperature")
    val dndAlarmElementKey = ElementKey("weather-large-clock-dnd-alarm")
}
+84 −5
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
@@ -33,11 +35,14 @@ import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.keyguard.KeyguardClockSwitch.LARGE
import com.android.systemui.Flags
import com.android.systemui.customization.R as customizationR
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChanged
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
@@ -47,8 +52,8 @@ import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.WeatherClockSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.res.R
import com.android.systemui.shade.LargeScreenHeaderHelper
import dagger.Binds
@@ -71,6 +76,7 @@ constructor(
    private val settingsMenuSection: SettingsMenuSection,
    private val clockInteractor: KeyguardClockInteractor,
    private val mediaCarouselSection: MediaCarouselSection,
    private val clockViewModel: KeyguardClockViewModel,
) : ComposableLockscreenSceneBlueprint {

    override val id: String = WEATHER_CLOCK_BLUEPRINT_ID
@@ -79,7 +85,7 @@ constructor(
        val isUdfpsVisible = viewModel.isUdfpsVisible
        val burnIn = rememberBurnIn(clockInteractor)
        val resources = LocalContext.current.resources

        val currentClockState = clockViewModel.currentClock.collectAsState()
        LockscreenLongPress(
            viewModel = viewModel.longPress,
            modifier = modifier,
@@ -91,7 +97,34 @@ constructor(
                        modifier = Modifier.fillMaxWidth(),
                    ) {
                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
                        // TODO: Add weather clock for small and large clock
                        val currentClock = currentClockState.value
                        val clockSize by clockViewModel.clockSize.collectAsState()
                        with(weatherClockSection) {
                            if (currentClock == null) {
                                return@with
                            }

                            if (clockSize == LARGE) {
                                Time(
                                    clock = currentClock,
                                    modifier =
                                        Modifier.padding(
                                            start =
                                                dimensionResource(
                                                    customizationR.dimen.clock_padding_start
                                                )
                                        )
                                )
                            } else {
                                SmallClock(
                                    burnInParams = burnIn.parameters,
                                    modifier =
                                        Modifier.align(Alignment.Start)
                                            .onTopPlacementChanged(burnIn.onSmallClockTopChanged),
                                    clock = currentClock
                                )
                            }
                        }
                        with(smartSpaceSection) {
                            SmartSpace(
                                burnInParams = burnIn.parameters,
@@ -119,6 +152,12 @@ constructor(
                                )
                            }
                        }
                        with(weatherClockSection) {
                            if (currentClock == null || clockSize != LARGE) {
                                return@with
                            }
                            LargeClockSectionBelowSmartspace(clock = currentClock)
                        }

                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
                            with(ambientIndicationSectionOptional.get()) {
@@ -234,6 +273,7 @@ constructor(
    private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
    private val weatherClockSection: WeatherClockSection,
    private val mediaCarouselSection: MediaCarouselSection,
    private val clockViewModel: KeyguardClockViewModel,
) : ComposableLockscreenSceneBlueprint {
    override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID

@@ -242,7 +282,7 @@ constructor(
        val isUdfpsVisible = viewModel.isUdfpsVisible
        val burnIn = rememberBurnIn(clockInteractor)
        val resources = LocalContext.current.resources

        val currentClockState = clockViewModel.currentClock.collectAsState()
        LockscreenLongPress(
            viewModel = viewModel.longPress,
            modifier = modifier,
@@ -257,11 +297,42 @@ constructor(
                        Row(
                            modifier = Modifier.fillMaxSize(),
                        ) {
                            // TODO: Add weather clock for small and large clock
                            Column(
                                modifier = Modifier.fillMaxHeight().weight(weight = 1f),
                                horizontalAlignment = Alignment.CenterHorizontally,
                            ) {
                                val currentClock = currentClockState.value
                                val clockSize by clockViewModel.clockSize.collectAsState()
                                with(weatherClockSection) {
                                    if (currentClock == null) {
                                        return@with
                                    }

                                    if (clockSize == LARGE) {
                                        Time(
                                            clock = currentClock,
                                            modifier =
                                                Modifier.align(Alignment.Start)
                                                    .padding(
                                                        start =
                                                            dimensionResource(
                                                                customizationR.dimen
                                                                    .clock_padding_start
                                                            )
                                                    )
                                        )
                                    } else {
                                        SmallClock(
                                            burnInParams = burnIn.parameters,
                                            modifier =
                                                Modifier.align(Alignment.Start)
                                                    .onTopPlacementChanged(
                                                        burnIn.onSmallClockTopChanged
                                                    ),
                                            clock = currentClock,
                                        )
                                    }
                                }
                                with(smartSpaceSection) {
                                    SmartSpace(
                                        burnInParams = burnIn.parameters,
@@ -284,6 +355,14 @@ constructor(
                                }

                                with(mediaCarouselSection) { MediaCarousel() }

                                with(weatherClockSection) {
                                    if (currentClock == null || clockSize != LARGE) {
                                        return@with
                                    }

                                    LargeClockSectionBelowSmartspace(currentClock)
                                }
                            }
                            with(notificationSection) {
                                val splitShadeTopMargin: Dp =
+13 −8
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@@ -32,6 +33,7 @@ import androidx.core.view.contains
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.customization.R as customizationR
import com.android.systemui.customization.R
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.largeClockElementKey
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.smallClockElementKey
import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
@@ -58,19 +60,21 @@ constructor(
        if (currentClock?.smallClock?.view == null) {
            return
        }

        val context = LocalContext.current
        MovableElement(key = smallClockElementKey, modifier = modifier) {
            content {
                AndroidView(
                    factory = { context ->
                        FrameLayout(context).apply {
                            addClockView(checkNotNull(currentClock).smallClock.view)
                            ensureClockViewExists(checkNotNull(currentClock).smallClock.view)
                        }
                    },
                    update = { it.addClockView(checkNotNull(currentClock).smallClock.view) },
                    update = {
                        it.ensureClockViewExists(checkNotNull(currentClock).smallClock.view)
                    },
                    modifier =
                        Modifier.padding(
                        Modifier.height(dimensionResource(R.dimen.small_clock_height))
                            .padding(
                                horizontal =
                                    dimensionResource(customizationR.dimen.clock_padding_start)
                            )
@@ -91,23 +95,24 @@ constructor(
        if (currentClock?.largeClock?.view == null) {
            return
        }

        MovableElement(key = largeClockElementKey, modifier = modifier) {
            content {
                AndroidView(
                    factory = { context ->
                        FrameLayout(context).apply {
                            addClockView(checkNotNull(currentClock).largeClock.view)
                            ensureClockViewExists(checkNotNull(currentClock).largeClock.view)
                        }
                    },
                    update = { it.addClockView(checkNotNull(currentClock).largeClock.view) },
                    update = {
                        it.ensureClockViewExists(checkNotNull(currentClock).largeClock.view)
                    },
                    modifier = Modifier.fillMaxSize()
                )
            }
        }
    }

    private fun FrameLayout.addClockView(clockView: View) {
    private fun FrameLayout.ensureClockViewExists(clockView: View) {
        if (contains(clockView)) {
            return
        }
+142 −10
Original line number Diff line number Diff line
@@ -16,45 +16,177 @@

package com.android.systemui.keyguard.ui.composable.section

import android.view.ViewGroup
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.viewinterop.AndroidView
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.customization.R
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.weatherSmallClockElementKey
import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockElementKeys
import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.plugins.clocks.ClockController
import javax.inject.Inject

/** Provides small clock and large clock composables for the weather clock layout. */
class WeatherClockSection @Inject constructor() {
class WeatherClockSection
@Inject
constructor(
    private val viewModel: KeyguardClockViewModel,
    private val aodBurnInViewModel: AodBurnInViewModel,
) {
    @Composable
    fun SceneScope.Time(
        clock: ClockController,
        modifier: Modifier = Modifier,
    ) {
        // TODO: compose view
        WeatherElement(
            weatherClockElementViewId = R.id.weather_clock_time,
            clock = clock,
            elementKey = WeatherClockElementKeys.timeElementKey,
            modifier = modifier.wrapContentSize(),
        )
    }

    @Composable
    fun SceneScope.Date(
    private fun SceneScope.Date(
        clock: ClockController,
        modifier: Modifier = Modifier,
    ) {
        // TODO: compose view
        WeatherElement(
            weatherClockElementViewId = R.id.weather_clock_date,
            clock = clock,
            elementKey = WeatherClockElementKeys.dateElementKey,
            modifier = modifier,
        )
    }

    @Composable
    fun SceneScope.Weather(
    private fun SceneScope.Weather(
        clock: ClockController,
        modifier: Modifier = Modifier,
    ) {
        // TODO: compose view
        WeatherElement(
            weatherClockElementViewId = R.id.weather_clock_weather_icon,
            clock = clock,
            elementKey = WeatherClockElementKeys.weatherIconElementKey,
            modifier = modifier.wrapContentSize(),
        )
    }

    @Composable
    fun SceneScope.DndAlarmStatus(
    private fun SceneScope.DndAlarmStatus(
        clock: ClockController,
        modifier: Modifier = Modifier,
    ) {
        // TODO: compose view
        WeatherElement(
            weatherClockElementViewId = R.id.weather_clock_alarm_dnd,
            clock = clock,
            elementKey = WeatherClockElementKeys.dndAlarmElementKey,
            modifier = modifier.wrapContentSize(),
        )
    }

    @Composable
    fun SceneScope.Temperature(
    private fun SceneScope.Temperature(
        clock: ClockController,
        modifier: Modifier = Modifier,
    ) {
        // TODO: compose view
        WeatherElement(
            weatherClockElementViewId = R.id.weather_clock_temperature,
            clock = clock,
            elementKey = WeatherClockElementKeys.temperatureElementKey,
            modifier = modifier.wrapContentSize(),
        )
    }

    @Composable
    private fun SceneScope.WeatherElement(
        weatherClockElementViewId: Int,
        clock: ClockController,
        elementKey: ElementKey,
        modifier: Modifier
    ) {
        MovableElement(key = elementKey, modifier) {
            content {
                AndroidView(
                    factory = {
                        val view =
                            clock.largeClock.layout.views.first {
                                it.id == weatherClockElementViewId
                            }
                        (view.parent as? ViewGroup)?.removeView(view)
                        view
                    },
                    update = {},
                    modifier = modifier
                )
            }
        }
    }

    @Composable
    fun SceneScope.LargeClockSectionBelowSmartspace(
        clock: ClockController,
    ) {
        Row(
            modifier =
                Modifier.height(IntrinsicSize.Max)
                    .padding(horizontal = dimensionResource(R.dimen.clock_padding_start))
        ) {
            Date(clock = clock, modifier = Modifier.wrapContentSize())
            Box(modifier = Modifier.fillMaxSize()) {
                Weather(clock = clock, modifier = Modifier.align(Alignment.TopStart))
                Temperature(clock = clock, modifier = Modifier.align(Alignment.BottomEnd))
                DndAlarmStatus(clock = clock, modifier = Modifier.align(Alignment.TopEnd))
            }
        }
    }

    @Composable
    fun SceneScope.SmallClock(
        burnInParams: BurnInParameters,
        modifier: Modifier = Modifier,
        clock: ClockController,
    ) {
        val localContext = LocalContext.current
        MovableElement(key = weatherSmallClockElementKey, modifier) {
            content {
                AndroidView(
                    factory = {
                        val view = clock.smallClock.view
                        if (view.parent != null) {
                            (view.parent as? ViewGroup)?.removeView(view)
                        }
                        view
                    },
                    modifier =
                        modifier
                            .height(dimensionResource(R.dimen.small_clock_height))
                            .padding(start = dimensionResource(R.dimen.clock_padding_start))
                            .padding(top = { viewModel.getSmallClockTopMargin(localContext) })
                            .burnInAware(
                                viewModel = aodBurnInViewModel,
                                params = burnInParams,
                            ),
                    update = {},
                )
            }
        }
    }
}