fix more fast forward foo

This commit is contained in:
Christian Schabesberger 2024-08-07 17:33:49 +02:00
parent 628ba4db1b
commit 2b197b62b7
10 changed files with 167 additions and 144 deletions

View File

@ -52,8 +52,7 @@ interface NewPlayer {
fun prepare()
fun play()
fun pause()
fun fastSeekForward(ntimes: Int = 1)
fun fastSeekBackward(ntimes: Int = 1)
fun fastSeek(steps: Int)
fun seekTo(millisecond: Long)
fun addToPlaylist(newItem: String)
fun addListener(callbackListener: Listener)
@ -115,14 +114,9 @@ class NewPlayerImpl(override val internal_player: Player, override val repositor
internal_player.pause()
}
override fun fastSeekForward(ntimes: Int) {
override fun fastSeek(steps: Int) {
val currentPosition = internal_player.currentPosition
internal_player.seekTo(currentPosition + fastSeekAmountSec * 1000 * ntimes)
}
override fun fastSeekBackward(ntimes: Int) {
val currentPosition = internal_player.currentPosition
internal_player.seekTo(currentPosition - fastSeekAmountSec * 1000 * ntimes)
internal_player.seekTo(currentPosition + fastSeekAmountSec * 1000 * steps)
}
override fun seekTo(millisecond: Long) {

View File

@ -54,7 +54,7 @@ data class VideoPlayerUIState(
isLoading = true,
durationInMs = 0,
playbackPositionInMs = 0,
fastseekSeconds = 10
fastseekSeconds = 0
)
}
}

View File

@ -48,8 +48,8 @@ interface VideoPlayerViewModel {
fun seekPositionChanged(newValue: Float)
fun seekingFinished()
fun embeddedDraggedDown(offset: Float)
fun fastSeekForward()
fun fastSeekBackward()
fun fastSeek(count: Int)
fun fastSeekFinished()
interface Listener {
fun onFullscreenToggle(isFullscreen: Boolean) {}

View File

@ -268,19 +268,23 @@ class VideoPlayerViewModelImpl @Inject constructor(
callbackListeners.forEach { it?.embeddedPlayerDraggedDown(offset) }
}
override fun fastSeekForward() {
mutableUiState.update { it.copy(fastseekSeconds = newPlayer?.fastSeekAmountSec ?: 10) }
newPlayer?.fastSeekForward()
override fun fastSeek(count: Int) {
mutableUiState.update {
it.copy(
fastseekSeconds = count * (newPlayer?.fastSeekAmountSec ?: 10)
)
}
if (mutableUiState.value.uiVisible) {
resetHideUiDelayedJob()
}
}
override fun fastSeekBackward() {
mutableUiState.update { it.copy(fastseekSeconds = newPlayer?.fastSeekAmountSec ?: 10) }
newPlayer?.fastSeekBackward()
if (mutableUiState.value.uiVisible) {
resetHideUiDelayedJob()
override fun fastSeekFinished() {
val fastSeekAmount = mutableUiState.value.fastseekSeconds
newPlayer?.fastSeek(fastSeekAmount)
mutableUiState.update {
it.copy(fastseekSeconds = 0)
}
}
@ -362,11 +366,11 @@ class VideoPlayerViewModelImpl @Inject constructor(
println("dymmy embeddedDraggedDown: offset: ${offset}")
}
override fun fastSeekForward() {
override fun fastSeek(steps: Int) {
println("dummy impl")
}
override fun fastSeekBackward() {
override fun fastSeekFinished() {
println("dummy impl")
}

View File

@ -74,8 +74,8 @@ fun VideoPlayerControllerUI(
seekPositionChanged: (Float) -> Unit,
seekingFinished: () -> Unit,
embeddedDraggedDownBy: (Float) -> Unit,
fastSeekBackward: () -> Unit,
fastSeekForward: () -> Unit,
fastSeek: (Int) -> Unit,
finishFastSeek: () -> Unit
) {
if (fullscreen) {
@ -98,12 +98,12 @@ fun VideoPlayerControllerUI(
showUi = showUi,
uiVissible = uiVissible,
fullscreen = fullscreen,
fastSeekSeconds = fastSeekSeconds,
switchToFullscreen = switchToFullscreen,
switchToEmbeddedView = switchToEmbeddedView,
embeddedDraggedDownBy = embeddedDraggedDownBy,
fastSeekForward = fastSeekForward,
fastSeekBackward = fastSeekBackward,
fastSeekSeconds = fastSeekSeconds
fastSeek = fastSeek,
fastSeekFinished = finishFastSeek
)
}
@ -134,12 +134,12 @@ fun VideoPlayerControllerUI(
showUi = showUi,
uiVissible = uiVissible,
fullscreen = fullscreen,
fastSeekSeconds = fastSeekSeconds,
switchToFullscreen = switchToFullscreen,
switchToEmbeddedView = switchToEmbeddedView,
embeddedDraggedDownBy = embeddedDraggedDownBy,
fastSeekForward = fastSeekForward,
fastSeekBackward = fastSeekBackward,
fastSeekSeconds = fastSeekSeconds
fastSeek = fastSeek,
fastSeekFinished = finishFastSeek
)
Box(modifier = Modifier.fillMaxSize()) {
@ -219,10 +219,10 @@ fun VideoPlayerControllerUIPreviewEmbedded() {
uiVissible = true,
seekPosition = 0.3F,
isLoading = false,
durationInMs = 9*60*1000,
playbackPositionInMs = 6*60*1000,
durationInMs = 9 * 60 * 1000,
playbackPositionInMs = 6 * 60 * 1000,
bufferedPercentage = 0.4f,
fastSeekSeconds = 10,
fastSeekSeconds = 0,
play = {},
pause = {},
prevStream = {},
@ -234,8 +234,8 @@ fun VideoPlayerControllerUIPreviewEmbedded() {
seekPositionChanged = {},
seekingFinished = {},
embeddedDraggedDownBy = {},
fastSeekBackward = {},
fastSeekForward = {})
fastSeek = {},
finishFastSeek = {})
}
}
}
@ -250,10 +250,10 @@ fun VideoPlayerControllerUIPreviewLandscape() {
uiVissible = true,
seekPosition = 0.3F,
isLoading = true,
durationInMs = 9*60*1000,
playbackPositionInMs = 6*60*1000,
durationInMs = 9 * 60 * 1000,
playbackPositionInMs = 6 * 60 * 1000,
bufferedPercentage = 0.4f,
fastSeekSeconds = 10,
fastSeekSeconds = 0,
play = {},
pause = {},
prevStream = {},
@ -265,8 +265,8 @@ fun VideoPlayerControllerUIPreviewLandscape() {
seekPositionChanged = {},
seekingFinished = {},
embeddedDraggedDownBy = {},
fastSeekBackward = {},
fastSeekForward = {})
fastSeek = {},
finishFastSeek = {})
}
}
}
@ -282,10 +282,10 @@ fun VideoPlayerControllerUIPreviewPortrait() {
uiVissible = true,
seekPosition = 0.3F,
isLoading = false,
durationInMs = 9*60*1000,
playbackPositionInMs = 6*60*1000,
durationInMs = 9 * 60 * 1000,
playbackPositionInMs = 6 * 60 * 1000,
bufferedPercentage = 0.4f,
fastSeekSeconds = 10,
fastSeekSeconds = 0,
play = {},
pause = {},
prevStream = {},
@ -297,8 +297,8 @@ fun VideoPlayerControllerUIPreviewPortrait() {
seekPositionChanged = {},
seekingFinished = {},
embeddedDraggedDownBy = {},
fastSeekForward = {},
fastSeekBackward = {})
fastSeek = {},
finishFastSeek = {})
}
}
}

View File

@ -164,8 +164,8 @@ fun VideoPlayerUI(
seekPositionChanged = viewModel::seekPositionChanged,
seekingFinished = viewModel::seekingFinished,
embeddedDraggedDownBy = viewModel::embeddedDraggedDown,
fastSeekForward = viewModel::fastSeekForward,
fastSeekBackward = viewModel::fastSeekBackward
fastSeek = viewModel::fastSeek,
finishFastSeek = viewModel::fastSeekFinished
)
}
}

