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

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

Merge "Add captioning button to the Volume Panel" into main

parents fe4d70f9 3291b498
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -14,24 +14,8 @@
 * limitations under the License.
 */

package com.android.systemui.volume.panel.ui.layout
package com.android.systemui.volume.panel.component.captioning

import com.android.systemui.volume.panel.ui.viewmodel.ComponentState
import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
import dagger.Module

class FakeComponentsLayoutManager(
    private val isBottomBar: (components: ComponentState) -> Boolean
) : ComponentsLayoutManager {

    override fun layout(
        volumePanelState: VolumePanelState,
        components: Collection<ComponentState>
    ): ComponentsLayout {
        return ComponentsLayout(
            components
                .filter { componentState -> !isBottomBar(componentState) }
                .sortedBy { it.key },
            components.find(isBottomBar)!!,
        )
    }
}
@Module interface CaptioningModule
+79 −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.button.ui.composable

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedIconToggleButton
import androidx.compose.material3.Text
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.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.volume.panel.component.button.ui.viewmodel.ToggleButtonViewModel
import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope
import kotlinx.coroutines.flow.StateFlow

class ToggleButtonComponent(
    private val viewModelFlow: StateFlow<ToggleButtonViewModel?>,
    private val onCheckedChange: (isChecked: Boolean) -> Unit
) : ComposeVolumePanelUiComponent {

    @Composable
    override fun VolumePanelComposeScope.Content(modifier: Modifier) {
        val viewModelByState by viewModelFlow.collectAsState()
        val viewModel = viewModelByState ?: return
        Column(
            modifier = modifier,
            verticalArrangement = Arrangement.spacedBy(12.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {
            OutlinedIconToggleButton(
                modifier = Modifier.height(64.dp).fillMaxWidth(),
                checked = viewModel.isChecked,
                onCheckedChange = onCheckedChange,
                colors =
                    IconButtonDefaults.outlinedIconToggleButtonColors(
                        containerColor = MaterialTheme.colorScheme.surface,
                        contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
                        checkedContainerColor = MaterialTheme.colorScheme.primaryContainer,
                        checkedContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
                    ),
                border = BorderStroke(8.dp, MaterialTheme.colorScheme.surface),
            ) {
                Icon(modifier = Modifier.size(24.dp), icon = viewModel.icon)
            }
            Text(
                text = viewModel.label.toString(),
                style = MaterialTheme.typography.labelMedium,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
            )
        }
    }
}
+53 −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.captioning

import com.android.systemui.volume.panel.component.button.ui.composable.ToggleButtonComponent
import com.android.systemui.volume.panel.component.captioning.domain.CaptioningAvailabilityCriteria
import com.android.systemui.volume.panel.component.captioning.ui.viewmodel.CaptioningViewModel
import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
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.Provides
import dagger.multibindings.IntoMap
import dagger.multibindings.StringKey

/** Dagger module, that provides Captioning Volume Panel UI functionality. */
@Module
interface CaptioningModule {

    @Binds
    @IntoMap
    @StringKey(VolumePanelComponents.CAPTIONING)
    fun bindComponentAvailabilityCriteria(
        criteria: CaptioningAvailabilityCriteria
    ): ComponentAvailabilityCriteria

    companion object {

        @Provides
        @IntoMap
        @StringKey(VolumePanelComponents.CAPTIONING)
        fun provideVolumePanelUiComponent(viewModel: CaptioningViewModel): VolumePanelUiComponent =
            ToggleButtonComponent(
                viewModel.buttonViewModel,
                viewModel::setIsSystemAudioCaptioningEnabled,
            )
    }
}
+18 −5
Original line number Diff line number Diff line
@@ -19,26 +19,39 @@ package com.android.systemui.volume.panel.ui.composable
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Slider
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android.systemui.volume.panel.ui.viewmodel.ComponentState
import com.android.systemui.volume.panel.ui.layout.ComponentsLayout

@Composable
fun VolumePanelComposeScope.VerticalVolumePanelContent(
    components: List<ComponentState>,
    layout: ComponentsLayout,
    modifier: Modifier = Modifier,
) {
    Column(
        modifier = modifier,
        verticalArrangement = Arrangement.spacedBy(20.dp),
    ) {
        Slider(0.5f, {})
        for (component in components) {
        for (component in layout.contentComponents) {
            AnimatedVisibility(component.isVisible) {
                with(component.component as ComposeVolumePanelUiComponent) { Content(Modifier) }
            }
        }
        if (layout.footerComponents.isNotEmpty()) {
            Row(
                modifier = Modifier.fillMaxWidth().wrapContentHeight(),
                horizontalArrangement = Arrangement.spacedBy(20.dp)
            ) {
                for (component in layout.footerComponents) {
                    with(component.component as ComposeVolumePanelUiComponent) {
                        Content(Modifier.weight(1f))
                    }
                }
            }
        }
    }
}
+17 −11
Original line number Diff line number Diff line
@@ -21,14 +21,15 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
@@ -37,7 +38,9 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.dimensionResource
import com.android.compose.theme.PlatformTheme
import com.android.systemui.res.R
@@ -64,14 +67,17 @@ fun VolumePanelRoot(
            }
        }

        Column(
            modifier =
                modifier
                    .fillMaxSize()
                    .statusBarsPadding()
                    .clickable(onClick = { viewModel.dismissPanel() }),
            verticalArrangement = Arrangement.Bottom,
        Box(
            modifier = modifier.fillMaxSize(),
            contentAlignment = Alignment.BottomCenter,
        ) {
            Spacer(
                modifier =
                    Modifier.fillMaxSize()
                        .alpha(0.32f)
                        .background(MaterialTheme.colorScheme.scrim)
                        .clickable(onClick = { viewModel.dismissPanel() })
            )
            AnimatedVisibility(
                visibleState = transitionState,
                enter = slideInVertically { it },
@@ -80,7 +86,7 @@ fun VolumePanelRoot(
                val radius = dimensionResource(R.dimen.volume_panel_corner_radius)
                Surface(
                    shape = RoundedCornerShape(topStart = radius, topEnd = radius),
                    color = MaterialTheme.colorScheme.surfaceBright,
                    color = MaterialTheme.colorScheme.surfaceContainer,
                ) {
                    Column {
                        components?.let { componentsState ->
@@ -97,7 +103,7 @@ fun VolumePanelRoot(
private fun VolumePanelComposeScope.Components(state: ComponentsLayout) {
    if (orientation == Configuration.ORIENTATION_PORTRAIT) {
        VerticalVolumePanelContent(
            components = state.contentComponents,
            state,
            modifier = Modifier.padding(dimensionResource(R.dimen.volume_panel_content_padding)),
        )
    } else {
Loading