From 9eff22e939fff436fcd5eafac7101c99eb27107d Mon Sep 17 00:00:00 2001 From: Damontecres Date: Mon, 25 May 2026 13:27:34 -0400 Subject: [PATCH] Fix several issues with right-to-left locales (#1404) ## Description Fix several issues when the current locale is right-to-left - Fixes the backdrop dynamic colors - Fixes mirroring of playback controls, including seeking ### Related issues Fixes #1397 Fixes #1398 ### Testing Emulator w/ forced RTL in developer options ## Screenshots rtl_backdrop Large rtl_controls Large ## AI or LLM usage None --- .../ui/detail/music/NowPlayingPage.kt | 6 +- .../damontecres/wholphin/ui/nav/Backdrop.kt | 16 +- .../wholphin/ui/playback/KeyIdentifier.kt | 8 + .../wholphin/ui/playback/PlaybackDialog.kt | 16 +- .../ui/playback/PlaybackKeyHandler.kt | 21 +- .../wholphin/ui/playback/PlaybackPage.kt | 42 ++-- .../ui/playback/overlay/ChapterRowOverlay.kt | 8 +- .../ui/playback/overlay/PlaybackControls.kt | 11 +- .../wholphin/ui/playback/overlay/SeekBar.kt | 203 +++++++++++------- 9 files changed, 214 insertions(+), 117 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingPage.kt index a9d43a27..5b571e4a 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingPage.kt @@ -45,7 +45,9 @@ import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.type import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.media3.common.util.UnstableApi @@ -106,9 +108,11 @@ fun NowPlayingPage( ).value.appPreferences val musicPrefs = preferences.musicPreferences + val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr val keyHandler = - remember(preferences) { + remember(isLtr, preferences) { PlaybackKeyHandler( + isLtr = isLtr, player = player, controlsEnabled = true, skipWithLeftRight = false, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Backdrop.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Backdrop.kt index 81028501..188ad347 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Backdrop.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Backdrop.kt @@ -23,6 +23,8 @@ import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.LayoutDirection import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.tv.material3.MaterialTheme @@ -75,6 +77,7 @@ fun Backdrop( useExistingImageAsPlaceholder: Boolean = false, crossfadeDuration: Duration = 800.milliseconds, ) { + val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl val baseBackgroundColor = MaterialTheme.colorScheme.background if (backdrop.hasColors && (backdropStyle == BackdropStyle.BACKDROP_DYNAMIC_COLOR || backdropStyle == BackdropStyle.UNRECOGNIZED) @@ -100,12 +103,14 @@ fun Backdrop( .fillMaxSize() .drawBehind { drawRect(color = baseBackgroundColor) + val start = if (isRtl) size.width else 0f + val end = if (isRtl) 0f else size.width // Top Left (Vibrant/Muted) drawRect( brush = Brush.radialGradient( colors = listOf(animSecondary, Color.Transparent), - center = Offset(0f, 0f), + center = Offset(start, 0f), radius = size.width * 0.8f, ), ) @@ -114,7 +119,7 @@ fun Backdrop( brush = Brush.radialGradient( colors = listOf(animPrimary, Color.Transparent), - center = Offset(size.width, size.height), + center = Offset(end, size.height), radius = size.width * 0.8f, ), ) @@ -127,7 +132,7 @@ fun Backdrop( baseBackgroundColor, Color.Transparent, ), - center = Offset(0f, size.height), + center = Offset(start, size.height), radius = size.width * 0.8f, ), ) @@ -136,7 +141,7 @@ fun Backdrop( brush = Brush.radialGradient( colors = listOf(animTertiary, Color.Transparent), - center = Offset(size.width, 0f), + center = Offset(end, 0f), radius = size.width * 0.8f, ), ) @@ -165,6 +170,7 @@ fun Backdrop( .fillMaxWidth(.7f) .graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen) .drawWithContent { + val start = if (isRtl) size.width else 0f drawContent() if (drawerIsOpen) { drawRect( @@ -190,7 +196,7 @@ fun Backdrop( brush = Brush.horizontalGradient( colors = listOf(Color.Transparent, Color.Black), - startX = 0f, + startX = start, endX = size.width * 0.6f, ), blendMode = BlendMode.DstIn, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/KeyIdentifier.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/KeyIdentifier.kt index 1915e02b..eed379e7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/KeyIdentifier.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/KeyIdentifier.kt @@ -32,6 +32,14 @@ fun isControllerMedia(event: KeyEvent) = event.key == Key.ButtonL1 || event.key == Key.ButtonL2 +fun isDpadLeft(event: KeyEvent) = + event.key == Key.DirectionLeft || + event.key == Key.SystemNavigationLeft + +fun isDpadRight(event: KeyEvent) = + event.key == Key.DirectionRight || + event.key == Key.SystemNavigationRight + fun isSkipBack(event: KeyEvent) = event.key == Key.DirectionLeft || event.key == Key.ButtonL1 || diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackDialog.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackDialog.kt index 5b0bd5d8..c3bff78c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackDialog.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackDialog.kt @@ -21,8 +21,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -85,6 +87,10 @@ fun PlaybackDialog( onPlaybackActionClick: (PlaybackAction) -> Unit, onChangeSubtitleDelay: (Duration) -> Unit, ) { + val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr + // TODO, shouldn't this work out of the box? + val leftGravity = remember(isLtr) { if (isLtr) Gravity.START else Gravity.END } + val rightGravity = remember(isLtr) { if (isLtr) Gravity.END else Gravity.START } when (type) { PlaybackDialogType.DEBUG -> { throw IllegalStateException("Should not open a dialog with " + PlaybackDialogType.DEBUG) @@ -113,7 +119,7 @@ fun PlaybackDialog( onDismissRequest.invoke() onPlaybackActionClick.invoke(PlaybackAction.SearchCaptions) }, - gravity = Gravity.END, + gravity = rightGravity, ) } @@ -167,7 +173,7 @@ fun PlaybackDialog( onClickPlaybackDialogType(choice.data) } }, - gravity = Gravity.START, + gravity = leftGravity, ) } @@ -182,7 +188,7 @@ fun PlaybackDialog( onSelectChoice = { _, choice -> onPlaybackActionClick.invoke(PlaybackAction.ToggleAudio(choice.index)) }, - gravity = Gravity.END, + gravity = rightGravity, ) } @@ -205,7 +211,7 @@ fun PlaybackDialog( onSelectChoice = { _, value -> onPlaybackActionClick.invoke(PlaybackAction.PlaybackSpeed(value.data)) }, - gravity = Gravity.START, + gravity = leftGravity, ) } @@ -228,7 +234,7 @@ fun PlaybackDialog( onSelectChoice = { _, choice -> onPlaybackActionClick.invoke(PlaybackAction.Scale(choice.data)) }, - gravity = Gravity.START, + gravity = leftGravity, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackKeyHandler.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackKeyHandler.kt index a7cd4bb1..7209fbd9 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackKeyHandler.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackKeyHandler.kt @@ -15,6 +15,7 @@ import kotlin.time.Duration * Handles [KeyEvent]s during playback on [PlaybackPage] */ class PlaybackKeyHandler( + private val isLtr: Boolean, private val player: Player, private val controlsEnabled: Boolean, private val skipWithLeftRight: Boolean, @@ -47,11 +48,21 @@ class PlaybackKeyHandler( if (isDirectionalDpad(it) || isEnterKey(it) || isControllerMedia(it)) { if (!controllerViewState.controlsVisible) { if (skipWithLeftRight && isSkipBack(it)) { - updateSkipIndicator(-seekBack.inWholeMilliseconds) - player.seekBack(seekBack) + if (isLtr) { + updateSkipIndicator(-seekBack.inWholeMilliseconds) + player.seekBack(seekBack) + } else { + updateSkipIndicator(seekForward.inWholeMilliseconds) + player.seekForward(seekForward) + } } else if (skipWithLeftRight && isSkipForward(it)) { - player.seekForward(seekForward) - updateSkipIndicator(seekForward.inWholeMilliseconds) + if (isLtr) { + player.seekForward(seekForward) + updateSkipIndicator(seekForward.inWholeMilliseconds) + } else { + player.seekBack(seekBack) + updateSkipIndicator(seekBack.inWholeMilliseconds) + } } else if (oneClickPause && isEnterKey(it)) { val wasPlaying = player.isPlaying Util.handlePlayPauseButtonAction(player) @@ -127,7 +138,7 @@ class PlaybackKeyHandler( return false } - val isBack = isSkipBack(event) + val isBack = if (isLtr) isSkipBack(event) else isSkipForward(event) return when (event.type) { KeyEventType.KeyDown -> { val repeatCount = event.nativeKeyEvent.repeatCount diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt index cc004ef2..020a1eff 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt @@ -50,7 +50,9 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.window.Dialog @@ -234,25 +236,29 @@ fun PlaybackPageContent( skipIndicatorDuration += delta skipPosition = player.currentPosition } + val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr val keyHandler = - PlaybackKeyHandler( - player = player, - controlsEnabled = state.nextUp == null, - skipWithLeftRight = true, - seekForward = preferences.appPreferences.playbackPreferences.skipForwardMs.milliseconds, - seekBack = preferences.appPreferences.playbackPreferences.skipBackMs.milliseconds, - getDurationMs = { player.duration.coerceAtLeast(0L) }, - controllerViewState = controllerViewState, - updateSkipIndicator = updateSkipIndicator, - skipBackOnResume = preferences.appPreferences.playbackPreferences.skipBackOnResume, - onInteraction = viewModel::reportInteraction, - oneClickPause = preferences.appPreferences.playbackPreferences.oneClickPause, - onStop = { - player.stop() - viewModel.navigationManager.goBack() - }, - onPlaybackDialogTypeClick = { playbackDialog = it }, - ) + remember(isLtr, preferences) { + PlaybackKeyHandler( + isLtr = isLtr, + player = player, + controlsEnabled = state.nextUp == null, + skipWithLeftRight = true, + seekForward = preferences.appPreferences.playbackPreferences.skipForwardMs.milliseconds, + seekBack = preferences.appPreferences.playbackPreferences.skipBackMs.milliseconds, + getDurationMs = { player.duration.coerceAtLeast(0L) }, + controllerViewState = controllerViewState, + updateSkipIndicator = updateSkipIndicator, + skipBackOnResume = preferences.appPreferences.playbackPreferences.skipBackOnResume, + onInteraction = viewModel::reportInteraction, + oneClickPause = preferences.appPreferences.playbackPreferences.oneClickPause, + onStop = { + player.stop() + viewModel.navigationManager.goBack() + }, + onPlaybackDialogTypeClick = { playbackDialog = it }, + ) + } val onPlaybackActionClick: (PlaybackAction) -> Unit = { when (it) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/ChapterRowOverlay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/ChapterRowOverlay.kt index 2270e5f7..30254061 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/ChapterRowOverlay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/ChapterRowOverlay.kt @@ -22,7 +22,9 @@ import androidx.compose.ui.focus.focusProperties import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRestorer import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.media3.common.Player import androidx.tv.material3.MaterialTheme @@ -47,6 +49,7 @@ fun ChapterRowOverlay( onChangeState: (OverlayViewState) -> Unit, modifier: Modifier = Modifier, ) { + val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr val chapterInteractionSources = remember(chapters.size) { List(chapters.size) { MutableInteractionSource() } } val bringIntoViewRequester = remember { BringIntoViewRequester() } @@ -135,7 +138,10 @@ fun ChapterRowOverlay( index == 0, Modifier.focusProperties { // Prevent scrolling left on first card to prevent moving down - left = FocusRequester.Cancel + left = + if (isLtr) FocusRequester.Cancel else FocusRequester.Default + right = + if (isLtr) FocusRequester.Default else FocusRequester.Cancel }, ), ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackControls.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackControls.kt index f423b8ca..820e634f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackControls.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackControls.kt @@ -42,10 +42,12 @@ import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.isSpecified import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog @@ -368,12 +370,13 @@ fun PlaybackButtons( seekForward: Duration, modifier: Modifier = Modifier, ) { + val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr Row( modifier = modifier.focusGroup(), horizontalArrangement = Arrangement.spacedBy(buttonSpacing), ) { PlaybackButton( - iconRes = R.drawable.baseline_skip_previous_24, + iconRes = if (isLtr) R.drawable.baseline_skip_previous_24 else R.drawable.baseline_skip_next_24, onClick = { onControllerInteraction.invoke() onPlaybackActionClick.invoke(PlaybackAction.Previous) @@ -382,7 +385,7 @@ fun PlaybackButtons( onControllerInteraction = onControllerInteraction, ) PlaybackButton( - iconRes = R.drawable.baseline_fast_rewind_24, + iconRes = if (isLtr) R.drawable.baseline_fast_rewind_24 else R.drawable.baseline_fast_forward_24, onClick = { onControllerInteraction.invoke() player.seekBack(seekBack) @@ -406,7 +409,7 @@ fun PlaybackButtons( onControllerInteraction = onControllerInteraction, ) PlaybackButton( - iconRes = R.drawable.baseline_fast_forward_24, + iconRes = if (isLtr) R.drawable.baseline_fast_forward_24 else R.drawable.baseline_fast_rewind_24, onClick = { onControllerInteraction.invoke() player.seekForward(seekForward) @@ -414,7 +417,7 @@ fun PlaybackButtons( onControllerInteraction = onControllerInteraction, ) PlaybackButton( - iconRes = R.drawable.baseline_skip_next_24, + iconRes = if (isLtr) R.drawable.baseline_skip_next_24 else R.drawable.baseline_skip_previous_24, onClick = { onControllerInteraction.invoke() onPlaybackActionClick.invoke(PlaybackAction.Next) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/SeekBar.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/SeekBar.kt index 1ca67657..d0dfec31 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/SeekBar.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/SeekBar.kt @@ -18,7 +18,6 @@ package com.github.damontecres.wholphin.ui.playback.overlay * limitations under the License. */ -import android.view.KeyEvent import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.Canvas import androidx.compose.foundation.focusable @@ -44,11 +43,16 @@ import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.type +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.tv.material3.MaterialTheme import com.github.damontecres.wholphin.ui.playback.ControllerViewState import com.github.damontecres.wholphin.ui.playback.calculateSeekAccelerationMultiplier +import com.github.damontecres.wholphin.ui.playback.isDpadLeft +import com.github.damontecres.wholphin.ui.playback.isDpadRight import kotlinx.coroutines.FlowPreview +import timber.log.Timber import kotlin.time.Duration /** @@ -174,6 +178,7 @@ private fun SeekBarDisplay( modifier: Modifier = Modifier, enabled: Boolean = true, ) { + val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr val color = MaterialTheme.colorScheme.border val onSurface = MaterialTheme.colorScheme.onSurface @@ -192,70 +197,75 @@ private fun SeekBarDisplay( .height(animatedIndicatorHeight) .padding(horizontal = 4.dp) .onPreviewKeyEvent { event -> - when (event.nativeKeyEvent.keyCode) { - KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT -> { - when (event.type) { - KeyEventType.KeyDown -> { - val repeatCount = event.nativeKeyEvent.repeatCount - if (repeatCount > 0) { - leftHandledByRepeat = true - onLeft.invoke( - calculateSeekAccelerationMultiplier( - repeatCount = repeatCount, - durationMs = durationMs, - ), - ) - } else { - leftHandledByRepeat = false - } - } - - KeyEventType.KeyUp -> { - if (!leftHandledByRepeat) { - onLeft.invoke(1) - } + if (!isDpadLeft(event) && !isDpadRight(event)) { + Timber.v("Ignoring %s", event) + return@onPreviewKeyEvent false + } + val seekBack = + if (isLtr) { + isDpadLeft(event) + } else { + isDpadRight(event) + } + if (seekBack) { + when (event.type) { + KeyEventType.KeyDown -> { + val repeatCount = event.nativeKeyEvent.repeatCount + if (repeatCount > 0) { + leftHandledByRepeat = true + onLeft.invoke( + calculateSeekAccelerationMultiplier( + repeatCount = repeatCount, + durationMs = durationMs, + ), + ) + } else { leftHandledByRepeat = false } - - else -> { - return@onPreviewKeyEvent false - } } - return@onPreviewKeyEvent true - } - KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT -> { - when (event.type) { - KeyEventType.KeyDown -> { - val repeatCount = event.nativeKeyEvent.repeatCount - if (repeatCount > 0) { - rightHandledByRepeat = true - onRight.invoke( - calculateSeekAccelerationMultiplier( - repeatCount = repeatCount, - durationMs = durationMs, - ), - ) - } else { - rightHandledByRepeat = false - } + KeyEventType.KeyUp -> { + if (!leftHandledByRepeat) { + onLeft.invoke(1) } + leftHandledByRepeat = false + } - KeyEventType.KeyUp -> { - if (!rightHandledByRepeat) { - onRight.invoke(1) - } + else -> { + return@onPreviewKeyEvent false + } + } + return@onPreviewKeyEvent true + } else { + when (event.type) { + KeyEventType.KeyDown -> { + val repeatCount = event.nativeKeyEvent.repeatCount + if (repeatCount > 0) { + rightHandledByRepeat = true + onRight.invoke( + calculateSeekAccelerationMultiplier( + repeatCount = repeatCount, + durationMs = durationMs, + ), + ) + } else { rightHandledByRepeat = false } - - else -> { - return@onPreviewKeyEvent false - } } - return@onPreviewKeyEvent true + + KeyEventType.KeyUp -> { + if (!rightHandledByRepeat) { + onRight.invoke(1) + } + rightHandledByRepeat = false + } + + else -> { + return@onPreviewKeyEvent false + } } + return@onPreviewKeyEvent true } - false }.focusable(enabled = enabled, interactionSource = interactionSource), onDraw = { val yOffset = size.height.div(2) @@ -266,33 +276,70 @@ private fun SeekBarDisplay( strokeWidth = size.height, cap = StrokeCap.Round, ) - drawLine( - color = onSurface.copy(alpha = .65f), - start = Offset(x = 0f, y = yOffset), - end = - Offset( - x = size.width.times(bufferedProgress), - y = yOffset, - ), - strokeWidth = size.height, - cap = StrokeCap.Round, - ) - drawLine( - color = color, - start = Offset(x = 0f, y = yOffset), - end = - Offset( -// x = size.width.times(if (isSelected) seekProgress else progress), - x = size.width.times(progress), - y = yOffset, - ), - strokeWidth = size.height, - cap = StrokeCap.Round, - ) + if (isLtr) { + drawLine( + color = onSurface.copy(alpha = .65f), + start = Offset(x = 0f, y = yOffset), + end = + Offset( + x = size.width.times(bufferedProgress), + y = yOffset, + ), + strokeWidth = size.height, + cap = StrokeCap.Round, + ) + drawLine( + color = color, + start = Offset(x = 0f, y = yOffset), + end = + Offset( + x = size.width.times(progress), + y = yOffset, + ), + strokeWidth = size.height, + cap = StrokeCap.Round, + ) + } else { + drawLine( + color = onSurface.copy(alpha = .65f), + start = + Offset( + x = size.width - size.width.times(bufferedProgress), + y = yOffset, + ), + end = + Offset( + x = size.width, + y = yOffset, + ), + strokeWidth = size.height, + cap = StrokeCap.Round, + ) + drawLine( + color = color, + start = Offset(x = size.width - size.width.times(progress), y = yOffset), + end = + Offset( + x = size.width, + y = yOffset, + ), + strokeWidth = size.height, + cap = StrokeCap.Round, + ) + } drawCircle( color = Color.White, radius = size.height + 2, - center = Offset(x = size.width.times(progress), y = yOffset), + center = + Offset( + x = + if (isLtr) { + size.width.times(progress) + } else { + size.width - size.width.times(progress) + }, + y = yOffset, + ), ) }, )