mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-11-06 18:54:49 +01:00
Configure playback controls for RTL (#1945)
## Description Reverts/fixes parts of #1404 for the playback UI. Generally the playback UI always uses left-to-right for seek bar & media controls even on RTL. Other buttons or texts will be RTL. ### Related issues Fixes #1397 ### Testing Emulator w/ forced RTL English ## Screenshots See https://github.com/damontecres/Wholphin/issues/1397#issuecomment-5553711593 ## AI or LLM usage None
This commit is contained in:
parent
4a567cbcf4
commit
0b995b5404
6 changed files with 185 additions and 214 deletions
|
|
@ -45,9 +45,7 @@ import androidx.compose.ui.input.key.KeyEventType
|
||||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||||
import androidx.compose.ui.input.key.type
|
import androidx.compose.ui.input.key.type
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
|
@ -106,11 +104,9 @@ fun NowPlayingPage(
|
||||||
).value.appPreferences
|
).value.appPreferences
|
||||||
val musicPrefs = preferences.musicPreferences
|
val musicPrefs = preferences.musicPreferences
|
||||||
|
|
||||||
val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr
|
|
||||||
val keyHandler =
|
val keyHandler =
|
||||||
remember(isLtr, preferences) {
|
remember(preferences) {
|
||||||
PlaybackKeyHandler(
|
PlaybackKeyHandler(
|
||||||
isLtr = isLtr,
|
|
||||||
player = player,
|
player = player,
|
||||||
controlsEnabled = true,
|
controlsEnabled = true,
|
||||||
skipWithLeftRight = false,
|
skipWithLeftRight = false,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import kotlin.time.Duration
|
||||||
* Handles [KeyEvent]s during playback on [PlaybackPage]
|
* Handles [KeyEvent]s during playback on [PlaybackPage]
|
||||||
*/
|
*/
|
||||||
class PlaybackKeyHandler(
|
class PlaybackKeyHandler(
|
||||||
private val isLtr: Boolean,
|
|
||||||
private val player: Player,
|
private val player: Player,
|
||||||
private val controlsEnabled: Boolean,
|
private val controlsEnabled: Boolean,
|
||||||
private val skipWithLeftRight: Boolean,
|
private val skipWithLeftRight: Boolean,
|
||||||
|
|
@ -53,17 +52,9 @@ class PlaybackKeyHandler(
|
||||||
if (isDirectionalDpad(it) || isEnterKey(it) || isControllerMedia(it)) {
|
if (isDirectionalDpad(it) || isEnterKey(it) || isControllerMedia(it)) {
|
||||||
if (!controllerViewState.controlsVisible) {
|
if (!controllerViewState.controlsVisible) {
|
||||||
if (skipWithLeftRight && isSkipBack(it)) {
|
if (skipWithLeftRight && isSkipBack(it)) {
|
||||||
if (isLtr) {
|
seekBy(-seekBack)
|
||||||
seekBy(-seekBack)
|
|
||||||
} else {
|
|
||||||
seekBy(seekForward)
|
|
||||||
}
|
|
||||||
} else if (skipWithLeftRight && isSkipForward(it)) {
|
} else if (skipWithLeftRight && isSkipForward(it)) {
|
||||||
if (isLtr) {
|
seekBy(seekForward)
|
||||||
seekBy(seekForward)
|
|
||||||
} else {
|
|
||||||
seekBy(-seekBack)
|
|
||||||
}
|
|
||||||
} else if (isEnterKey(it) && isDpadSeekVisible()) {
|
} else if (isEnterKey(it) && isDpadSeekVisible()) {
|
||||||
// If d-pad seek bar is visible, hide it
|
// If d-pad seek bar is visible, hide it
|
||||||
clearSkipIndicator.invoke()
|
clearSkipIndicator.invoke()
|
||||||
|
|
@ -142,7 +133,7 @@ class PlaybackKeyHandler(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val isBack = if (isLtr) isSkipBack(event) else isSkipForward(event)
|
val isBack = isSkipBack(event)
|
||||||
return when (event.type) {
|
return when (event.type) {
|
||||||
KeyEventType.KeyDown -> {
|
KeyEventType.KeyDown -> {
|
||||||
val repeatCount = event.nativeKeyEvent.repeatCount
|
val repeatCount = event.nativeKeyEvent.repeatCount
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.systemBars
|
||||||
import androidx.compose.foundation.layout.widthIn
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -243,11 +244,9 @@ fun PlaybackPageContent(
|
||||||
)
|
)
|
||||||
seekBarState.onValueChange(skipPosition)
|
seekBarState.onValueChange(skipPosition)
|
||||||
}
|
}
|
||||||
val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr
|
|
||||||
val keyHandler =
|
val keyHandler =
|
||||||
remember(isLtr, preferences) {
|
remember(preferences) {
|
||||||
PlaybackKeyHandler(
|
PlaybackKeyHandler(
|
||||||
isLtr = isLtr,
|
|
||||||
player = player,
|
player = player,
|
||||||
controlsEnabled = state.nextUp == null,
|
controlsEnabled = state.nextUp == null,
|
||||||
skipWithLeftRight = true,
|
skipWithLeftRight = true,
|
||||||
|
|
@ -390,17 +389,19 @@ fun PlaybackPageContent(
|
||||||
Modifier
|
Modifier
|
||||||
.align(Alignment.BottomCenter),
|
.align(Alignment.BottomCenter),
|
||||||
) {
|
) {
|
||||||
DpadSeekOverlay(
|
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||||
player = player,
|
DpadSeekOverlay(
|
||||||
seekPositionMs = skipPosition,
|
player = player,
|
||||||
trickplayInfo = state.currentMediaInfo.trickPlayInfo,
|
seekPositionMs = skipPosition,
|
||||||
trickplayUrlFor = viewModel::getTrickplayUrl,
|
trickplayInfo = state.currentMediaInfo.trickPlayInfo,
|
||||||
modifier =
|
trickplayUrlFor = viewModel::getTrickplayUrl,
|
||||||
Modifier
|
modifier =
|
||||||
.align(Alignment.BottomCenter)
|
Modifier
|
||||||
.padding(bottom = 16.dp)
|
.align(Alignment.BottomCenter)
|
||||||
.fillMaxWidth(.95f),
|
.padding(bottom = 16.dp)
|
||||||
)
|
.fillMaxWidth(.95f),
|
||||||
|
)
|
||||||
|
}
|
||||||
// Clear the overlay after a delay
|
// Clear the overlay after a delay
|
||||||
LaunchedEffect(skipIndicatorDuration) {
|
LaunchedEffect(skipIndicatorDuration) {
|
||||||
delay(1.5.seconds)
|
delay(1.5.seconds)
|
||||||
|
|
@ -426,15 +427,23 @@ fun PlaybackPageContent(
|
||||||
// Show a small progress bar along the bottom of the screen
|
// Show a small progress bar along the bottom of the screen
|
||||||
if (prefs.dpadSeekMode == DpadSeekMode.SEEKBAR_MINIMAL) {
|
if (prefs.dpadSeekMode == DpadSeekMode.SEEKBAR_MINIMAL) {
|
||||||
val percent = skipPosition.toFloat() / player.duration.toFloat()
|
val percent = skipPosition.toFloat() / player.duration.toFloat()
|
||||||
Box(
|
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||||
modifier =
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.align(Alignment.BottomStart)
|
.fillMaxWidth()
|
||||||
.background(MaterialTheme.colorScheme.border)
|
.align(Alignment.BottomCenter),
|
||||||
.clip(RectangleShape)
|
) {
|
||||||
.height(3.dp)
|
Box(
|
||||||
.fillMaxWidth(percent),
|
modifier =
|
||||||
)
|
Modifier
|
||||||
|
.align(Alignment.BottomStart)
|
||||||
|
.background(MaterialTheme.colorScheme.border)
|
||||||
|
.clip(RectangleShape)
|
||||||
|
.height(3.dp)
|
||||||
|
.fillMaxWidth(percent),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import androidx.compose.foundation.relocation.bringIntoViewRequester
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
|
@ -191,6 +192,7 @@ fun PlaybackControls(
|
||||||
onClickPlaybackDialogType = onClickPlaybackDialogType,
|
onClickPlaybackDialogType = onClickPlaybackDialogType,
|
||||||
modifier = Modifier.align(Alignment.CenterStart),
|
modifier = Modifier.align(Alignment.CenterStart),
|
||||||
)
|
)
|
||||||
|
|
||||||
PlaybackButtons(
|
PlaybackButtons(
|
||||||
player = player,
|
player = player,
|
||||||
initialFocusRequester = initialFocusRequester,
|
initialFocusRequester = initialFocusRequester,
|
||||||
|
|
@ -204,6 +206,7 @@ fun PlaybackControls(
|
||||||
skipBackOnResume = skipBackOnResume,
|
skipBackOnResume = skipBackOnResume,
|
||||||
modifier = Modifier.align(Alignment.Center),
|
modifier = Modifier.align(Alignment.Center),
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.align(Alignment.CenterEnd),
|
modifier = Modifier.align(Alignment.CenterEnd),
|
||||||
) {
|
) {
|
||||||
|
|
@ -286,31 +289,40 @@ fun SeekTimecodes(
|
||||||
durationMs: Long,
|
durationMs: Long,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Row(
|
val currentLayoutDirection = LocalLayoutDirection.current
|
||||||
modifier = modifier,
|
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
Row(
|
||||||
) {
|
modifier = modifier,
|
||||||
val resources = LocalResources.current
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
val positionSec = positionMs / 1000
|
) {
|
||||||
val remainingSec = (durationMs - positionMs) / 1000
|
val resources = LocalResources.current
|
||||||
val positionText = remember(positionSec) { resources.formatDuration(positionSec.seconds) }
|
val positionSec = positionMs / 1000
|
||||||
val remainingText = remember(remainingSec) { "-${resources.formatDuration(remainingSec.seconds)}" }
|
val remainingSec = (durationMs - positionMs) / 1000
|
||||||
Text(
|
val positionText =
|
||||||
text = positionText,
|
remember(positionSec) { resources.formatDuration(positionSec.seconds) }
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
val remainingText =
|
||||||
style = MaterialTheme.typography.labelLarge,
|
remember(remainingSec) { "-${resources.formatDuration(remainingSec.seconds)}" }
|
||||||
modifier =
|
CompositionLocalProvider(LocalLayoutDirection provides currentLayoutDirection) {
|
||||||
Modifier
|
Text(
|
||||||
.padding(8.dp),
|
text = positionText,
|
||||||
)
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
Text(
|
style = MaterialTheme.typography.labelLarge,
|
||||||
text = remainingText,
|
modifier =
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
Modifier
|
||||||
style = MaterialTheme.typography.labelLarge,
|
.padding(8.dp),
|
||||||
modifier =
|
)
|
||||||
Modifier
|
}
|
||||||
.padding(8.dp),
|
CompositionLocalProvider(LocalLayoutDirection provides currentLayoutDirection) {
|
||||||
)
|
Text(
|
||||||
|
text = remainingText,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.padding(8.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,61 +401,62 @@ fun PlaybackButtons(
|
||||||
seekForward: Duration,
|
seekForward: Duration,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr
|
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier.focusGroup(),
|
modifier = modifier.focusGroup(),
|
||||||
horizontalArrangement = Arrangement.spacedBy(buttonSpacing),
|
horizontalArrangement = Arrangement.spacedBy(buttonSpacing),
|
||||||
) {
|
) {
|
||||||
PlaybackButton(
|
PlaybackButton(
|
||||||
iconRes = if (isLtr) R.drawable.baseline_skip_previous_24 else R.drawable.baseline_skip_next_24,
|
iconRes = R.drawable.baseline_skip_previous_24,
|
||||||
onClick = {
|
onClick = {
|
||||||
onControllerInteraction.invoke()
|
onControllerInteraction.invoke()
|
||||||
onPlaybackActionClick.invoke(PlaybackAction.Previous)
|
onPlaybackActionClick.invoke(PlaybackAction.Previous)
|
||||||
},
|
},
|
||||||
enabled = previousEnabled,
|
enabled = previousEnabled,
|
||||||
onControllerInteraction = onControllerInteraction,
|
onControllerInteraction = onControllerInteraction,
|
||||||
)
|
)
|
||||||
PlaybackButton(
|
PlaybackButton(
|
||||||
iconRes = if (isLtr) R.drawable.baseline_fast_rewind_24 else R.drawable.baseline_fast_forward_24,
|
iconRes = R.drawable.baseline_fast_rewind_24,
|
||||||
onClick = {
|
onClick = {
|
||||||
onControllerInteraction.invoke()
|
onControllerInteraction.invoke()
|
||||||
player.seekBack(seekBack)
|
player.seekBack(seekBack)
|
||||||
},
|
},
|
||||||
onControllerInteraction = onControllerInteraction,
|
onControllerInteraction = onControllerInteraction,
|
||||||
)
|
)
|
||||||
PlaybackButton(
|
PlaybackButton(
|
||||||
modifier = Modifier.focusRequester(initialFocusRequester),
|
modifier = Modifier.focusRequester(initialFocusRequester),
|
||||||
iconRes = if (showPlay) R.drawable.baseline_play_arrow_24 else R.drawable.baseline_pause_24,
|
iconRes = if (showPlay) R.drawable.baseline_play_arrow_24 else R.drawable.baseline_pause_24,
|
||||||
onClick = {
|
onClick = {
|
||||||
onControllerInteraction.invoke()
|
onControllerInteraction.invoke()
|
||||||
if (showPlay) {
|
if (showPlay) {
|
||||||
player.play()
|
player.play()
|
||||||
skipBackOnResume?.let {
|
skipBackOnResume?.let {
|
||||||
player.seekBack(it)
|
player.seekBack(it)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
player.pause()
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
player.pause()
|
onControllerInteraction = onControllerInteraction,
|
||||||
}
|
)
|
||||||
},
|
PlaybackButton(
|
||||||
onControllerInteraction = onControllerInteraction,
|
iconRes = R.drawable.baseline_fast_forward_24,
|
||||||
)
|
onClick = {
|
||||||
PlaybackButton(
|
onControllerInteraction.invoke()
|
||||||
iconRes = if (isLtr) R.drawable.baseline_fast_forward_24 else R.drawable.baseline_fast_rewind_24,
|
player.seekForward(seekForward)
|
||||||
onClick = {
|
},
|
||||||
onControllerInteraction.invoke()
|
onControllerInteraction = onControllerInteraction,
|
||||||
player.seekForward(seekForward)
|
)
|
||||||
},
|
PlaybackButton(
|
||||||
onControllerInteraction = onControllerInteraction,
|
iconRes = R.drawable.baseline_skip_next_24,
|
||||||
)
|
onClick = {
|
||||||
PlaybackButton(
|
onControllerInteraction.invoke()
|
||||||
iconRes = if (isLtr) R.drawable.baseline_skip_next_24 else R.drawable.baseline_skip_previous_24,
|
onPlaybackActionClick.invoke(PlaybackAction.Next)
|
||||||
onClick = {
|
},
|
||||||
onControllerInteraction.invoke()
|
enabled = nextEnabled,
|
||||||
onPlaybackActionClick.invoke(PlaybackAction.Next)
|
onControllerInteraction = onControllerInteraction,
|
||||||
},
|
)
|
||||||
enabled = nextEnabled,
|
}
|
||||||
onControllerInteraction = onControllerInteraction,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.heightIn
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableLongStateOf
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
|
|
@ -40,8 +41,10 @@ import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
|
|
@ -254,39 +257,41 @@ fun PlaybackOverlay(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trickplay
|
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||||
AnimatedVisibility(
|
// Trickplay
|
||||||
visible = controllerViewState.controlsVisible && seekProgressPercent >= 0 && seekBarFocused,
|
AnimatedVisibility(
|
||||||
enter =
|
visible = controllerViewState.controlsVisible && seekProgressPercent >= 0 && seekBarFocused,
|
||||||
expandVertically(
|
enter =
|
||||||
spring(
|
expandVertically(
|
||||||
stiffness = Spring.StiffnessMedium,
|
spring(
|
||||||
visibilityThreshold = IntSize.VisibilityThreshold,
|
stiffness = Spring.StiffnessMedium,
|
||||||
),
|
visibilityThreshold = IntSize.VisibilityThreshold,
|
||||||
) + fadeIn(),
|
),
|
||||||
exit = shrinkVertically() + fadeOut(),
|
) + fadeIn(),
|
||||||
) {
|
exit = shrinkVertically() + fadeOut(),
|
||||||
Box(
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.align(Alignment.Center)
|
|
||||||
.fillMaxWidth(.95f),
|
|
||||||
) {
|
) {
|
||||||
Column(
|
Box(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.align(Alignment.BottomStart)
|
.align(Alignment.Center)
|
||||||
.offsetByPercent(
|
.fillMaxWidth(.95f),
|
||||||
xPercentage = seekProgressPercent.coerceIn(0f, 1f),
|
|
||||||
).padding(bottom = controllerHeight - titleHeight - subtitleHeight),
|
|
||||||
) {
|
) {
|
||||||
TrickplayPreview(
|
Column(
|
||||||
seekProgressMs = seekProgressMs,
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
trickplayInfo = trickplayInfo,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
trickplayUrlFor = trickplayUrlFor,
|
modifier =
|
||||||
)
|
Modifier
|
||||||
|
.align(Alignment.BottomStart)
|
||||||
|
.offsetByPercent(
|
||||||
|
xPercentage = seekProgressPercent.coerceIn(0f, 1f),
|
||||||
|
).padding(bottom = controllerHeight - titleHeight - subtitleHeight),
|
||||||
|
) {
|
||||||
|
TrickplayPreview(
|
||||||
|
seekProgressMs = seekProgressMs,
|
||||||
|
trickplayInfo = trickplayInfo,
|
||||||
|
trickplayUrlFor = trickplayUrlFor,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,6 @@ import androidx.compose.ui.graphics.StrokeCap
|
||||||
import androidx.compose.ui.input.key.KeyEventType
|
import androidx.compose.ui.input.key.KeyEventType
|
||||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||||
import androidx.compose.ui.input.key.type
|
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.compose.ui.unit.dp
|
||||||
import androidx.tv.material3.MaterialTheme
|
import androidx.tv.material3.MaterialTheme
|
||||||
import com.github.damontecres.wholphin.ui.playback.ControllerViewState
|
import com.github.damontecres.wholphin.ui.playback.ControllerViewState
|
||||||
|
|
@ -202,7 +200,6 @@ private fun SeekBarDisplay(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr
|
|
||||||
val color = MaterialTheme.colorScheme.border
|
val color = MaterialTheme.colorScheme.border
|
||||||
val onSurface = MaterialTheme.colorScheme.onSurface
|
val onSurface = MaterialTheme.colorScheme.onSurface
|
||||||
|
|
||||||
|
|
@ -225,13 +222,7 @@ private fun SeekBarDisplay(
|
||||||
Timber.v("Ignoring %s", event)
|
Timber.v("Ignoring %s", event)
|
||||||
return@onPreviewKeyEvent false
|
return@onPreviewKeyEvent false
|
||||||
}
|
}
|
||||||
val seekBack =
|
if (isDpadLeft(event)) {
|
||||||
if (isLtr) {
|
|
||||||
isDpadLeft(event)
|
|
||||||
} else {
|
|
||||||
isDpadRight(event)
|
|
||||||
}
|
|
||||||
if (seekBack) {
|
|
||||||
when (event.type) {
|
when (event.type) {
|
||||||
KeyEventType.KeyDown -> {
|
KeyEventType.KeyDown -> {
|
||||||
val repeatCount = event.nativeKeyEvent.repeatCount
|
val repeatCount = event.nativeKeyEvent.repeatCount
|
||||||
|
|
@ -300,68 +291,34 @@ private fun SeekBarDisplay(
|
||||||
strokeWidth = size.height,
|
strokeWidth = size.height,
|
||||||
cap = StrokeCap.Round,
|
cap = StrokeCap.Round,
|
||||||
)
|
)
|
||||||
if (isLtr) {
|
drawLine(
|
||||||
drawLine(
|
color = onSurface.copy(alpha = .65f),
|
||||||
color = onSurface.copy(alpha = .65f),
|
start = Offset(x = 0f, y = yOffset),
|
||||||
start = Offset(x = 0f, y = yOffset),
|
end =
|
||||||
end =
|
Offset(
|
||||||
Offset(
|
x = size.width.times(bufferedProgress),
|
||||||
x = size.width.times(bufferedProgress),
|
y = yOffset,
|
||||||
y = yOffset,
|
),
|
||||||
),
|
strokeWidth = size.height,
|
||||||
strokeWidth = size.height,
|
cap = StrokeCap.Round,
|
||||||
cap = StrokeCap.Round,
|
)
|
||||||
)
|
drawLine(
|
||||||
drawLine(
|
color = color,
|
||||||
color = color,
|
start = Offset(x = 0f, y = yOffset),
|
||||||
start = Offset(x = 0f, y = yOffset),
|
end =
|
||||||
end =
|
Offset(
|
||||||
Offset(
|
x = size.width.times(progress),
|
||||||
x = size.width.times(progress),
|
y = yOffset,
|
||||||
y = yOffset,
|
),
|
||||||
),
|
strokeWidth = size.height,
|
||||||
strokeWidth = size.height,
|
cap = StrokeCap.Round,
|
||||||
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(
|
drawCircle(
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
radius = size.height + 2,
|
radius = size.height + 2,
|
||||||
center =
|
center =
|
||||||
Offset(
|
Offset(
|
||||||
x =
|
x = size.width.times(progress),
|
||||||
if (isLtr) {
|
|
||||||
size.width.times(progress)
|
|
||||||
} else {
|
|
||||||
size.width - size.width.times(progress)
|
|
||||||
},
|
|
||||||
y = yOffset,
|
y = yOffset,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue