diff --git a/new-player/src/main/java/net/newpipe/newplayer/NewPlayer.kt b/new-player/src/main/java/net/newpipe/newplayer/NewPlayer.kt index 949eb29..19ecce6 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/NewPlayer.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/NewPlayer.kt @@ -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) { diff --git a/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerUIState.kt b/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerUIState.kt index ff0020f..f08fcbd 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerUIState.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerUIState.kt @@ -54,7 +54,7 @@ data class VideoPlayerUIState( isLoading = true, durationInMs = 0, playbackPositionInMs = 0, - fastseekSeconds = 10 + fastseekSeconds = 0 ) } } \ No newline at end of file diff --git a/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt b/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt index 5b3316e..cae48a7 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt @@ -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) {} diff --git a/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModelImpl.kt b/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModelImpl.kt index 42878de..8993200 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModelImpl.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModelImpl.kt @@ -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") } diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerControllerUI.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerControllerUI.kt index 71ac7d2..48980ea 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerControllerUI.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerControllerUI.kt @@ -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 = {}) } } } \ No newline at end of file diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt index c0e0a4a..d205349 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt @@ -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 ) } } diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/theme/Color.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/theme/Color.kt index 35b7a76..d1c85c5 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/theme/Color.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/theme/Color.kt @@ -95,8 +95,8 @@ fun VideoPlayerControllerUIPreviewEmbeddedColorPreview() { seekPositionChanged = {}, seekingFinished = {}, embeddedDraggedDownBy = {}, - fastSeekForward = {}, - fastSeekBackward = {}) + fastSeek = {}, + finishFastSeek = {}) } } } diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/GestureUI.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/GestureUI.kt index 9dcd404..aec3ce7 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/GestureUI.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/GestureUI.kt @@ -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 = {}) } } } diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/gesture_ui/FastSeekVisualFeedback.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/gesture_ui/FastSeekVisualFeedback.kt index 7b75797..0679349 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/gesture_ui/FastSeekVisualFeedback.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/gesture_ui/FastSeekVisualFeedback.kt @@ -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) } } diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/gesture_ui/TouchSurface.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/gesture_ui/TouchSurface.kt index 0fc0a49..cef4607 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/gesture_ui/TouchSurface.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/gesture_ui/TouchSurface.kt @@ -92,6 +92,7 @@ fun TouchSurface( onMultiTap(multitapAmount) cancelMultitapJob = composableScope.launch { delay(multitapDurationInMs) + multitapAmount = 0 onMultiTapFinished() } } else {