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

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

Merge "Update volume slider dragging animation" into main

parents 926af4ed f5e1da7f
Loading
Loading
Loading
Loading
+24 −20
Original line number Diff line number Diff line
@@ -16,13 +16,15 @@

package com.android.systemui.volume.panel.component.volume.ui.composable

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
@@ -84,10 +86,7 @@ fun VolumeSlider(
        valueRange = state.valueRange,
        onValueChange = onValueChange,
        enabled = state.isEnabled,
        icon = { isDragging ->
            if (isDragging) {
                Text(text = state.valueText, color = LocalContentColor.current)
            } else {
        icon = {
            state.icon?.let {
                SliderIcon(
                    icon = it,
@@ -95,10 +94,14 @@ fun VolumeSlider(
                    isTappable = state.isMutable,
                )
            }
            }
        },
        colors = sliderColors,
        label = {
        label = { isDragging ->
            AnimatedVisibility(
                visible = !isDragging,
                enter = fadeIn(tween(150)),
                exit = fadeOut(tween(150)),
            ) {
                VolumeSliderContent(
                    modifier = Modifier,
                    label = state.label,
@@ -106,6 +109,7 @@ fun VolumeSlider(
                    disabledMessage = state.disabledMessage,
                )
            }
        }
    )
}

+0 −40
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.domain.interactor

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
@SmallTest
class VolumeSliderInteractorTest : SysuiTestCase() {

    private val underTest = VolumeSliderInteractor()

    @Test
    fun processVolumeToValue_returnsTranslatedVolume() {
        assertThat(underTest.processVolumeToValue(2, volumeRange)).isEqualTo(20f)
    }

    private companion object {
        val volumeRange = 0..10
    }
}
+0 −47
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.domain.interactor

import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject

/** Converts from slider value to volume and back. */
@VolumePanelScope
class VolumeSliderInteractor @Inject constructor() {

    /** mimic percentage volume setting */
    private val displayValueRange: ClosedFloatingPointRange<Float> = 0f..100f

    /**
     * Translates [volume], that belongs to [volumeRange] to the value that belongs to
     * [displayValueRange].
     */
    fun processVolumeToValue(
        volume: Int,
        volumeRange: ClosedRange<Int>,
    ): Float {
        val currentRangeStart: Float = volumeRange.start.toFloat()
        val targetRangeStart: Float = displayValueRange.start
        val currentRangeLength: Float = (volumeRange.endInclusive.toFloat() - currentRangeStart)
        val targetRangeLength: Float = displayValueRange.endInclusive - targetRangeStart
        if (currentRangeLength == 0f || targetRangeLength == 0f) {
            return 0f
        }
        val volumeFraction: Float = (volume.toFloat() - currentRangeStart) / currentRangeLength
        return targetRangeStart + volumeFraction * targetRangeLength
    }
}
+0 −7
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import com.android.settingslib.volume.shared.model.AudioStreamModel
import com.android.settingslib.volume.shared.model.RingerMode
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -44,7 +43,6 @@ constructor(
    @Assisted private val coroutineScope: CoroutineScope,
    private val context: Context,
    private val audioVolumeInteractor: AudioVolumeInteractor,
    private val volumeSliderInteractor: VolumeSliderInteractor,
) : SliderViewModel {

    private val audioStream = audioStreamWrapper.audioStream
@@ -105,10 +103,6 @@ constructor(
        return State(
            value = volume.toFloat(),
            valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
            valueText =
                SliderViewModel.formatValue(
                    volumeSliderInteractor.processVolumeToValue(volume, volumeRange)
                ),
            icon = getIcon(ringerMode),
            label = labelsByStream[audioStream]?.let(context::getString)
                    ?: error("No label for the stream: $audioStream"),
@@ -157,7 +151,6 @@ constructor(
        override val valueRange: ClosedFloatingPointRange<Float>,
        override val icon: Icon,
        override val label: String,
        override val valueText: String,
        override val disabledMessage: String?,
        override val isEnabled: Boolean,
        override val a11yStep: Int,
+1 −10
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import com.android.systemui.common.shared.model.Icon
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -41,7 +40,6 @@ constructor(
    @Assisted private val coroutineScope: CoroutineScope,
    private val context: Context,
    private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
    private val volumeSliderInteractor: VolumeSliderInteractor,
) : SliderViewModel {

    override val slider: StateFlow<SliderState> =
@@ -66,13 +64,6 @@ constructor(
            value = currentVolume.toFloat(),
            valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
            icon = Icon.Resource(R.drawable.ic_cast, null),
            valueText =
                SliderViewModel.formatValue(
                    volumeSliderInteractor.processVolumeToValue(
                        volume = currentVolume,
                        volumeRange = volumeRange,
                    )
                ),
            label = context.getString(R.string.media_device_cast),
            isEnabled = true,
            a11yStep = 1
@@ -83,13 +74,13 @@ constructor(
        override val value: Float,
        override val valueRange: ClosedFloatingPointRange<Float>,
        override val icon: Icon,
        override val valueText: String,
        override val label: String,
        override val isEnabled: Boolean,
        override val a11yStep: Int,
    ) : SliderState {
        override val disabledMessage: String?
            get() = null

        override val isMutable: Boolean
            get() = false
    }
Loading