refactor: set traversal order for player
This commit is contained in:
@@ -58,6 +58,7 @@ fun PlayerControl(
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
SpeedPreferenceButton(
|
||||
modifier = Modifier.traversalOrder(PlayerTraversalOrder.PLAYBACK_SETTINGS),
|
||||
isActive = isPlaybackModified,
|
||||
onSpeedClicked = onSpeedClicked,
|
||||
)
|
||||
@@ -69,17 +70,20 @@ fun PlayerControl(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
PreviousButton(
|
||||
modifier = Modifier.traversalOrder(PlayerTraversalOrder.PREVIOUS),
|
||||
canGoToPreviousSentence = canGoToPreviousSentence,
|
||||
onPreviousSentenceClicked = onPreviousSentenceClicked,
|
||||
)
|
||||
|
||||
PlayButton(
|
||||
modifier = Modifier.traversalOrder(PlayerTraversalOrder.PLAY),
|
||||
playbackState = playbackState,
|
||||
breakDuration = breakBetweenPhrases,
|
||||
onMainPlayActionButtonClicked = onMainPlayActionButtonClicked,
|
||||
)
|
||||
|
||||
NextButton(
|
||||
modifier = Modifier.traversalOrder(PlayerTraversalOrder.NEXT),
|
||||
canGoToNextSentence = canGoToNextSentence,
|
||||
onNextSentenceClicked = onNextSentenceClicked,
|
||||
)
|
||||
|
||||
@@ -32,6 +32,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.isTraversalGroup
|
||||
import androidx.compose.ui.semantics.onClick
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
@@ -116,6 +117,9 @@ fun PlayerScreen(
|
||||
var showSpeed by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
// Root of the screen reader order defined by PlayerTraversalOrder, which interleaves the
|
||||
// top bar and the controls.
|
||||
modifier = Modifier.semantics { isTraversalGroup = true },
|
||||
topBar = {
|
||||
PlayerTopBar(
|
||||
uiState = uiState,
|
||||
@@ -191,7 +195,11 @@ private fun PlayerTopBar(
|
||||
showPreferences: () -> Unit,
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = Modifier.shadow(elevation = 2.dp),
|
||||
modifier = Modifier
|
||||
.shadow(elevation = 2.dp)
|
||||
// TopAppBar makes itself a traversal group, which would keep its subtitle settings
|
||||
// button next to the title. Flattened so PlayerTraversalOrder can move it last.
|
||||
.semantics { isTraversalGroup = false },
|
||||
title = {
|
||||
// Animate the title in as it loads, and between records: the record data isn't there on
|
||||
// the first frame, so fade + rise it into place once uiState carries it.
|
||||
@@ -204,7 +212,9 @@ private fun PlayerTopBar(
|
||||
label = "PlayerTitle",
|
||||
) { (emoji, title) ->
|
||||
Row(
|
||||
modifier = Modifier.clearAndSetSemantics {
|
||||
modifier = Modifier
|
||||
.traversalOrder(PlayerTraversalOrder.TITLE)
|
||||
.clearAndSetSemantics {
|
||||
contentDescription = title.translation ?: title.transcription
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@@ -242,7 +252,9 @@ private fun PlayerTopBar(
|
||||
val openSettingsLabel = stringResource(Res.string.settings_open_action_description)
|
||||
IconButton(
|
||||
// Names the action: "double-tap to open settings" rather than the generic "to activate".
|
||||
modifier = Modifier.semantics {
|
||||
modifier = Modifier
|
||||
.traversalOrder(PlayerTraversalOrder.SUBTITLE_SETTINGS)
|
||||
.semantics {
|
||||
onClick(label = openSettingsLabel) {
|
||||
showPreferences()
|
||||
true
|
||||
@@ -265,6 +277,7 @@ private fun BackButton(onBackClicked: () -> Unit) {
|
||||
IconButton(
|
||||
onClick = onBackClicked,
|
||||
modifier = Modifier
|
||||
.traversalOrder(PlayerTraversalOrder.BACK)
|
||||
.semantics {
|
||||
onClick(label = backActionLabel) {
|
||||
onBackClicked()
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package bzh.ajaury.chombev.player.ui
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.semantics.isTraversalGroup
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.traversalIndex
|
||||
|
||||
/**
|
||||
* Screen reader order on the player, which departs from the visual layout: the title and back
|
||||
* button first, then the transport controls, the settings last.
|
||||
*/
|
||||
internal enum class PlayerTraversalOrder {
|
||||
TITLE,
|
||||
BACK,
|
||||
PLAY,
|
||||
PREVIOUS,
|
||||
NEXT,
|
||||
PLAYBACK_SETTINGS,
|
||||
SUBTITLE_SETTINGS,
|
||||
}
|
||||
|
||||
/**
|
||||
* Places this element at [order] in the player's screen reader order. Grouped so that an element
|
||||
* made of several nodes (e.g. the play button and its break ring) moves as a whole.
|
||||
*/
|
||||
internal fun Modifier.traversalOrder(order: PlayerTraversalOrder): Modifier =
|
||||
semantics {
|
||||
isTraversalGroup = true
|
||||
traversalIndex = order.ordinal.toFloat()
|
||||
}
|
||||
Reference in New Issue
Block a user