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

Commit eaaa15e5 authored by Andrew Xu's avatar Andrew Xu Committed by Android (Google) Code Review
Browse files

Merge changes from topic "ANDREWXU_SINGLE_SHADE_FLEXIGLASS" into main

* changes:
  [Flexiglass] Implement the composable edit scene
  [Flexiglass] Use the BC25 styled tiles in the single shade
  [Flexiglass] Use TileGrid to replace the legacy QS view
parents d738d7a5 e3e4f1aa
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.scene

import com.android.systemui.qs.ui.composable.EditModeScene
import com.android.systemui.scene.ui.composable.Scene
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet

@Module
interface EditSceneModule {
    @Binds @IntoSet fun editModeScene(scene: EditModeScene): Scene
}
+77 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.ui.composable

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.qs.ui.viewmodel.EditModeSceneActionsViewModel
import com.android.systemui.qs.ui.viewmodel.EditModeSceneContentViewModel
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.Scene
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import com.android.compose.animation.scene.ContentScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.shade.ui.composable.Shade
import androidx.compose.ui.res.colorResource
import com.android.systemui.qs.panels.ui.compose.EditMode
import com.android.systemui.res.R

@SysUISingleton
class EditModeScene
@Inject
constructor(
    private val contentViewModelFactory: EditModeSceneContentViewModel.Factory,
    private val actionsViewModelFactory: EditModeSceneActionsViewModel.Factory,
) : ExclusiveActivatable(), Scene {
    override val key = Scenes.QSEditMode

    private val actionsViewModel: EditModeSceneActionsViewModel by lazy {
        actionsViewModelFactory.create()
    }

    override suspend fun onActivated() {
        actionsViewModel.activate()
    }

    override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions

    @Composable
    override fun ContentScope.Content(modifier: Modifier) {
        val viewModel = rememberViewModel("edit_mode_scene_view_model") {
            contentViewModelFactory.create()
        }

        Box(
            modifier =
                Modifier
                    .fillMaxSize()
                    .element(Shade.Elements.BackgroundScrim)
                    .background(colorResource(R.color.shade_scrim_background_dark))
        )

        EditMode(viewModel.editModeViewModel, modifier.testTag("edit_mode_scene"))
    }
}
 No newline at end of file
+15 −8
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntOffset
@@ -96,7 +97,9 @@ import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.notifications.ui.composable.HeadsUpNotificationSpace
import com.android.systemui.notifications.ui.composable.NotificationScrollingStack
import com.android.systemui.notifications.ui.composable.NotificationStackCutoffGuideline
import com.android.systemui.qs.composefragment.ui.GridAnchor
import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility
import com.android.systemui.qs.panels.ui.compose.TileGrid
import com.android.systemui.qs.shared.ui.ElementKeys
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaOffset.InQS
@@ -354,7 +357,11 @@ private fun ContentScope.QuickSettingsScene(
                            CollapsedShadeHeader(viewModel = headerViewModel, isSplitShade = false)
                    }
                    Spacer(modifier = Modifier.height(16.dp))
                    Column(modifier = Modifier.element(ElementKeys.QuickSettingsContent)) {
                    Column(
                        modifier = Modifier
                            .element(ElementKeys.QuickSettingsContent)
                            .padding(horizontal = dimensionResource(id = R.dimen.qs_horizontal_margin))
                    ) {
                        BrightnessSliderContainer(
                            viewModel.qsContainerViewModel.brightnessSliderViewModel,
                            containerColors =
@@ -363,17 +370,17 @@ private fun ContentScope.QuickSettingsScene(
                                    ContainerColors.defaultContainerColor,
                                ),
                            modifier = Modifier.padding(
                                horizontal =
                                    dimensionResource(id = R.dimen.qs_horizontal_margin)
                                vertical = dimensionResource(id = R.dimen.qs_brightness_margin_top),
                            )
                        )
                        GridAnchor()
                        // This view has its own horizontal padding
                        val content: @Composable () -> Unit = {
                            QuickSettings(
                                viewModel.qsSceneAdapter,
                                { viewModel.qsSceneAdapter.qsHeight },
                                isSplitShade = false,
                                modifier = Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.QS),
                            TileGrid(
                                viewModel.qsContainerViewModel.tileGridViewModel,
                                modifier = Modifier
                                    .sysuiResTag("quick_settings_panel")
                                    .layoutId(QSMediaMeasurePolicy.LayoutId.QS),
                            )

                            MediaCarousel(
+13 −6
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ import com.android.systemui.notifications.ui.composable.NotificationScrollingSta
import com.android.systemui.notifications.ui.composable.NotificationStackCutoffGuideline
import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility
import com.android.systemui.qs.ui.composable.BrightnessMirror
import com.android.systemui.qs.panels.ui.compose.QuickQuickSettings
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset
import com.android.systemui.res.R
@@ -331,13 +332,19 @@ private fun ContentScope.SingleShade(
                Box(
                    Modifier.element(QuickSettings.Elements.QuickQuickSettings)
                        .layoutId(SingleShadeMeasurePolicy.LayoutId.QuickSettings)
                        .padding(horizontal = shadeHorizontalPadding)
                        .padding(
                            horizontal =
                                shadeHorizontalPadding +
                                        dimensionResource(id = R.dimen.qs_horizontal_margin)
                        )
                ) {
                    QuickSettings(
                        viewModel.qsSceneAdapter,
                        { viewModel.qsSceneAdapter.qqsHeight },
                        isSplitShade = false,
                        squishiness = { tileSquishiness },
                    val qqsViewModel = rememberViewModel(traceName = "shade_scene_qqs") {
                        viewModel.quickQuickSettingsViewModel.create()
                    }
                    QuickQuickSettings(
                        qqsViewModel,
                        listening = { true },
                        modifier = Modifier.sysuiResTag("quick_qs_panel")
                    )
                }

+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.ui.viewmodel

import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.awaitCancellation


class EditModeSceneActionsViewModel
@AssistedInject
constructor(
    private val sceneBackInteractor: SceneBackInteractor
) : UserActionsViewModel() {
    override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
        sceneBackInteractor.backScene.collect {
            setActions(
                buildMap {
                    put(Swipe.Up, UserActionResult(Scenes.Gone))
                    if (it != null) {
                        put(Back, UserActionResult(it))
                    }
                }
            )
        }
    }

    @AssistedFactory
    interface Factory {
        fun create(): EditModeSceneActionsViewModel
    }
}
Loading