Remove skip button with back or timer & show it in controls

This commit is contained in:
Damontecres 2025-10-14 16:25:09 -04:00
parent d1e9561eae
commit c6b7e0f4de
No known key found for this signature in database
3 changed files with 53 additions and 13 deletions

View file

@ -65,6 +65,8 @@ import com.github.damontecres.dolphin.util.ExceptionHandler
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jellyfin.sdk.model.api.MediaSegmentDto
import org.jellyfin.sdk.model.extensions.ticks
import timber.log.Timber import timber.log.Timber
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
@ -120,6 +122,7 @@ fun PlaybackControls(
seekBack: Duration, seekBack: Duration,
skipBackOnResume: Duration?, skipBackOnResume: Duration?,
seekForward: Duration, seekForward: Duration,
currentSegment: MediaSegmentDto?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
initialFocusRequester: FocusRequester = remember { FocusRequester() }, initialFocusRequester: FocusRequester = remember { FocusRequester() },
seekBarInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() }, seekBarInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@ -189,18 +192,37 @@ fun PlaybackControls(
skipBackOnResume = skipBackOnResume, skipBackOnResume = skipBackOnResume,
modifier = Modifier.align(Alignment.Center), modifier = Modifier.align(Alignment.Center),
) )
RightPlaybackButtons( Row(
subtitleStreams = subtitleStreams,
onControllerInteraction = onControllerInteraction,
onControllerInteractionForDialog = onControllerInteractionForDialog,
onPlaybackActionClick = onPlaybackActionClick,
subtitleIndex = subtitleIndex,
audioStreams = audioStreams,
audioIndex = audioIndex,
playbackSpeed = playbackSpeed,
scale = scale,
modifier = Modifier.align(Alignment.CenterEnd), modifier = Modifier.align(Alignment.CenterEnd),
) ) {
currentSegment?.let { segment ->
Button(
onClick = {
playerControls.seekTo(segment.endTicks.ticks.inWholeMilliseconds)
},
modifier =
Modifier
.align(Alignment.CenterVertically)
.padding(end = 32.dp),
) {
Text(
text = "Skip ${segment.type.serialName}",
)
}
}
RightPlaybackButtons(
subtitleStreams = subtitleStreams,
onControllerInteraction = onControllerInteraction,
onControllerInteractionForDialog = onControllerInteractionForDialog,
onPlaybackActionClick = onPlaybackActionClick,
subtitleIndex = subtitleIndex,
audioStreams = audioStreams,
audioIndex = audioIndex,
playbackSpeed = playbackSpeed,
scale = scale,
modifier = Modifier,
)
}
} }
} }
} }

View file

