make fastseek work
This commit is contained in:
parent
ae3ef47a3f
commit
990a4aaa12
|
@ -45,7 +45,7 @@ interface NewPlayer {
|
|||
val bufferedPercentage: Int
|
||||
val repository: MediaRepository
|
||||
var currentPosition: Long
|
||||
var fastSeekAmountSec: Long
|
||||
var fastSeekAmountSec: Int
|
||||
var playBackMode: PlayMode
|
||||
var playList: MutableList<String>
|
||||
|
||||
|
@ -54,6 +54,7 @@ interface NewPlayer {
|
|||
fun pause()
|
||||
fun fastSeekForward()
|
||||
fun fastSeekBackward()
|
||||
fun seekTo(millisecond: Long)
|
||||
fun addToPlaylist(newItem: String)
|
||||
fun addListener(callbackListener: Listener)
|
||||
|
||||
|
@ -88,7 +89,7 @@ class NewPlayerImpl(override val internal_player: Player, override val repositor
|
|||
override val duartion: Long = internal_player.duration
|
||||
override val bufferedPercentage: Int = internal_player.bufferedPercentage
|
||||
override var currentPosition: Long = internal_player.currentPosition
|
||||
override var fastSeekAmountSec: Long = 100
|
||||
override var fastSeekAmountSec: Int = 10
|
||||
override var playBackMode: PlayMode = PlayMode.EMBEDDED_VIDEO
|
||||
override var playList: MutableList<String> = ArrayList<String>()
|
||||
|
||||
|
@ -115,11 +116,17 @@ class NewPlayerImpl(override val internal_player: Player, override val repositor
|
|||
}
|
||||
|
||||
override fun fastSeekForward() {
|
||||
Log.d(TAG, "not implemented fast seek forward")
|
||||
val currentPosition = internal_player.currentPosition
|
||||
internal_player.seekTo(currentPosition + fastSeekAmountSec * 1000)
|
||||
}
|
||||
|
||||
override fun fastSeekBackward() {
|
||||
Log.d(TAG, "not implemented fast seek backward")
|
||||
val currentPosition = internal_player.currentPosition
|
||||
internal_player.seekTo(currentPosition - fastSeekAmountSec * 1000)
|
||||
}
|
||||
|
||||
override fun seekTo(millisecond: Long) {
|
||||
internal_player.seekTo(millisecond)
|
||||
}
|
||||
|
||||
override fun addToPlaylist(newItem: String) {
|
||||
|
|
|
@ -37,7 +37,8 @@ data class VideoPlayerUIState(
|
|||
val bufferedPercentage: Float,
|
||||
val isLoading: Boolean,
|
||||
val durationInMs: Long,
|
||||
val playbackPositionInMs: Long
|
||||
val playbackPositionInMs: Long,
|
||||
val fastseekSeconds: Int,
|
||||
) : Parcelable {
|
||||
companion object {
|
||||
val DEFAULT = VideoPlayerUIState(
|
||||
|
@ -52,7 +53,8 @@ data class VideoPlayerUIState(
|
|||
bufferedPercentage = 0f,
|
||||
isLoading = true,
|
||||
durationInMs = 0,
|
||||
playbackPositionInMs = 0
|
||||
playbackPositionInMs = 0,
|
||||
fastseekSeconds = 10
|
||||
)
|
||||
}
|
||||
}
|
|
@ -65,6 +65,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
set(value) {
|
||||
field = value
|
||||
installExoPlayer()
|
||||
mutableUiState.update { it.copy(fastseekSeconds = field?.fastSeekAmountSec ?: 10) }
|
||||
}
|
||||
|
||||
override val uiState = mutableUiState.asStateFlow()
|
||||
|
@ -259,7 +260,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
resetHideUiDelayedJob()
|
||||
val seekerPosition = mutableUiState.value.seekerPosition
|
||||
val seekPositionInMs = (player?.duration?.toFloat() ?: 0F) * seekerPosition
|
||||
player?.seekTo(seekPositionInMs.toLong())
|
||||
newPlayer?.seekTo(seekPositionInMs.toLong())
|
||||
Log.i(TAG, "Seek to Ms: $seekPositionInMs")
|
||||
}
|
||||
|
||||
|
@ -268,6 +269,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun fastSeekForward() {
|
||||
mutableUiState.update { it.copy(fastseekSeconds = newPlayer?.fastSeekAmountSec ?: 10) }
|
||||
newPlayer?.fastSeekForward()
|
||||
if (mutableUiState.value.uiVisible) {
|
||||
resetHideUiDelayedJob()
|
||||
|
@ -275,6 +277,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun fastSeekBackward() {
|
||||
mutableUiState.update { it.copy(fastseekSeconds = newPlayer?.fastSeekAmountSec ?: 10) }
|
||||
newPlayer?.fastSeekBackward()
|
||||
if (mutableUiState.value.uiVisible) {
|
||||
resetHideUiDelayedJob()
|
||||
|
|
|
@ -62,6 +62,7 @@ fun VideoPlayerControllerUI(
|
|||
durationInMs: Long,
|
||||
playbackPositionInMs: Long,
|
||||
bufferedPercentage: Float,
|
||||
fastSeekSeconds: Int,
|
||||
play: () -> Unit,
|
||||
pause: () -> Unit,
|
||||
prevStream: () -> Unit,
|
||||
|
@ -101,7 +102,8 @@ fun VideoPlayerControllerUI(
|
|||
switchToEmbeddedView = switchToEmbeddedView,
|
||||
embeddedDraggedDownBy = embeddedDraggedDownBy,
|
||||
fastSeekForward = fastSeekForward,
|
||||
fastSeekBackward = fastSeekBackward
|
||||
fastSeekBackward = fastSeekBackward,
|
||||
fastSeekSeconds = fastSeekSeconds
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -136,7 +138,8 @@ fun VideoPlayerControllerUI(
|
|||
switchToEmbeddedView = switchToEmbeddedView,
|
||||
embeddedDraggedDownBy = embeddedDraggedDownBy,
|
||||
fastSeekForward = fastSeekForward,
|
||||
fastSeekBackward = fastSeekBackward
|
||||
fastSeekBackward = fastSeekBackward,
|
||||
fastSeekSeconds = fastSeekSeconds
|
||||
)
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
|
@ -219,6 +222,7 @@ fun VideoPlayerControllerUIPreviewEmbedded() {
|
|||
durationInMs = 9*60*1000,
|
||||
playbackPositionInMs = 6*60*1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 10,
|
||||
play = {},
|
||||
pause = {},
|
||||
prevStream = {},
|
||||
|
@ -249,6 +253,7 @@ fun VideoPlayerControllerUIPreviewLandscape() {
|
|||
durationInMs = 9*60*1000,
|
||||
playbackPositionInMs = 6*60*1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 10,
|
||||
play = {},
|
||||
pause = {},
|
||||
prevStream = {},
|
||||
|
@ -280,6 +285,7 @@ fun VideoPlayerControllerUIPreviewPortrait() {
|
|||
durationInMs = 9*60*1000,
|
||||
playbackPositionInMs = 6*60*1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 10,
|
||||
play = {},
|
||||
pause = {},
|
||||
prevStream = {},
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
@ -30,6 +31,7 @@ fun VideoPlayerLoadingPlaceholder(aspectRatio: Float = 3F / 1F) {
|
|||
.height(64.dp)
|
||||
.align((Alignment.Center)))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@ fun VideoPlayerUI(
|
|||
durationInMs = uiState.durationInMs,
|
||||
playbackPositionInMs = uiState.playbackPositionInMs,
|
||||
bufferedPercentage = uiState.bufferedPercentage,
|
||||
fastSeekSeconds = uiState.fastseekSeconds,
|
||||
play = viewModel::play,
|
||||
pause = viewModel::pause,
|
||||
prevStream = viewModel::prevStream,
|
||||
|
|
|
@ -83,6 +83,7 @@ fun VideoPlayerControllerUIPreviewEmbeddedColorPreview() {
|
|||
durationInMs = 9*60*1000,
|
||||
playbackPositionInMs = 6*60*1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 10,
|
||||
play = {},
|
||||
pause = {},
|
||||
prevStream = {},
|
||||
|
|
|
@ -22,23 +22,43 @@ package net.newpipe.newplayer.ui.videoplayer
|
|||
|
||||
import android.util.Log
|
||||
import android.view.MotionEvent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColor
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
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.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
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.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInteropFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import net.newpipe.newplayer.R
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
|
||||
private const val TAG = "TouchUi"
|
||||
|
||||
|
@ -47,7 +67,10 @@ private data class TouchedPosition(val x: Float, val y: Float) {
|
|||
}
|
||||
|
||||
const val DELAY_UNTIL_SHOWING_UI_AFTER_TOUCH_IN_MS: Long = 200
|
||||
|
||||
const val SEEK_ANIMATION_DURATION_IN_MS = 400
|
||||
const val SEEK_ANIMATION_VISSIBLE_IN_MS = 500L
|
||||
const val SEEK_ANIMATION_FADE_IN = 200
|
||||
const val SEEK_ANIMATION_FADE_OUT = 500
|
||||
|
||||
@Composable
|
||||
fun GestureUI(
|
||||
|
@ -56,6 +79,7 @@ fun GestureUI(
|
|||
showUi: () -> Unit,
|
||||
uiVissible: Boolean,
|
||||
fullscreen: Boolean,
|
||||
fastSeekSeconds: Int,
|
||||
switchToFullscreen: () -> Unit,
|
||||
switchToEmbeddedView: () -> Unit,
|
||||
embeddedDraggedDownBy: (Float) -> Unit,
|
||||
|
@ -70,14 +94,53 @@ fun GestureUI(
|
|||
}
|
||||
}
|
||||
|
||||
var showFastSeekBack by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
var showFastSeekForward by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
val composeScope = rememberCoroutineScope()
|
||||
|
||||
val doForwardSeek = {
|
||||
showFastSeekForward = true
|
||||
composeScope.launch {
|
||||
delay(SEEK_ANIMATION_VISSIBLE_IN_MS)
|
||||
showFastSeekForward = false
|
||||
}
|
||||
fastSeekForward()
|
||||
}
|
||||
|
||||
val doBackwardSeek = {
|
||||
showFastSeekBack = true
|
||||
composeScope.launch {
|
||||
delay(SEEK_ANIMATION_VISSIBLE_IN_MS)
|
||||
showFastSeekBack = false
|
||||
}
|
||||
fastSeekBackward()
|
||||
}
|
||||
|
||||
|
||||
if (fullscreen) {
|
||||
Row(modifier = modifier) {
|
||||
TouchSurface(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
onRegularTap = defaultOnRegularTap,
|
||||
onDoubleTab = fastSeekBackward
|
||||
onDoubleTab = doBackwardSeek
|
||||
) {
|
||||
FadedAnimationForSeekFeedback(visible = showFastSeekBack) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
FastSeekVisualFeedback(
|
||||
seconds = fastSeekSeconds,
|
||||
backwards = true,
|
||||
modifier = Modifier.align(Alignment.CenterEnd)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
TouchSurface(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
|
@ -92,9 +155,19 @@ fun GestureUI(
|
|||
modifier = Modifier
|
||||
.weight(1f),
|
||||
onRegularTap = defaultOnRegularTap,
|
||||
onDoubleTab = fastSeekForward
|
||||
onDoubleTab = doForwardSeek
|
||||
) {
|
||||
FadedAnimationForSeekFeedback(visible = showFastSeekForward) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
FastSeekVisualFeedback(
|
||||
modifier = Modifier.align(Alignment.CenterStart),
|
||||
seconds = fastSeekSeconds,
|
||||
backwards = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // (!fullscreen)
|
||||
val handleDownwardMovement = { movement: TouchedPosition ->
|
||||
Log.d(TAG, "${movement.x}:${movement.y}")
|
||||
|
@ -109,20 +182,51 @@ fun GestureUI(
|
|||
TouchSurface(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
onDoubleTab = fastSeekBackward,
|
||||
onDoubleTab = doBackwardSeek,
|
||||
onRegularTap = defaultOnRegularTap,
|
||||
onMovement = handleDownwardMovement
|
||||
) {
|
||||
FadedAnimationForSeekFeedback(visible = showFastSeekBack) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
FastSeekVisualFeedback(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
seconds = fastSeekSeconds,
|
||||
backwards = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
TouchSurface(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
onDoubleTab = fastSeekForward,
|
||||
onDoubleTab = doForwardSeek,
|
||||
onRegularTap = defaultOnRegularTap,
|
||||
onMovement = handleDownwardMovement
|
||||
) {
|
||||
FadedAnimationForSeekFeedback(visible = showFastSeekForward) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
FastSeekVisualFeedback(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
seconds = fastSeekSeconds,
|
||||
backwards = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
|
@ -131,7 +235,8 @@ private fun TouchSurface(
|
|||
color: Color = Color.Transparent,
|
||||
onDoubleTab: () -> Unit = {},
|
||||
onRegularTap: () -> Unit = {},
|
||||
onMovement: (TouchedPosition) -> Unit = {}
|
||||
onMovement: (TouchedPosition) -> Unit = {},
|
||||
content: @Composable () -> Unit = {}
|
||||
) {
|
||||
var moveOccured by remember {
|
||||
mutableStateOf(false)
|
||||
|
@ -194,6 +299,169 @@ private fun TouchSurface(
|
|||
else -> false
|
||||
}
|
||||
}) {
|
||||
content()
|
||||
Surface(color = color, modifier = Modifier.fillMaxSize()) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FastSeekVisualFeedback(modifier: Modifier = Modifier, seconds: Int, backwards: Boolean) {
|
||||
|
||||
val contentDescription = String.format(
|
||||
if (backwards) {
|
||||
"Fast seeking backward by %d seconds."
|
||||
//stringResource(id = R.string.fast_seeking_backward)
|
||||
} else {
|
||||
"Fast seeking forward by %d seconds."
|
||||
//stringResource(id = R.string.fast_seeking_forward)
|
||||
}, seconds
|
||||
)
|
||||
|
||||
val infiniteTransition = rememberInfiniteTransition()
|
||||
|
||||
val animatedColor1 by infiniteTransition.animateColor(
|
||||
initialValue = Color.White,
|
||||
targetValue = Color.Transparent,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = keyframes {
|
||||
durationMillis = SEEK_ANIMATION_DURATION_IN_MS
|
||||
Color.White.copy(alpha = 1f) at 0 with LinearEasing
|
||||
Color.White.copy(alpha = 0f) at SEEK_ANIMATION_DURATION_IN_MS with LinearEasing
|
||||
},
|
||||
repeatMode = RepeatMode.Restart
|
||||
), label = "Arrow1 animation"
|
||||
)
|
||||
|
||||
val animatedColor2 by infiniteTransition.animateColor(
|
||||
initialValue = Color.White,
|
||||
targetValue = Color.Transparent,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = keyframes {
|
||||
durationMillis = SEEK_ANIMATION_DURATION_IN_MS
|
||||
Color.White.copy(alpha = 1f / 3f) at 0 with LinearEasing
|
||||
Color.White.copy(alpha = 0f) at SEEK_ANIMATION_DURATION_IN_MS / 3 with LinearEasing
|
||||
Color.White.copy(alpha = 1f) at SEEK_ANIMATION_DURATION_IN_MS / 3 + 1 with LinearEasing
|
||||
Color.White.copy(alpha = 2f / 3f) at SEEK_ANIMATION_DURATION_IN_MS with LinearEasing
|
||||
},
|
||||
repeatMode = RepeatMode.Restart
|
||||
), label = "Arrow2 animation"
|
||||
)
|
||||
|
||||
val animatedColor3 by infiniteTransition.animateColor(
|
||||
initialValue = Color.White,
|
||||
targetValue = Color.Transparent,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = keyframes {
|
||||
durationMillis = SEEK_ANIMATION_DURATION_IN_MS
|
||||
Color.White.copy(alpha = 2f / 3f) at 0 with LinearEasing
|
||||
Color.White.copy(alpha = 0f) at 2 * SEEK_ANIMATION_DURATION_IN_MS / 3 with LinearEasing
|
||||
Color.White.copy(alpha = 1f) at 2 * SEEK_ANIMATION_DURATION_IN_MS / 3 + 1 with LinearEasing
|
||||
Color.White.copy(alpha = 2f / 3f) at SEEK_ANIMATION_DURATION_IN_MS with LinearEasing
|
||||
},
|
||||
repeatMode = RepeatMode.Restart
|
||||
), label = "Arrow3 animation"
|
||||
)
|
||||
|
||||
|
||||
//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
|
||||
)
|
||||
}
|
||||
Text(text = "$seconds $secondsString")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun SeekerIcon(backwards: Boolean, description: String, color: Color) {
|
||||
Icon(
|
||||
modifier = if (backwards) {
|
||||
Modifier.scale(-1f, 1f)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
tint = color,
|
||||
painter = painterResource(id = R.drawable.ic_play_seek_triangle),
|
||||
contentDescription = description
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
|
||||
@Composable
|
||||
fun FullscreenGestureUIPreview() {
|
||||
VideoPlayerTheme {
|
||||
Surface(modifier = Modifier.wrapContentSize(), color = Color.Black) {
|
||||
GestureUI(
|
||||
modifier = Modifier,
|
||||
hideUi = { },
|
||||
showUi = { },
|
||||
uiVissible = false,
|
||||
fullscreen = true,
|
||||
fastSeekSeconds = 10,
|
||||
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") })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(device = "spec:width=600px,height=400px,dpi=440,orientation=landscape")
|
||||
@Composable
|
||||
fun EmbeddedGestureUIPreview() {
|
||||
VideoPlayerTheme {
|
||||
Surface(modifier = Modifier.wrapContentSize(), color = Color.Black) {
|
||||
GestureUI(
|
||||
modifier = Modifier,
|
||||
hideUi = { },
|
||||
showUi = { },
|
||||
uiVissible = false,
|
||||
fullscreen = false,
|
||||
fastSeekSeconds = 10,
|
||||
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") })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
|
||||
@Composable
|
||||
fun FastSeekVisualFeedbackPreviewBackwards() {
|
||||
VideoPlayerTheme {
|
||||
Surface(modifier = Modifier.wrapContentSize(), color = Color.Black) {
|
||||
FastSeekVisualFeedback(seconds = 10, backwards = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
|
||||
@Composable
|
||||
fun FastSeekVisualFeedbackPreview() {
|
||||
VideoPlayerTheme {
|
||||
Surface(modifier = Modifier.wrapContentSize(), color = Color.Black) {
|
||||
FastSeekVisualFeedback(seconds = 10, backwards = false)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,4 +35,7 @@
|
|||
<string name="widget_description_toggle_fullscreen">Toggle fullscreen</string>
|
||||
<string name="widget_description_chapter_selection">Chapter selection</string>
|
||||
<string name="widget_descriptoin_playlist_item_selection">Playlist item selection</string>
|
||||
<string name="fast_seeking_backward">Fast seeking backward by %d seconds.</string>
|
||||
<string name="fast_seeking_forward">Fast seeking forward by %d seconds.</string>
|
||||
<string name="seconds">Seconds</string>
|
||||
</resources>
|
Loading…
Reference in New Issue