Loading packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt +15 −8 Original line number Diff line number Diff line Loading @@ -57,9 +57,6 @@ import androidx.compose.ui.unit.dp import com.android.compose.modifiers.padding import com.android.compose.theme.LocalAndroidColorScheme /** Indicator corner radius used when the user drags the [PlatformSlider]. */ private val DefaultPlatformSliderDraggingCornerRadius = 8.dp /** * Platform slider implementation that displays a slider with an [icon] and a [label] at the start. * Loading @@ -83,10 +80,8 @@ fun PlatformSlider( valueRange: ClosedFloatingPointRange<Float> = 0f..1f, enabled: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, colors: PlatformSliderColors = if (isSystemInDarkTheme()) darkThemePlatformSliderColors() else lightThemePlatformSliderColors(), draggingCornersRadius: Dp = DefaultPlatformSliderDraggingCornerRadius, colors: PlatformSliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(), draggingCornersRadius: Dp = PlatformSliderDefaults.DefaultPlatformSliderDraggingCornerRadius, icon: (@Composable (isDragging: Boolean) -> Unit)? = null, label: (@Composable (isDragging: Boolean) -> Unit)? = null, ) { Loading @@ -109,7 +104,7 @@ fun PlatformSlider( val paddingStart by animateDpAsState( targetValue = if ((!isDragging && value == 0f) || icon == null) { if ((!isDragging && value == valueRange.start) || icon == null) { 16.dp } else { 0.dp Loading @@ -125,6 +120,7 @@ fun PlatformSlider( valueRange = valueRange, onValueChangeFinished = onValueChangeFinished, interactionSource = interactionSource, enabled = enabled, track = { Track( sliderState = it, Loading Loading @@ -286,6 +282,17 @@ data class PlatformSliderColors( val disabledLabelColor: Color, ) object PlatformSliderDefaults { /** Indicator corner radius used when the user drags the [PlatformSlider]. */ val DefaultPlatformSliderDraggingCornerRadius = 8.dp @Composable fun defaultPlatformSliderColors(): PlatformSliderColors = if (isSystemInDarkTheme()) darkThemePlatformSliderColors() else lightThemePlatformSliderColors() } /** [PlatformSliderColors] for the light theme */ @Composable private fun lightThemePlatformSliderColors() = Loading packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt 0 → 100644 +21 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.volume.panel.component.volume import dagger.Module @Module interface VolumeSlidersModule packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt 0 → 100644 +43 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.volume.panel.component.volume import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents import com.android.systemui.volume.panel.component.volume.ui.composable.VolumeSlidersComponent import com.android.systemui.volume.panel.domain.AlwaysAvailableCriteria import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent import dagger.Binds import dagger.Module import dagger.multibindings.IntoMap import dagger.multibindings.StringKey @Module interface VolumeSlidersModule { @Binds @IntoMap @StringKey(VolumePanelComponents.VOLUME_SLIDERS) fun bindVolumePanelUiComponent(component: VolumeSlidersComponent): VolumePanelUiComponent @Binds @IntoMap @StringKey(VolumePanelComponents.VOLUME_SLIDERS) fun bindComponentAvailabilityCriteria( criteria: AlwaysAvailableCriteria ): ComponentAvailabilityCriteria } packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt 0 → 100644 +200 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.volume.panel.component.volume.ui.composable import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.animation.shrinkVertically import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults 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 import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.android.compose.PlatformSliderColors import com.android.systemui.res.R import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel private const val EXPAND_DURATION_MILLIS = 500 private const val COLLAPSE_DURATION_MILLIS = 300 /** Volume sliders laid out in a collapsable column */ @OptIn(ExperimentalAnimationApi::class) @Composable fun ColumnVolumeSliders( viewModels: List<SliderViewModel>, sliderColors: PlatformSliderColors, isExpandable: Boolean, modifier: Modifier = Modifier, ) { require(viewModels.isNotEmpty()) var isExpanded: Boolean by remember { mutableStateOf(false) } val transition = updateTransition(isExpanded, label = "CollapsableSliders") Column(modifier = modifier) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { val sliderViewModel: SliderViewModel = viewModels.first() val sliderState by viewModels.first().slider.collectAsState() VolumeSlider( modifier = Modifier.weight(1f), state = sliderState, onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) }, sliderColors = sliderColors, ) if (isExpandable) { ExpandButton( isExpanded = isExpanded, onExpandedChanged = { isExpanded = it }, sliderColors, Modifier, ) } } transition.AnimatedVisibility( visible = { it }, enter = expandVertically( animationSpec = tween(durationMillis = EXPAND_DURATION_MILLIS), expandFrom = Alignment.CenterVertically, ), exit = shrinkVertically( animationSpec = tween(durationMillis = COLLAPSE_DURATION_MILLIS), shrinkTowards = Alignment.CenterVertically, ), ) { Column(modifier = Modifier.fillMaxWidth()) { for (index in 1..viewModels.lastIndex) { val sliderViewModel: SliderViewModel = viewModels[index] val sliderState by sliderViewModel.slider.collectAsState() transition.AnimatedVisibility( visible = { it }, enter = enterTransition(index = index, totalCount = viewModels.size), exit = exitTransition(index = index, totalCount = viewModels.size) ) { VolumeSlider( modifier = Modifier.fillMaxWidth().padding(top = 16.dp), state = sliderState, onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) }, sliderColors = sliderColors, ) } } } } } } @Composable private fun ExpandButton( isExpanded: Boolean, onExpandedChanged: (Boolean) -> Unit, sliderColors: PlatformSliderColors, modifier: Modifier = Modifier, ) { IconButton( modifier = modifier.size(64.dp), onClick = { onExpandedChanged(!isExpanded) }, colors = IconButtonDefaults.filledIconButtonColors( containerColor = sliderColors.indicatorColor, contentColor = sliderColors.iconColor ), ) { Icon( painter = painterResource( if (isExpanded) { R.drawable.ic_filled_arrow_down } else { R.drawable.ic_filled_arrow_up } ), contentDescription = null, ) } } private fun enterTransition(index: Int, totalCount: Int): EnterTransition { val enterDelay = ((totalCount - index + 1) * 10).coerceAtLeast(0) val enterDuration = (EXPAND_DURATION_MILLIS - enterDelay).coerceAtLeast(100) return slideInVertically( initialOffsetY = { (it * 0.25).toInt() }, animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), ) + scaleIn( initialScale = 0.9f, animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), ) + expandVertically( initialHeight = { (it * 0.65).toInt() }, animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), clip = false, expandFrom = Alignment.CenterVertically, ) + fadeIn( animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), ) } private fun exitTransition(index: Int, totalCount: Int): ExitTransition { val exitDuration = (COLLAPSE_DURATION_MILLIS - (totalCount - index + 1) * 10).coerceAtLeast(100) return slideOutVertically( targetOffsetY = { (it * 0.25).toInt() }, animationSpec = tween(durationMillis = exitDuration), ) + scaleOut( targetScale = 0.9f, animationSpec = tween(durationMillis = exitDuration), ) + shrinkVertically( targetHeight = { (it * 0.65).toInt() }, animationSpec = tween(durationMillis = exitDuration), clip = false, shrinkTowards = Alignment.CenterVertically, ) + fadeOut(animationSpec = tween(durationMillis = exitDuration)) } packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt 0 → 100644 +51 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.volume.panel.component.volume.ui.composable import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.android.compose.PlatformSliderColors import com.android.compose.grid.VerticalGrid import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel @Composable fun GridVolumeSliders( viewModels: List<SliderViewModel>, sliderColors: PlatformSliderColors, modifier: Modifier = Modifier, ) { require(viewModels.isNotEmpty()) VerticalGrid( modifier = modifier, columns = 2, verticalSpacing = 16.dp, horizontalSpacing = 24.dp, ) { for (sliderViewModel in viewModels) { val sliderState = sliderViewModel.slider.collectAsState().value VolumeSlider( modifier = Modifier.fillMaxWidth(), state = sliderState, onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) }, sliderColors = sliderColors, ) } } } Loading
packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt +15 −8 Original line number Diff line number Diff line Loading @@ -57,9 +57,6 @@ import androidx.compose.ui.unit.dp import com.android.compose.modifiers.padding import com.android.compose.theme.LocalAndroidColorScheme /** Indicator corner radius used when the user drags the [PlatformSlider]. */ private val DefaultPlatformSliderDraggingCornerRadius = 8.dp /** * Platform slider implementation that displays a slider with an [icon] and a [label] at the start. * Loading @@ -83,10 +80,8 @@ fun PlatformSlider( valueRange: ClosedFloatingPointRange<Float> = 0f..1f, enabled: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, colors: PlatformSliderColors = if (isSystemInDarkTheme()) darkThemePlatformSliderColors() else lightThemePlatformSliderColors(), draggingCornersRadius: Dp = DefaultPlatformSliderDraggingCornerRadius, colors: PlatformSliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(), draggingCornersRadius: Dp = PlatformSliderDefaults.DefaultPlatformSliderDraggingCornerRadius, icon: (@Composable (isDragging: Boolean) -> Unit)? = null, label: (@Composable (isDragging: Boolean) -> Unit)? = null, ) { Loading @@ -109,7 +104,7 @@ fun PlatformSlider( val paddingStart by animateDpAsState( targetValue = if ((!isDragging && value == 0f) || icon == null) { if ((!isDragging && value == valueRange.start) || icon == null) { 16.dp } else { 0.dp Loading @@ -125,6 +120,7 @@ fun PlatformSlider( valueRange = valueRange, onValueChangeFinished = onValueChangeFinished, interactionSource = interactionSource, enabled = enabled, track = { Track( sliderState = it, Loading Loading @@ -286,6 +282,17 @@ data class PlatformSliderColors( val disabledLabelColor: Color, ) object PlatformSliderDefaults { /** Indicator corner radius used when the user drags the [PlatformSlider]. */ val DefaultPlatformSliderDraggingCornerRadius = 8.dp @Composable fun defaultPlatformSliderColors(): PlatformSliderColors = if (isSystemInDarkTheme()) darkThemePlatformSliderColors() else lightThemePlatformSliderColors() } /** [PlatformSliderColors] for the light theme */ @Composable private fun lightThemePlatformSliderColors() = Loading
packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt 0 → 100644 +21 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.volume.panel.component.volume import dagger.Module @Module interface VolumeSlidersModule
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt 0 → 100644 +43 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.volume.panel.component.volume import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents import com.android.systemui.volume.panel.component.volume.ui.composable.VolumeSlidersComponent import com.android.systemui.volume.panel.domain.AlwaysAvailableCriteria import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent import dagger.Binds import dagger.Module import dagger.multibindings.IntoMap import dagger.multibindings.StringKey @Module interface VolumeSlidersModule { @Binds @IntoMap @StringKey(VolumePanelComponents.VOLUME_SLIDERS) fun bindVolumePanelUiComponent(component: VolumeSlidersComponent): VolumePanelUiComponent @Binds @IntoMap @StringKey(VolumePanelComponents.VOLUME_SLIDERS) fun bindComponentAvailabilityCriteria( criteria: AlwaysAvailableCriteria ): ComponentAvailabilityCriteria }
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt 0 → 100644 +200 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.volume.panel.component.volume.ui.composable import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.animation.shrinkVertically import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults 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 import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.android.compose.PlatformSliderColors import com.android.systemui.res.R import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel private const val EXPAND_DURATION_MILLIS = 500 private const val COLLAPSE_DURATION_MILLIS = 300 /** Volume sliders laid out in a collapsable column */ @OptIn(ExperimentalAnimationApi::class) @Composable fun ColumnVolumeSliders( viewModels: List<SliderViewModel>, sliderColors: PlatformSliderColors, isExpandable: Boolean, modifier: Modifier = Modifier, ) { require(viewModels.isNotEmpty()) var isExpanded: Boolean by remember { mutableStateOf(false) } val transition = updateTransition(isExpanded, label = "CollapsableSliders") Column(modifier = modifier) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { val sliderViewModel: SliderViewModel = viewModels.first() val sliderState by viewModels.first().slider.collectAsState() VolumeSlider( modifier = Modifier.weight(1f), state = sliderState, onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) }, sliderColors = sliderColors, ) if (isExpandable) { ExpandButton( isExpanded = isExpanded, onExpandedChanged = { isExpanded = it }, sliderColors, Modifier, ) } } transition.AnimatedVisibility( visible = { it }, enter = expandVertically( animationSpec = tween(durationMillis = EXPAND_DURATION_MILLIS), expandFrom = Alignment.CenterVertically, ), exit = shrinkVertically( animationSpec = tween(durationMillis = COLLAPSE_DURATION_MILLIS), shrinkTowards = Alignment.CenterVertically, ), ) { Column(modifier = Modifier.fillMaxWidth()) { for (index in 1..viewModels.lastIndex) { val sliderViewModel: SliderViewModel = viewModels[index] val sliderState by sliderViewModel.slider.collectAsState() transition.AnimatedVisibility( visible = { it }, enter = enterTransition(index = index, totalCount = viewModels.size), exit = exitTransition(index = index, totalCount = viewModels.size) ) { VolumeSlider( modifier = Modifier.fillMaxWidth().padding(top = 16.dp), state = sliderState, onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) }, sliderColors = sliderColors, ) } } } } } } @Composable private fun ExpandButton( isExpanded: Boolean, onExpandedChanged: (Boolean) -> Unit, sliderColors: PlatformSliderColors, modifier: Modifier = Modifier, ) { IconButton( modifier = modifier.size(64.dp), onClick = { onExpandedChanged(!isExpanded) }, colors = IconButtonDefaults.filledIconButtonColors( containerColor = sliderColors.indicatorColor, contentColor = sliderColors.iconColor ), ) { Icon( painter = painterResource( if (isExpanded) { R.drawable.ic_filled_arrow_down } else { R.drawable.ic_filled_arrow_up } ), contentDescription = null, ) } } private fun enterTransition(index: Int, totalCount: Int): EnterTransition { val enterDelay = ((totalCount - index + 1) * 10).coerceAtLeast(0) val enterDuration = (EXPAND_DURATION_MILLIS - enterDelay).coerceAtLeast(100) return slideInVertically( initialOffsetY = { (it * 0.25).toInt() }, animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), ) + scaleIn( initialScale = 0.9f, animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), ) + expandVertically( initialHeight = { (it * 0.65).toInt() }, animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), clip = false, expandFrom = Alignment.CenterVertically, ) + fadeIn( animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), ) } private fun exitTransition(index: Int, totalCount: Int): ExitTransition { val exitDuration = (COLLAPSE_DURATION_MILLIS - (totalCount - index + 1) * 10).coerceAtLeast(100) return slideOutVertically( targetOffsetY = { (it * 0.25).toInt() }, animationSpec = tween(durationMillis = exitDuration), ) + scaleOut( targetScale = 0.9f, animationSpec = tween(durationMillis = exitDuration), ) + shrinkVertically( targetHeight = { (it * 0.65).toInt() }, animationSpec = tween(durationMillis = exitDuration), clip = false, shrinkTowards = Alignment.CenterVertically, ) + fadeOut(animationSpec = tween(durationMillis = exitDuration)) }
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt 0 → 100644 +51 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.volume.panel.component.volume.ui.composable import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.android.compose.PlatformSliderColors import com.android.compose.grid.VerticalGrid import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel @Composable fun GridVolumeSliders( viewModels: List<SliderViewModel>, sliderColors: PlatformSliderColors, modifier: Modifier = Modifier, ) { require(viewModels.isNotEmpty()) VerticalGrid( modifier = modifier, columns = 2, verticalSpacing = 16.dp, horizontalSpacing = 24.dp, ) { for (sliderViewModel in viewModels) { val sliderState = sliderViewModel.slider.collectAsState().value VolumeSlider( modifier = Modifier.fillMaxWidth(), state = sliderState, onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) }, sliderColors = sliderColors, ) } } }