View File

@ -95,8 +95,8 @@ fun VideoPlayerControllerUIPreviewEmbeddedColorPreview() {
seekPositionChanged = {},
seekingFinished = {},
embeddedDraggedDownBy = {},
fastSeekForward = {},
fastSeekBackward = {})
fastSeek = {},
finishFastSeek = {})
}
}
}

View File

@ -34,7 +34,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -48,7 +47,6 @@ import net.newpipe.newplayer.ui.videoplayer.gesture_ui.TouchedPosition
private const val TAG = "TouchUi"
const val DELAY_UNTIL_SHOWING_UI_AFTER_TOUCH_IN_MS: Long = 200
const val SEEK_ANIMATION_DURATION_IN_MS = 400
const val FAST_SEEKMODE_DURATION = 500L
@ -66,8 +64,8 @@ fun GestureUI(
switchToFullscreen: () -> Unit,
switchToEmbeddedView: () -> Unit,
embeddedDraggedDownBy: (Float) -> Unit,
fastSeekBackward: () -> Unit,
fastSeekForward: () -> Unit,
fastSeek: (Int) -> Unit,
fastSeekFinished: () -> Unit
) {
val defaultOnRegularTap = {
if (uiVissible) {
@ -77,50 +75,6 @@ fun GestureUI(
}
}
var fastSeekBackwardBy:Int by remember {
mutableStateOf(0)
}
var fastSeekForwardBy:Int by remember {
mutableStateOf(0)
}
val composeScope = rememberCoroutineScope()
/*
val doForwardSeek = {
fastSeekModeForward = true
composeScope.launch {
delay(FAST_SEEKMODE_DURATION)
fastSeekModeForward = false
}
fastSeekForward()
}
var fastSeekModeTimeout: Job? = null
val resetFastSeekModeEnd = {
fastSeekModeTimeout?.cancel()
fastSeekModeTimeout = composeScope.launch {
delay(FAST_SEEKMODE_DURATION)
fastSeekModeBackward = false
}
}
val doBackwardSeek = {
fastSeekModeBackward = true
resetFastSeekModeEnd()
fastSeekBackward()
}
*/
val onMultitapBackward = { amount: Int ->
fastSeekBackwardBy = amount * fastSeekSeconds
}
val onMultitapForward = { amount: Int ->
fastSeekForwardBy = amount * fastSeekSeconds
}
if (fullscreen) {
Row(modifier = modifier) {
TouchSurface(
@ -128,12 +82,16 @@ fun GestureUI(
.weight(1f),
multitapDurationInMs = FAST_SEEKMODE_DURATION,
onRegularTap = defaultOnRegularTap,
onMultiTap = onMultitapBackward
onMultiTap = {
println("multitap ${-it}")
fastSeek(-it)
},
onMultiTapFinished = fastSeekFinished
) {
FadedAnimationForSeekFeedback(visible = fastSeekForwardBy != 0) {
FadedAnimationForSeekFeedback(fastSeekSeconds, backwards = true) {
Box(modifier = Modifier.fillMaxSize()) {
FastSeekVisualFeedback(
seconds = fastSeekSeconds,
seconds = -fastSeekSeconds,
backwards = true,
modifier = Modifier.align(Alignment.CenterEnd)
)
@ -156,9 +114,10 @@ fun GestureUI(
.weight(1f),
onRegularTap = defaultOnRegularTap,
multitapDurationInMs = FAST_SEEKMODE_DURATION,
onMultiTap = onMultitapForward
onMultiTap = fastSeek,
onMultiTapFinished = fastSeekFinished
) {
FadedAnimationForSeekFeedback(visible = fastSeekBackwardBy != 0) {
FadedAnimationForSeekFeedback(fastSeekSeconds) {
Box(modifier = Modifier.fillMaxSize()) {
FastSeekVisualFeedback(
modifier = Modifier.align(Alignment.CenterStart),
@ -185,14 +144,17 @@ fun GestureUI(
.weight(1f),
multitapDurationInMs = FAST_SEEKMODE_DURATION,
onRegularTap = defaultOnRegularTap,
onMultiTap = onMultitapBackward,
onMultiTap = {
fastSeek(-it)
},
onMultiTapFinished = fastSeekFinished,
onMovement = handleDownwardMovement
) {
FadedAnimationForSeekFeedback(visible = fastSeekBackwardBy != 0) {
FadedAnimationForSeekFeedback(fastSeekSeconds, backwards = true) {
Box(modifier = Modifier.fillMaxSize()) {
FastSeekVisualFeedback(
modifier = Modifier.align(Alignment.Center),
seconds = fastSeekSeconds,
seconds = -fastSeekSeconds,
backwards = true
)
}
@ -204,9 +166,10 @@ fun GestureUI(
multitapDurationInMs = FAST_SEEKMODE_DURATION,
onRegularTap = defaultOnRegularTap,
onMovement = handleDownwardMovement,
onMultiTap = onMultitapForward
onMultiTap = fastSeek,
onMultiTapFinished = fastSeekFinished
) {
FadedAnimationForSeekFeedback(visible = fastSeekForwardBy != 0) {
FadedAnimationForSeekFeedback(fastSeekSeconds) {
Box(modifier = Modifier.fillMaxSize()) {
FastSeekVisualFeedback(
modifier = Modifier.align(Alignment.Center),
@ -223,56 +186,105 @@ fun GestureUI(
@Composable
fun FadedAnimationForSeekFeedback(visible: Boolean, content: @Composable () -> Unit) {
AnimatedVisibility(
visible = visible,
enter = fadeIn(animationSpec = tween(SEEK_ANIMATION_FADE_IN)),
exit = fadeOut(animationSpec = tween(SEEK_ANIMATION_FADE_OUT))
) {
content()
fun FadedAnimationForSeekFeedback(
fastSeekSeconds: Int,
backwards: Boolean = false,
content: @Composable () -> Unit
) {
val vissible = if (backwards) {
fastSeekSeconds < 0
} else {
0 < fastSeekSeconds
}
val disapearEmediatly = if (backwards) {
0 < fastSeekSeconds
} else {
fastSeekSeconds < 0
}
if (!disapearEmediatly) {
AnimatedVisibility(
visible = vissible,
enter = fadeIn(animationSpec = tween(SEEK_ANIMATION_FADE_IN)),
exit = fadeOut(
animationSpec = tween(SEEK_ANIMATION_FADE_OUT)
)
) {
content()
}
}
}
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
@Composable
fun FullscreenGestureUIPreview() {
VideoPlayerTheme {
Surface(modifier = Modifier.wrapContentSize(), color = Color.Black) {
Surface(modifier = Modifier.wrapContentSize(), color = Color.DarkGray) {
GestureUI(
modifier = Modifier,
hideUi = { },
showUi = { },
uiVissible = false,
fullscreen = true,
fastSeekSeconds = 10,
fastSeekSeconds = 0,
switchToFullscreen = { println("switch to fullscreen") },
switchToEmbeddedView = { println("switch to embedded") },
embeddedDraggedDownBy = { println("embedded dragged down") },
fastSeekBackward = { println("fast seek backward") },
fastSeekForward = { println("fast seek forward") })
fastSeek = { println("fast seek by $it steps") },
fastSeekFinished = {})
}
}
}
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
@Composable
fun FullscreenGestureUIPreviewInteractive() {
var seekSeconds by remember {
mutableStateOf(0)
}
VideoPlayerTheme {
Surface(modifier = Modifier.wrapContentSize(), color = Color.DarkGray) {
GestureUI(
modifier = Modifier,
hideUi = { },
showUi = { },
uiVissible = false,
fullscreen = true,
fastSeekSeconds = seekSeconds,
switchToFullscreen = { println("switch to fullscreen") },
switchToEmbeddedView = { println("switch to embedded") },
embeddedDraggedDownBy = { println("embedded dragged down") },
fastSeek = { seekSeconds = it * 10 },
fastSeekFinished = {
seekSeconds = 0
})
}
}
}
@Preview(device = "spec:width=600px,height=400px,dpi=440,orientation=landscape")
@Composable
fun EmbeddedGestureUIPreview() {
VideoPlayerTheme {
Surface(modifier = Modifier.wrapContentSize(), color = Color.Black) {
Surface(modifier = Modifier.wrapContentSize(), color = Color.DarkGray) {
GestureUI(
modifier = Modifier,
hideUi = { },
showUi = { },
uiVissible = false,
fullscreen = false,
fastSeekSeconds = 10,
fastSeekSeconds = 0,
switchToFullscreen = { println("switch to fullscreen") },
switchToEmbeddedView = { println("switch to embedded") },
embeddedDraggedDownBy = { println("embedded dragged down") },
fastSeekBackward = { println("fast seek backward") },
fastSeekForward = { println("fast seek forward") })
fastSeek = { println("Fast seek by $it steps") },
fastSeekFinished = {})
}
}
}

View File

@ -26,9 +26,12 @@ import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
@ -36,10 +39,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.android.material.color.MaterialColors
import net.newpipe.newplayer.R
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
import net.newpipe.newplayer.ui.videoplayer.SEEK_ANIMATION_DURATION_IN_MS
@ -106,27 +112,33 @@ fun FastSeekVisualFeedback(modifier: Modifier = Modifier, seconds: Int, backward
//val secondsString = stringResource(id = R.string.seconds)
val secondsString = "Seconds"
Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
Row {
SeekerIcon(
backwards = backwards,
description = contentDescription,
color = if (backwards) animatedColor3 else animatedColor1
)
SeekerIcon(
backwards = backwards,
description = contentDescription,
color = animatedColor2
)
SeekerIcon(
backwards = backwards,
description = contentDescription,
color = if (backwards) animatedColor1 else animatedColor3
)
Surface(
color = Color.Black.copy(alpha = 0.5f),
modifier = modifier.clip(RoundedCornerShape(50.dp))
) {
Box(modifier = Modifier.padding(10.dp, 5.dp)) {
Column(modifier = Modifier, horizontalAlignment = Alignment.CenterHorizontally) {
Row {
SeekerIcon(
backwards = backwards,
description = contentDescription,
color = if (backwards) animatedColor3 else animatedColor1
)
SeekerIcon(
backwards = backwards,
description = contentDescription,
color = animatedColor2
)
SeekerIcon(
backwards = backwards,
description = contentDescription,
color = if (backwards) animatedColor1 else animatedColor3
)
}
Text(text = "$seconds $secondsString")
}
}
Text(text = "$seconds $secondsString")
}
}
@ -148,7 +160,7 @@ private fun SeekerIcon(backwards: Boolean, description: String, color: Color) {
@Composable
fun FastSeekVisualFeedbackPreviewBackwards() {
VideoPlayerTheme {
Surface(modifier = Modifier.wrapContentSize(), color = Color.Black) {
Surface(modifier = Modifier.wrapContentSize(), color = Color.Gray) {
FastSeekVisualFeedback(seconds = 10, backwards = true)
}
}
@ -158,7 +170,7 @@ fun FastSeekVisualFeedbackPreviewBackwards() {
@Composable
fun FastSeekVisualFeedbackPreview() {
VideoPlayerTheme {
Surface(modifier = Modifier.wrapContentSize(), color = Color.Black) {
Surface(modifier = Modifier.wrapContentSize(), color = Color.Gray) {
FastSeekVisualFeedback(seconds = 10, backwards = false)
}
}

View File

@ -92,6 +92,7 @@ fun TouchSurface(
onMultiTap(multitapAmount)
cancelMultitapJob = composableScope.launch {
delay(multitapDurationInMs)
multitapAmount = 0
onMultiTapFinished()
}
} else {