Skip to content

Commit

Permalink
Improve accessibility in "Showcases" and on the player (#821)
Browse files Browse the repository at this point in the history
  • Loading branch information
MGaetan89 authored Dec 12, 2024
1 parent e8f789f commit e01699c
Show file tree
Hide file tree
Showing 22 changed files with 268 additions and 129 deletions.
5 changes: 0 additions & 5 deletions .github/workflows/build_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ jobs:
with:
java-version: '17'
distribution: 'temurin'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
cache-read-only: true
- name: Build project
run: >
./gradlew
Expand Down
2 changes: 0 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ android-gradle-plugin = "8.7.3"
androidx-activity = "1.9.3"
androidx-annotation = "1.9.1"
androidx-compose = "2024.11.00"
androidx-compose-material-navigation = "1.7.0-beta01" # TODO Remove this once https://issuetracker.google.com/issues/347719428 is resolved
androidx-core = "1.15.0"
androidx-datastore = "1.1.1"
androidx-fragment = "1.8.5"
Expand Down Expand Up @@ -137,7 +136,6 @@ androidx-compose-material3 = { group = "androidx.compose.material3", name = "mat
androidx-compose-material3-window-size = { module = "androidx.compose.material3:material3-window-size-class" }
androidx-compose-material-icons-core = { module = "androidx.compose.material:material-icons-core" }
androidx-compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" }
androidx-compose-material-navigation = { module = "androidx.compose.material:material-navigation", version.ref = "androidx-compose-material-navigation" }
androidx-compose-runtime = { module = "androidx.compose.runtime:runtime" }
androidx-compose-runtime-saveable = { module = "androidx.compose.runtime:runtime-saveable" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
Expand Down
3 changes: 3 additions & 0 deletions pillarbox-demo-shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ dependencies {
api(libs.androidx.compose.ui.text)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.ui.unit)
implementation(libs.androidx.core)
implementation(libs.androidx.core.ktx)
api(libs.androidx.datastore.core)
api(libs.androidx.datastore.preferences)
api(libs.androidx.datastore.preferences.core)
Expand All @@ -38,6 +40,7 @@ dependencies {
api(libs.androidx.navigation.runtime)
implementation(libs.androidx.paging.common)
api(libs.kotlinx.coroutines.core)
api(libs.kotlinx.datetime)
api(libs.kotlinx.serialization.core)
implementation(libs.okhttp)
api(libs.srg.data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ data class Playlist(val title: String, val items: List<DemoItem>, val languageTa
imageUri = "https://www.rts.ch/2022/08/18/12/38/13317144.image/16x9",
languageTag = "fr-CH",
),
// urn:swi:video:48498670
DemoItem.URL(
title = "Swiss wheelchair athlete wins top award",
uri = "https://cdn.prod.swi-services.ch/video-projects/94f5f5d1-5d53-4336-afda-9198462c45d9/localised-videos/ENG/renditions/ENG.mp4",
description = "VOD - MP4 (urn:swi:video:48498670)",
description = "VOD - MP4",
imageUri = "https://cdn.prod.swi-services.ch/video-delivery/images/94f5f5d1-5d53-4336-afda-9198462c45d9/_.1hAGinujJ.yERGrrGNzBGCNSxmhKZT/16x9",
languageTag = "en-CH",
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) SRG SSR. All rights reserved.
* License information is available from the LICENSE file.
*/
package ch.srgssr.pillarbox.demo.shared.ui

import android.view.accessibility.AccessibilityManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.getSystemService

/**
* Remembers the current touch exploration state and provides it as a Composable state.
*
* @return A boolean indicating whether touch exploration is currently enabled.
*/
@Composable
fun rememberIsTouchExplorationEnabled(): Boolean {
val accessibilityManager = LocalContext.current.getSystemService<AccessibilityManager>() ?: return false
val (isTouchExplorationEnabled, setIsTouchExplorationEnabled) = remember {
mutableStateOf(accessibilityManager.isTouchExplorationEnabled)
}

DisposableEffect(Unit) {
val callback = AccessibilityManager.TouchExplorationStateChangeListener(setIsTouchExplorationEnabled)

accessibilityManager.addTouchExplorationStateChangeListener(callback)

onDispose {
accessibilityManager.removeTouchExplorationStateChangeListener(callback)
}
}

return isTouchExplorationEnabled
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.foundation.focusable
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.DragInteraction
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.isSystemInDarkTheme
Expand All @@ -21,6 +22,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
Expand All @@ -33,11 +35,15 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerInputScope
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.semantics.ProgressBarRangeInfo
import androidx.compose.ui.semantics.progressBarRangeInfo
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import ch.srgssr.pillarbox.demo.shared.extension.onDpadEvent
import ch.srgssr.pillarbox.demo.shared.ui.rememberIsTouchExplorationEnabled
import ch.srgssr.pillarbox.demo.shared.ui.theme.md_theme_dark_inverseSurface
import ch.srgssr.pillarbox.demo.shared.ui.theme.md_theme_dark_onSurface
import ch.srgssr.pillarbox.demo.shared.ui.theme.md_theme_dark_primary
Expand Down Expand Up @@ -96,7 +102,12 @@ fun PillarboxSlider(
PillarboxSliderInternal(
activeTrackWeight = value / range.last.toFloat(),
compactMode = compactMode,
modifier = modifier,
modifier = modifier.semantics {
progressBarRangeInfo = ProgressBarRangeInfo(
current = value.toFloat(),
range = range.first.toFloat()..range.last.toFloat(),
)
},
secondaryValueWeight = secondaryValue?.let { it / range.last.toFloat() },
enabled = enabled,
thumbColorEnabled = thumbColorEnabled,
Expand Down Expand Up @@ -166,7 +177,12 @@ fun PillarboxSlider(
PillarboxSliderInternal(
activeTrackWeight = value / range.endInclusive,
compactMode = compactMode,
modifier = modifier,
modifier = modifier.semantics {
progressBarRangeInfo = ProgressBarRangeInfo(
current = value.toFloat(),
range = range.start..range.endInclusive,
)
},
secondaryValueWeight = secondaryValue?.let { it / range.endInclusive },
enabled = enabled,
thumbColorEnabled = thumbColorEnabled,
Expand Down Expand Up @@ -208,8 +224,11 @@ private fun PillarboxSliderInternal(
onSeekBack: () -> Unit,
onSeekForward: () -> Unit,
) {
val isTouchExplorationEnabled = rememberIsTouchExplorationEnabled()
val compactMode = compactMode && !isTouchExplorationEnabled
val seekBarHeight by animateDpAsState(targetValue = if (compactMode) 8.dp else 16.dp, label = "seek_bar_height")
val thumbColor by animateColorAsState(targetValue = if (enabled) thumbColorEnabled else thumbColorDisabled, label = "thumb_color")
val verticalPadding by animateDpAsState(targetValue = if (isTouchExplorationEnabled) 48.dp - seekBarHeight else 0.dp, label = "padding_top")

val animatedActiveTrackWeight by animateFloatAsState(targetValue = activeTrackWeight, label = "active_track_weight")
val activeTrackColor by animateColorAsState(
Expand All @@ -230,6 +249,8 @@ private fun PillarboxSliderInternal(

Row(
modifier = modifier
.semantics(mergeDescendants = true) {}
.padding(vertical = verticalPadding)
.height(seekBarHeight)
.then(
if (interactionSource != null) {
Expand Down Expand Up @@ -257,7 +278,7 @@ private fun PillarboxSliderInternal(

Thumb(
color = thumbColor,
enabled = enabled,
enabled = enabled && !isTouchExplorationEnabled,
onSeekBack = onSeekBack,
onSeekForward = onSeekForward,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.media3.common.Format
import ch.srgssr.pillarbox.demo.shared.ui.settings.MetricsOverlayOptions
Expand All @@ -31,7 +32,9 @@ fun MetricsOverlay(
) {
val currentVideoFormat = playbackMetrics.videoFormat
val currentAudioFormat = playbackMetrics.audioFormat
Column(modifier = modifier) {
Column(
modifier = modifier.clearAndSetSemantics {},
) {
currentVideoFormat?.let {
OverlayText(
overlayOptions = overlayOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class StatsForNerdsViewModel(application: Application) : AndroidViewModel(applic
getSessionInformation(
labelRes = R.string.video_size,
value = if (value.videoSize != VideoSize.UNKNOWN) {
"${value.videoSize.width}x${value.videoSize.height}"
"${value.videoSize.width}×${value.videoSize.height}"
} else {
null
}
Expand Down
6 changes: 5 additions & 1 deletion pillarbox-demo-shared/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
<string name="search_placeholder">Search for content</string>
<string name="no_results">No results</string>
<string name="empty_search_query">Enter something to search</string>
<string name="audio_content">Audio</string>
<string name="video_content">Video</string>
<string name="controls_visible">Controls visible</string>
<string name="controls_hidden">Controls hidden</string>
<string name="duration"><xliff:g example="15" id="duration">%1$d</xliff:g> min</string>
<string name="settings">Settings</string>
<string name="audio_track">Audio tracks</string>
Expand All @@ -26,7 +30,7 @@
<string name="drm_loading">DRM loading</string>
<string name="total_load_time">Total load time</string>
<string name="media_information">Information</string>
<string name="session_id">Session id</string>
<string name="session_id">Session ID</string>
<string name="media_uri">URI</string>
<string name="playback_duration">Playback duration</string>
<string name="data_volume">Data volume</string>
Expand Down
1 change: 1 addition & 0 deletions pillarbox-demo-tv/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {
implementation(libs.coil.network.okhttp)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.datetime)
implementation(libs.kotlinx.serialization.core)
implementation(libs.okhttp)
implementation(libs.srg.data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ private fun NavigationDrawerScope.TracksSetting(
is VideoTrack -> {
val text = buildString {
append(format.width)
append("x")
append("×")
append(format.height)

if (format.bitrate > Format.NO_VALUE) {
Expand Down
1 change: 0 additions & 1 deletion pillarbox-demo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ dependencies {
implementation(libs.androidx.compose.foundation.layout)
implementation(libs.androidx.compose.material.icons.core)
implementation(libs.androidx.compose.material.icons.extended)
implementation(libs.androidx.compose.material.navigation)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material3.window.size)
implementation(libs.androidx.compose.runtime)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import ch.srg.dataProvider.integrationlayer.data.remote.Type
import ch.srg.dataProvider.integrationlayer.data.remote.Vendor
import ch.srgssr.pillarbox.demo.shared.R
import ch.srgssr.pillarbox.demo.shared.ui.integrationLayer.data.Content
import ch.srgssr.pillarbox.demo.shared.ui.rememberIsTouchExplorationEnabled
import ch.srgssr.pillarbox.demo.ui.theme.PillarboxTheme
import java.util.Date
import kotlin.time.Duration.Companion.seconds
Expand Down Expand Up @@ -78,9 +79,10 @@ private fun MediaView(
languageTag: String? = null,
onClick: () -> Unit
) {
val isTouchExplorationEnabled = rememberIsTouchExplorationEnabled()
val mediaTypeIcon = when (content.mediaType) {
MediaType.AUDIO -> "🎧"
MediaType.VIDEO -> "🎬"
MediaType.AUDIO -> if (isTouchExplorationEnabled) "${stringResource(R.string.audio_content)} -" else "🎧"
MediaType.VIDEO -> if (isTouchExplorationEnabled) "${stringResource(R.string.video_content)} -" else "🎬"
}
val subtitlePrefix = if (content.showTitle != null) {
"${content.showTitle} - "
Expand Down
Loading

0 comments on commit e01699c

Please sign in to comment.