@ -53,6 +53,7 @@ import com.github.damontecres.dolphin.ui.ifElse
import com.github.damontecres.dolphin.ui.isNotNullOrBlank import com.github.damontecres.dolphin.ui.isNotNullOrBlank
import com.github.damontecres.dolphin.ui.letNotEmpty import com.github.damontecres.dolphin.ui.letNotEmpty
import com.github.damontecres.dolphin.ui.tryRequestFocus import com.github.damontecres.dolphin.ui.tryRequestFocus
import org.jellyfin.sdk.model.api.MediaSegmentDto
import org.jellyfin.sdk.model.api.TrickplayInfo import org.jellyfin.sdk.model.api.TrickplayInfo
import kotlin.time.Duration import kotlin.time.Duration
@ -84,6 +85,7 @@ fun PlaybackOverlay(
moreButtonOptions: MoreButtonOptions, moreButtonOptions: MoreButtonOptions,
currentPlayback: CurrentPlayback?, currentPlayback: CurrentPlayback?,
audioStreams: List<AudioStream>, audioStreams: List<AudioStream>,
currentSegment: MediaSegmentDto?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
subtitle: String? = null, subtitle: String? = null,
trickplayInfo: TrickplayInfo? = null, trickplayInfo: TrickplayInfo? = null,
@ -161,6 +163,7 @@ fun PlaybackOverlay(
onNextStateFocus = { onNextStateFocus = {
nextState?.let { state = it } nextState?.let { state = it }
}, },
currentSegment = currentSegment,
modifier = modifier =
Modifier Modifier
// Don't use key events because this control has vertical items so up/down is tough to manage // Don't use key events because this control has vertical items so up/down is tough to manage
@ -413,6 +416,7 @@ fun Controller(
currentPlayback: CurrentPlayback?, currentPlayback: CurrentPlayback?,
audioStreams: List<AudioStream>, audioStreams: List<AudioStream>,
nextState: OverlayViewState?, nextState: OverlayViewState?,
currentSegment: MediaSegmentDto?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
subtitle: String? = null, subtitle: String? = null,
seekBarInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() }, seekBarInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@ -466,6 +470,7 @@ fun Controller(
seekBack = seekBack, seekBack = seekBack,
seekForward = seekForward, seekForward = seekForward,
skipBackOnResume = skipBackOnResume, skipBackOnResume = skipBackOnResume,
currentSegment = currentSegment,
) )
when (nextState) { when (nextState) {
OverlayViewState.CHAPTERS -> OverlayViewState.CHAPTERS ->

View file

@ -100,6 +100,7 @@ fun PlaybackPage(
val chapters by viewModel.chapters.observeAsState(listOf()) val chapters by viewModel.chapters.observeAsState(listOf())
val currentPlayback by viewModel.currentPlayback.observeAsState(null) val currentPlayback by viewModel.currentPlayback.observeAsState(null)
val currentSegment by viewModel.currentSegment.observeAsState(null) val currentSegment by viewModel.currentSegment.observeAsState(null)
var segmentCancelled by remember(currentSegment?.id) { mutableStateOf(false) }
var cues by remember { mutableStateOf<List<Cue>>(listOf()) } var cues by remember { mutableStateOf<List<Cue>>(listOf()) }
var showDebugInfo by remember { mutableStateOf(prefs.showDebugInfo) } var showDebugInfo by remember { mutableStateOf(prefs.showDebugInfo) }
@ -179,6 +180,13 @@ fun PlaybackPage(
skipBackOnResume = preferences.appPreferences.playbackPreferences.skipBackOnResume, skipBackOnResume = preferences.appPreferences.playbackPreferences.skipBackOnResume,
) )
val showSegment =
!segmentCancelled && currentSegment != null &&
!controllerViewState.controlsVisible && skipIndicatorDuration == 0L
BackHandler(showSegment) {
segmentCancelled = true
}
Box( Box(
modifier modifier
.background(Color.Black), .background(Color.Black),
@ -318,6 +326,7 @@ fun PlaybackPage(
onClickPlaylist = { onClickPlaylist = {
viewModel.playItemInPlaylist(it) viewModel.playItemInPlaylist(it)
}, },
currentSegment = currentSegment,
) )
} }
@ -345,7 +354,7 @@ fun PlaybackPage(
// Ask to skip intros, etc button // Ask to skip intros, etc button
AnimatedVisibility( AnimatedVisibility(
currentSegment != null && !controllerViewState.controlsVisible && skipIndicatorDuration == 0L, showSegment,
modifier = modifier =
Modifier Modifier
.padding(40.dp) .padding(40.dp)
@ -353,7 +362,11 @@ fun PlaybackPage(
) { ) {
currentSegment?.let { segment -> currentSegment?.let { segment ->
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) { focusRequester.tryRequestFocus() } LaunchedEffect(Unit) {
focusRequester.tryRequestFocus()
delay(10.seconds)
segmentCancelled = false
}
Button( Button(
onClick = { onClick = {
player.seekTo(segment.endTicks.ticks.inWholeMilliseconds) player.seekTo(segment.endTicks.ticks.inWholeMilliseconds)