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

Commit 87ae0365 authored by Anton Potapov's avatar Anton Potapov Committed by Android (Google) Code Review
Browse files

Merge "Update Volume Panel sliders to match the updated design" into main

parents d8acb5d5 4fe2d5aa
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -101,10 +101,17 @@ fun PlatformIconButton(
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    colors: IconButtonColors = iconButtonColors(),
    shape: Shape = IconButtonDefaults.standardShape,
    @DrawableRes iconResource: Int,
    contentDescription: String?,
) {
    IconButton(modifier = modifier, onClick = onClick, enabled = enabled, colors = colors) {
    IconButton(
        modifier = modifier,
        onClick = onClick,
        enabled = enabled,
        colors = colors,
        shape = shape,
    ) {
        Icon(
            painter = painterResource(id = iconResource),
            contentDescription = contentDescription,
+8 −8
Original line number Diff line number Diff line
@@ -30,9 +30,11 @@ import androidx.compose.animation.scaleOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults
@@ -42,7 +44,6 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
@@ -154,9 +155,7 @@ fun ColumnVolumeSliders(
                                                totalCount = viewModels.size,
                                            ),
                                    )
                                    .thenIf(!Flags.volumeRedesign()) {
                                        Modifier.padding(top = 16.dp)
                                    },
                                    .padding(top = if (Flags.volumeRedesign()) 4.dp else 16.dp),
                            state = sliderState,
                            onValueChange = { newValue: Float ->
                                sliderViewModel.onValueChanged(sliderState, newValue)
@@ -223,7 +222,7 @@ private fun ExpandButtonLegacy(
}

@Composable
private fun ExpandButton(
private fun RowScope.ExpandButton(
    isExpanded: Boolean,
    isExpandable: Boolean,
    onExpandedChanged: (Boolean) -> Unit,
@@ -243,16 +242,17 @@ private fun ExpandButton(
    ) {
        PlatformIconButton(
            modifier =
                Modifier.size(width = 48.dp, height = 40.dp).semantics {
                Modifier.size(40.dp).semantics {
                    role = Role.Switch
                    stateDescription = expandButtonStateDescription
                },
            onClick = { onExpandedChanged(!isExpanded) },
            colors =
                IconButtonDefaults.iconButtonColors(
                    containerColor = Color.Transparent,
                    contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
                    containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
                    contentColor = MaterialTheme.colorScheme.onSurface,
                ),
            shape = RoundedCornerShape(12.dp),
            iconResource =
                if (isExpanded) {
                    R.drawable.ic_arrow_down_24dp
+93 −53
Original line number Diff line number Diff line
@@ -30,14 +30,16 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon as MaterialIcon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -58,31 +60,33 @@ import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.disabled
import androidx.compose.ui.semantics.progressBarRangeInfo
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.setProgress
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import com.android.compose.PlatformSlider
import com.android.compose.PlatformSliderColors
import com.android.systemui.Flags
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Icon as IconModel
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.res.R
import com.android.systemui.volume.dialog.sliders.ui.compose.SliderTrack
import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigsProvider
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderState
import com.android.systemui.volume.ui.slider.AccessibilityParams
import com.android.systemui.volume.ui.slider.Haptics
import com.android.systemui.volume.ui.slider.Slider
import com.android.systemui.volume.ui.compose.slider.AccessibilityParams
import com.android.systemui.volume.ui.compose.slider.Haptics
import com.android.systemui.volume.ui.compose.slider.Slider
import com.android.systemui.volume.ui.compose.slider.SliderIcon
import kotlin.math.round
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map

@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun VolumeSlider(
    state: SliderState,
@@ -92,7 +96,7 @@ fun VolumeSlider(
    modifier: Modifier = Modifier,
    hapticsViewModelFactory: SliderHapticsViewModel.Factory?,
    onValueChangeFinished: (() -> Unit)? = null,
    button: (@Composable () -> Unit)? = null,
    button: (@Composable RowScope.() -> Unit)? = null,
) {
    if (!Flags.volumeRedesign()) {
        LegacyVolumeSlider(
@@ -107,36 +111,29 @@ fun VolumeSlider(
        return
    }

    Column(
        modifier = modifier.animateContentSize().semantics(true) {},
        verticalArrangement = Arrangement.Top,
    ) {
        Row(
            horizontalArrangement = Arrangement.spacedBy(12.dp),
            modifier = Modifier.fillMaxWidth().height(40.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            state.icon?.let {
                Icon(
                    icon = it,
                    tint = MaterialTheme.colorScheme.onSurface,
                    modifier = Modifier.size(24.dp),
                )
            }
    Column(modifier = modifier.animateContentSize()) {
        Text(
            text = state.label,
            style = MaterialTheme.typography.titleMedium,
            color = MaterialTheme.colorScheme.onSurface,
                modifier = Modifier.weight(1f).clearAndSetSemantics {},
            modifier = Modifier.fillMaxWidth().clearAndSetSemantics {},
        )
        Row(
            horizontalArrangement = Arrangement.spacedBy(8.dp),
            modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            val materialSliderColors =
                SliderDefaults.colors(
                    activeTickColor = MaterialTheme.colorScheme.surfaceContainerHigh,
                    inactiveTrackColor = MaterialTheme.colorScheme.surfaceContainerHigh,
                )
            button?.invoke()
        }

            Slider(
                value = state.value,
                valueRange = state.valueRange,
                onValueChanged = onValueChange,
                onValueChangeFinished = { onValueChangeFinished?.invoke() },
                colors = materialSliderColors,
                isEnabled = state.isEnabled,
                stepDistance = state.step,
                accessibilityParams =
@@ -144,6 +141,44 @@ fun VolumeSlider(
                        contentDescription = state.a11yContentDescription,
                        stateDescription = state.a11yStateDescription,
                    ),
                track = { sliderState ->
                    SliderTrack(
                        sliderState = sliderState,
                        colors = materialSliderColors,
                        isEnabled = state.isEnabled,
                        activeTrackStartIcon =
                            state.icon?.let { icon ->
                                { iconsState ->
                                    SliderIcon(
                                        icon = {
                                            Icon(icon = icon, modifier = Modifier.size(24.dp))
                                        },
                                        isVisible = iconsState.isActiveTrackStartIconVisible,
                                    )
                                }
                            },
                        inactiveTrackStartIcon =
                            state.icon?.let { icon ->
                                { iconsState ->
                                    SliderIcon(
                                        icon = {
                                            Icon(icon = icon, modifier = Modifier.size(24.dp))
                                        },
                                        isVisible = !iconsState.isActiveTrackStartIconVisible,
                                    )
                                }
                            },
                    )
                },
                thumb = { sliderState, interactionSource ->
                    SliderDefaults.Thumb(
                        sliderState = sliderState,
                        interactionSource = interactionSource,
                        enabled = state.isEnabled,
                        colors = materialSliderColors,
                        thumbSize = DpSize(4.dp, 52.dp),
                    )
                },
                haptics =
                    hapticsViewModelFactory?.let {
                        Haptics.Enabled(
@@ -152,9 +187,10 @@ fun VolumeSlider(
                            orientation = Orientation.Horizontal,
                        )
                    } ?: Haptics.Disabled,
            modifier =
                Modifier.height(40.dp).padding(top = 4.dp, bottom = 12.dp).sysuiResTag(state.label),
                modifier = Modifier.weight(1f).sysuiResTag(state.label),
            )
            button?.invoke(this)
        }
        state.disabledMessage?.let { disabledMessage ->
            AnimatedVisibility(visible = !state.isEnabled) {
                Row(
@@ -253,7 +289,11 @@ private fun LegacyVolumeSlider(
        enabled = state.isEnabled,
        icon = {
            state.icon?.let {
                SliderIcon(icon = it, onIconTapped = onIconTapped, isTappable = state.isMutable)
                LegacySliderIcon(
                    icon = it,
                    onIconTapped = onIconTapped,
                    isTappable = state.isMutable,
                )
            }
        },
        colors = sliderColors,
@@ -289,8 +329,8 @@ private fun valueState(state: SliderState): State<Float> {
}

@Composable
private fun SliderIcon(
    icon: Icon,
private fun LegacySliderIcon(
    icon: IconModel,
    onIconTapped: () -> Unit,
    isTappable: Boolean,
    modifier: Modifier = Modifier,
+33 −37
Original line number Diff line number Diff line
@@ -17,42 +17,37 @@
package com.android.systemui.volume.dialog.sliders.ui

import android.view.View
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.interaction.DragInteraction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SliderDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.theme.PlatformTheme
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.res.R
import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
import com.android.systemui.volume.dialog.sliders.ui.compose.VolumeDialogSliderTrack
import com.android.systemui.volume.dialog.sliders.ui.compose.SliderTrack
import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel
import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel
import com.android.systemui.volume.ui.slider.AccessibilityParams
import com.android.systemui.volume.ui.slider.Haptics
import com.android.systemui.volume.ui.slider.Slider
import com.android.systemui.volume.ui.compose.slider.AccessibilityParams
import com.android.systemui.volume.ui.compose.slider.Haptics
import com.android.systemui.volume.ui.compose.slider.Slider
import com.android.systemui.volume.ui.compose.slider.SliderIcon
import javax.inject.Inject
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.currentCoroutineContext
@@ -85,7 +80,7 @@ constructor(
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun VolumeDialogSlider(
    viewModel: VolumeDialogSliderViewModel,
@@ -95,10 +90,7 @@ private fun VolumeDialogSlider(
) {
    val colors =
        SliderDefaults.colors(
            thumbColor = MaterialTheme.colorScheme.primary,
            activeTickColor = MaterialTheme.colorScheme.surfaceContainerHighest,
            inactiveTickColor = MaterialTheme.colorScheme.primary,
            activeTrackColor = MaterialTheme.colorScheme.primary,
            inactiveTrackColor = MaterialTheme.colorScheme.surfaceContainerHighest,
        )
    val collectedSliderStateModel by viewModel.state.collectAsStateWithLifecycle(null)
@@ -142,16 +134,36 @@ private fun VolumeDialogSlider(
            } ?: Haptics.Disabled,
        stepDistance = 1f,
        track = { sliderState ->
            VolumeDialogSliderTrack(
            SliderTrack(
                sliderState,
                colors = colors,
                isEnabled = !sliderStateModel.isDisabled,
                activeTrackEndIcon = { iconsState ->
                    VolumeIcon(sliderStateModel.icon, iconsState.isActiveTrackEndIconVisible)
                isVertical = true,
                activeTrackStartIcon = { iconsState ->
                    SliderIcon(
                        icon = {
                            Icon(icon = sliderStateModel.icon, modifier = Modifier.size(20.dp))
                        },
                        isVisible = iconsState.isActiveTrackStartIconVisible,
                    )
                },
                inactiveTrackStartIcon = { iconsState ->
                    SliderIcon(
                        icon = {
                            Icon(icon = sliderStateModel.icon, modifier = Modifier.size(20.dp))
                        },
                inactiveTrackEndIcon = { iconsState ->
                    VolumeIcon(sliderStateModel.icon, !iconsState.isActiveTrackEndIconVisible)
                        isVisible = !iconsState.isActiveTrackStartIconVisible,
                    )
                },
            )
        },
        thumb = { sliderState, interactions ->
            SliderDefaults.Thumb(
                sliderState = sliderState,
                interactionSource = interactions,
                enabled = !sliderStateModel.isDisabled,
                colors = colors,
                thumbSize = DpSize(52.dp, 4.dp),
            )
        },
        accessibilityParams = AccessibilityParams(contentDescription = sliderStateModel.label),
@@ -168,19 +180,3 @@ private fun VolumeDialogSlider(
            },
    )
}

@Composable
private fun BoxScope.VolumeIcon(
    icon: Icon.Loaded,
    isVisible: Boolean,
    modifier: Modifier = Modifier,
) {
    AnimatedVisibility(
        visible = isVisible,
        enter = fadeIn(animationSpec = tween(delayMillis = 33, durationMillis = 100)),
        exit = fadeOut(animationSpec = tween(durationMillis = 50)),
        modifier = modifier.align(Alignment.Center).size(40.dp).padding(10.dp),
    ) {
        Icon(icon)
    }
}
+215 −156

File changed.

Preview size limit exceeded, changes collapsed.

Loading