restructure code and remove boilerplate by propagating viewmodel and uistate
This commit is contained in:
parent
0d6227071e
commit
819dc80387
|
@ -38,7 +38,7 @@ data class VideoPlayerUIState(
|
|||
val isLoading: Boolean,
|
||||
val durationInMs: Long,
|
||||
val playbackPositionInMs: Long,
|
||||
val fastseekSeconds: Int,
|
||||
val fastSeekSeconds: Int,
|
||||
val soundVolume: Float,
|
||||
|
||||
// when null use system value
|
||||
|
@ -58,7 +58,7 @@ data class VideoPlayerUIState(
|
|||
isLoading = true,
|
||||
durationInMs = 0,
|
||||
playbackPositionInMs = 0,
|
||||
fastseekSeconds = 0,
|
||||
fastSeekSeconds = 0,
|
||||
soundVolume = 0f,
|
||||
brightness = null
|
||||
)
|
||||
|
|
|
@ -279,7 +279,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
override fun fastSeek(count: Int) {
|
||||
mutableUiState.update {
|
||||
it.copy(
|
||||
fastseekSeconds = count * (newPlayer?.fastSeekAmountSec ?: 10)
|
||||
fastSeekSeconds = count * (newPlayer?.fastSeekAmountSec ?: 10)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -289,13 +289,13 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun finishFastSeek() {
|
||||
val fastSeekAmount = mutableUiState.value.fastseekSeconds
|
||||
val fastSeekAmount = mutableUiState.value.fastSeekSeconds
|
||||
if (fastSeekAmount != 0) {
|
||||
Log.d(TAG, "$fastSeekAmount")
|
||||
|
||||
newPlayer?.currentPosition = (newPlayer?.currentPosition ?: 0) + (fastSeekAmount * 1000)
|
||||
mutableUiState.update {
|
||||
it.copy(fastseekSeconds = 0)
|
||||
it.copy(fastSeekSeconds = 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,84 +356,4 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
|
||||
|
||||
} ?: minContentRatio
|
||||
|
||||
|
||||
companion object {
|
||||
val dummy = object : VideoPlayerViewModel {
|
||||
override var newPlayer: NewPlayer? = null
|
||||
override val internalPlayer: Player? = null
|
||||
override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT)
|
||||
override var minContentRatio = 4F / 3F
|
||||
override var maxContentRatio = 16F / 9F
|
||||
override var contentFitMode = ContentScale.FIT_INSIDE
|
||||
|
||||
override fun initUIState(instanceState: Bundle) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun addCallbackListener(listener: VideoPlayerViewModel.Listener) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun play() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun switchToEmbeddedView() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun switchToFullscreen() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun showUi() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun hideUi() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun seekPositionChanged(newValue: Float) {
|
||||
println("dymmy seekPositionChanged: newValue: ${newValue}")
|
||||
}
|
||||
|
||||
override fun seekingFinished() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun embeddedDraggedDown(offset: Float) {
|
||||
println("dymmy embeddedDraggedDown: offset: ${offset}")
|
||||
}
|
||||
|
||||
override fun fastSeek(steps: Int) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun finishFastSeek() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun brightnessChange(changeRate: Float, currentValue: Float) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun volumeChange(changeRate: Float) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun pause() {
|
||||
println("dummy pause")
|
||||
}
|
||||
|
||||
override fun prevStream() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun nextStream() {
|
||||
println("dummy impl")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package net.newpipe.newplayer.model
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.media3.common.Player
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import net.newpipe.newplayer.NewPlayer
|
||||
import net.newpipe.newplayer.ui.ContentScale
|
||||
|
||||
open class VideoPlayerViewModelDummy : VideoPlayerViewModel {
|
||||
override var newPlayer: NewPlayer? = null
|
||||
override val internalPlayer: Player? = null
|
||||
override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT)
|
||||
override var minContentRatio = 4F / 3F
|
||||
override var maxContentRatio = 16F / 9F
|
||||
override var contentFitMode = ContentScale.FIT_INSIDE
|
||||
|
||||
override fun initUIState(instanceState: Bundle) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun addCallbackListener(listener: VideoPlayerViewModel.Listener) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun play() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun switchToEmbeddedView() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun switchToFullscreen() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun showUi() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun hideUi() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun seekPositionChanged(newValue: Float) {
|
||||
println("dymmy seekPositionChanged: newValue: ${newValue}")
|
||||
}
|
||||
|
||||
override fun seekingFinished() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun embeddedDraggedDown(offset: Float) {
|
||||
println("dymmy embeddedDraggedDown: offset: ${offset}")
|
||||
}
|
||||
|
||||
override fun fastSeek(steps: Int) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun finishFastSeek() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun brightnessChange(changeRate: Float, currentValue: Float) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun volumeChange(changeRate: Float) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun pause() {
|
||||
println("dummy pause")
|
||||
}
|
||||
|
||||
override fun prevStream() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun nextStream() {
|
||||
println("dummy impl")
|
||||
}
|
||||
}
|
|
@ -48,54 +48,34 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelImpl
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
import net.newpipe.newplayer.ui.videoplayer.BottomUI
|
||||
import net.newpipe.newplayer.ui.videoplayer.CenterUI
|
||||
import net.newpipe.newplayer.ui.videoplayer.TopUI
|
||||
import net.newpipe.newplayer.ui.videoplayer.GestureUI
|
||||
import net.newpipe.newplayer.utils.getScreenBrightnes
|
||||
import net.newpipe.newplayer.utils.getDefaultBrightness
|
||||
|
||||
@Composable
|
||||
fun VideoPlayerControllerUI(
|
||||
isPlaying: Boolean,
|
||||
fullscreen: Boolean,
|
||||
uiVissible: Boolean,
|
||||
seekPosition: Float,
|
||||
isLoading: Boolean,
|
||||
durationInMs: Long,
|
||||
playbackPositionInMs: Long,
|
||||
bufferedPercentage: Float,
|
||||
fastSeekSeconds: Int,
|
||||
soundVolume: Float,
|
||||
brightnes: Float,
|
||||
play: () -> Unit,
|
||||
pause: () -> Unit,
|
||||
prevStream: () -> Unit,
|
||||
nextStream: () -> Unit,
|
||||
switchToFullscreen: () -> Unit,
|
||||
switchToEmbeddedView: () -> Unit,
|
||||
showUi: () -> Unit,
|
||||
hideUi: () -> Unit,
|
||||
seekPositionChanged: (Float) -> Unit,
|
||||
seekingFinished: () -> Unit,
|
||||
embeddedDraggedDownBy: (Float) -> Unit,
|
||||
fastSeek: (Int) -> Unit,
|
||||
finishFastSeek: () -> Unit,
|
||||
brightnessChange: (Float, Float) -> Unit,
|
||||
volumeChange: (Float) -> Unit
|
||||
viewModel: VideoPlayerViewModel,
|
||||
uiState: VideoPlayerUIState
|
||||
) {
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
if (fullscreen) {
|
||||
if (uiState.fullscreen) {
|
||||
BackHandler {
|
||||
switchToEmbeddedView()
|
||||
viewModel.switchToEmbeddedView()
|
||||
}
|
||||
}
|
||||
|
||||
val internalBrightnessChange = { rateChange: Float ->
|
||||
val systemBrightness = getScreenBrightnes(context as Activity)
|
||||
brightnessChange(rateChange, systemBrightness)
|
||||
val systemBrightness = getDefaultBrightness(context as Activity)
|
||||
viewModel.brightnessChange(rateChange, systemBrightness)
|
||||
}
|
||||
|
||||
val insets =
|
||||
|
@ -103,35 +83,23 @@ fun VideoPlayerControllerUI(
|
|||
.union(WindowInsets.displayCutout)
|
||||
.union(WindowInsets.waterfall)
|
||||
|
||||
if (!uiVissible) {
|
||||
if (!uiState.uiVissible) {
|
||||
GestureUI(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
// .windowInsetsPadding(WindowInsets.systemGestures),
|
||||
hideUi = hideUi,
|
||||
showUi = showUi,
|
||||
uiVissible = uiVissible,
|
||||
fullscreen = fullscreen,
|
||||
fastSeekSeconds = fastSeekSeconds,
|
||||
brightnes = brightnes,
|
||||
soundVolume = soundVolume,
|
||||
switchToFullscreen = switchToFullscreen,
|
||||
switchToEmbeddedView = switchToEmbeddedView,
|
||||
embeddedDraggedDownBy = embeddedDraggedDownBy,
|
||||
fastSeek = fastSeek,
|
||||
fastSeekFinished = finishFastSeek,
|
||||
brightnessChange = internalBrightnessChange,
|
||||
volumeChange = volumeChange
|
||||
viewModel = viewModel,
|
||||
uiState = uiState
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(uiVissible) {
|
||||
AnimatedVisibility(uiState.uiVissible) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(), color = Color(0x75000000)
|
||||
) {}
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
if (uiState.isLoading) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
|
@ -143,41 +111,25 @@ fun VideoPlayerControllerUI(
|
|||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(uiVissible) {
|
||||
AnimatedVisibility(uiState.uiVissible) {
|
||||
GestureUI(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.windowInsetsPadding(WindowInsets.systemGestures),
|
||||
hideUi = hideUi,
|
||||
showUi = showUi,
|
||||
uiVissible = uiVissible,
|
||||
fullscreen = fullscreen,
|
||||
fastSeekSeconds = fastSeekSeconds,
|
||||
soundVolume = soundVolume,
|
||||
brightnes = brightnes,
|
||||
switchToFullscreen = switchToFullscreen,
|
||||
switchToEmbeddedView = switchToEmbeddedView,
|
||||
embeddedDraggedDownBy = embeddedDraggedDownBy,
|
||||
fastSeek = fastSeek,
|
||||
fastSeekFinished = finishFastSeek,
|
||||
volumeChange = volumeChange,
|
||||
brightnessChange = internalBrightnessChange
|
||||
viewModel = viewModel,
|
||||
uiState = uiState
|
||||
)
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
CenterUI(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
isPlaying = isPlaying,
|
||||
isLoading = isLoading,
|
||||
play = play,
|
||||
pause = pause,
|
||||
prevStream = prevStream,
|
||||
nextStream = nextStream
|
||||
viewModel = viewModel,
|
||||
uiState = uiState
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = if (fullscreen) Modifier.windowInsetsPadding(insets) else Modifier
|
||||
modifier = if (uiState.fullscreen) Modifier.windowInsetsPadding(insets) else Modifier
|
||||
) {
|
||||
TopUI(
|
||||
modifier = Modifier
|
||||
|
@ -193,15 +145,8 @@ fun VideoPlayerControllerUI(
|
|||
.padding(start = 16.dp, end = 16.dp)
|
||||
.defaultMinSize(minHeight = 40.dp)
|
||||
.fillMaxWidth(),
|
||||
isFullscreen = fullscreen,
|
||||
durationInMs = durationInMs,
|
||||
playbackPositionInMs = playbackPositionInMs,
|
||||
seekPosition = seekPosition,
|
||||
bufferedPercentage = bufferedPercentage,
|
||||
switchToFullscreen = switchToFullscreen,
|
||||
switchToEmbeddedView = switchToEmbeddedView,
|
||||
seekPositionChanged = seekPositionChanged,
|
||||
seekingFinished = seekingFinished
|
||||
viewModel = viewModel,
|
||||
uiState = uiState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -236,32 +181,7 @@ fun PreviewBackgroundSurface(
|
|||
fun VideoPlayerControllerUIPreviewEmbedded() {
|
||||
VideoPlayerTheme {
|
||||
PreviewBackgroundSurface {
|
||||
VideoPlayerControllerUI(isPlaying = false,
|
||||
fullscreen = false,
|
||||
uiVissible = true,
|
||||
seekPosition = 0.3F,
|
||||
isLoading = false,
|
||||
durationInMs = 9 * 60 * 1000,
|
||||
playbackPositionInMs = 6 * 60 * 1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 0,
|
||||
soundVolume = 0f,
|
||||
brightnes = 0f,
|
||||
play = {},
|
||||
pause = {},
|
||||
prevStream = {},
|
||||
nextStream = {},
|
||||
switchToFullscreen = {},
|
||||
switchToEmbeddedView = {},
|
||||
showUi = {},
|
||||
hideUi = {},
|
||||
seekPositionChanged = {},
|
||||
seekingFinished = {},
|
||||
embeddedDraggedDownBy = {},
|
||||
fastSeek = {},
|
||||
finishFastSeek = {},
|
||||
brightnessChange = { a, b ->},
|
||||
volumeChange = {})
|
||||
VideoPlayerControllerUI(VideoPlayerViewModelDummy(), VideoPlayerUIState.DEFAULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -271,32 +191,7 @@ fun VideoPlayerControllerUIPreviewEmbedded() {
|
|||
fun VideoPlayerControllerUIPreviewLandscape() {
|
||||
VideoPlayerTheme {
|
||||
PreviewBackgroundSurface {
|
||||
VideoPlayerControllerUI(isPlaying = true,
|
||||
fullscreen = true,
|
||||
uiVissible = true,
|
||||
seekPosition = 0.3F,
|
||||
isLoading = true,
|
||||
durationInMs = 9 * 60 * 1000,
|
||||
playbackPositionInMs = 6 * 60 * 1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 0,
|
||||
brightnes = 0f,
|
||||
soundVolume = 0f,
|
||||
play = {},
|
||||
pause = {},
|
||||
prevStream = {},
|
||||
nextStream = {},
|
||||
switchToEmbeddedView = {},
|
||||
switchToFullscreen = {},
|
||||
showUi = {},
|
||||
hideUi = {},
|
||||
seekPositionChanged = {},
|
||||
seekingFinished = {},
|
||||
embeddedDraggedDownBy = {},
|
||||
fastSeek = {},
|
||||
finishFastSeek = {},
|
||||
brightnessChange = { a, b -> },
|
||||
volumeChange = {})
|
||||
VideoPlayerControllerUI(VideoPlayerViewModelDummy(), VideoPlayerUIState.DEFAULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -306,33 +201,7 @@ fun VideoPlayerControllerUIPreviewLandscape() {
|
|||
fun VideoPlayerControllerUIPreviewPortrait() {
|
||||
VideoPlayerTheme {
|
||||
PreviewBackgroundSurface {
|
||||
VideoPlayerControllerUI(
|
||||
isPlaying = false,
|
||||
fullscreen = true,
|
||||
uiVissible = true,
|
||||
seekPosition = 0.3F,
|
||||
isLoading = false,
|
||||
durationInMs = 9 * 60 * 1000,
|
||||
playbackPositionInMs = 6 * 60 * 1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 0,
|
||||
brightnes = 0f,
|
||||
soundVolume = 0f,
|
||||
play = {},
|
||||
pause = {},
|
||||
prevStream = {},
|
||||
nextStream = {},
|
||||
switchToEmbeddedView = {},
|
||||
switchToFullscreen = {},
|
||||
showUi = {},
|
||||
hideUi = {},
|
||||
seekPositionChanged = {},
|
||||
seekingFinished = {},
|
||||
embeddedDraggedDownBy = {},
|
||||
fastSeek = {},
|
||||
finishFastSeek = {},
|
||||
brightnessChange = { a, b -> },
|
||||
volumeChange = {})
|
||||
VideoPlayerControllerUI(VideoPlayerViewModelDummy(), VideoPlayerUIState.DEFAULT)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,11 +53,11 @@ import androidx.lifecycle.Lifecycle
|
|||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.media3.common.Player
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelImpl
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
import net.newpipe.newplayer.utils.LockScreenOrientation
|
||||
import net.newpipe.newplayer.utils.getScreenBrightnes
|
||||
import net.newpipe.newplayer.utils.setScreenBrightnes
|
||||
import net.newpipe.newplayer.utils.getDefaultBrightness
|
||||
import net.newpipe.newplayer.utils.setScreenBrightness
|
||||
|
||||
private const val TAG = "VideoPlayerUI"
|
||||
|
||||
|
@ -89,8 +89,7 @@ fun VideoPlayerUI(
|
|||
// Setup fullscreen
|
||||
if (uiState.fullscreen) {
|
||||
LaunchedEffect(key1 = true) {
|
||||
WindowCompat.getInsetsController(window, view)
|
||||
.isAppearanceLightStatusBars = false
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,13 +129,12 @@ fun VideoPlayerUI(
|
|||
val screenRatio =
|
||||
displayMetrics.widthPixels.toFloat() / displayMetrics.heightPixels.toFloat()
|
||||
|
||||
val systemScreenBrightnes = getScreenBrightnes(activity)
|
||||
val defaultBrightness = getDefaultBrightness(activity)
|
||||
|
||||
LaunchedEffect(key1 = uiState.brightness) {
|
||||
Log.d(TAG, "New Brightnes: ${uiState.brightness}")
|
||||
setScreenBrightnes(
|
||||
uiState.brightness
|
||||
?: if (systemScreenBrightnes < 0f) 0.5f else systemScreenBrightnes, activity
|
||||
setScreenBrightness(
|
||||
uiState.brightness ?: defaultBrightness, activity
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -160,33 +158,7 @@ fun VideoPlayerUI(
|
|||
}
|
||||
|
||||
VideoPlayerControllerUI(
|
||||
isPlaying = uiState.playing,
|
||||
fullscreen = uiState.fullscreen,
|
||||
uiVissible = uiState.uiVissible,
|
||||
seekPosition = uiState.seekerPosition,
|
||||
isLoading = uiState.isLoading,
|
||||
durationInMs = uiState.durationInMs,
|
||||
playbackPositionInMs = uiState.playbackPositionInMs,
|
||||
bufferedPercentage = uiState.bufferedPercentage,
|
||||
fastSeekSeconds = uiState.fastseekSeconds,
|
||||
brightnes = uiState.brightness
|
||||
?: if (systemScreenBrightnes < 0f) 0.5f else systemScreenBrightnes,
|
||||
soundVolume = uiState.soundVolume,
|
||||
play = viewModel::play,
|
||||
pause = viewModel::pause,
|
||||
prevStream = viewModel::prevStream,
|
||||
nextStream = viewModel::nextStream,
|
||||
switchToFullscreen = viewModel::switchToFullscreen,
|
||||
switchToEmbeddedView = viewModel::switchToEmbeddedView,
|
||||
showUi = viewModel::showUi,
|
||||
hideUi = viewModel::hideUi,
|
||||
seekPositionChanged = viewModel::seekPositionChanged,
|
||||
seekingFinished = viewModel::seekingFinished,
|
||||
embeddedDraggedDownBy = viewModel::embeddedDraggedDown,
|
||||
fastSeek = viewModel::fastSeek,
|
||||
finishFastSeek = viewModel::finishFastSeek,
|
||||
volumeChange = viewModel::volumeChange,
|
||||
brightnessChange = viewModel::brightnessChange
|
||||
viewModel, uiState = uiState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -253,6 +225,6 @@ fun PlaySurface(
|
|||
@Composable
|
||||
fun PlayerUIPreviewEmbeded() {
|
||||
VideoPlayerTheme {
|
||||
VideoPlayerUI(viewModel = VideoPlayerViewModelImpl.dummy)
|
||||
VideoPlayerUI(viewModel = VideoPlayerViewModelDummy())
|
||||
}
|
||||
}
|
|
@ -23,6 +23,8 @@ package net.newpipe.newplayer.ui.theme
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.ui.PreviewBackgroundSurface
|
||||
import net.newpipe.newplayer.ui.VideoPlayerControllerUI
|
||||
|
||||
|
@ -72,32 +74,20 @@ val video_player_scrim = Color(0xFF000000)
|
|||
fun VideoPlayerControllerUIPreviewEmbeddedColorPreview() {
|
||||
VideoPlayerTheme {
|
||||
PreviewBackgroundSurface {
|
||||
VideoPlayerControllerUI(isPlaying = false,
|
||||
fullscreen = false,
|
||||
uiVissible = true,
|
||||
seekPosition = 0.3F,
|
||||
isLoading = false,
|
||||
durationInMs = 9*60*1000,
|
||||
playbackPositionInMs = 6*60*1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 10,
|
||||
brightnes = 0f,
|
||||
soundVolume = 0f,
|
||||
play = {},
|
||||
pause = {},
|
||||
prevStream = {},
|
||||
nextStream = {},
|
||||
switchToFullscreen = {},
|
||||
switchToEmbeddedView = {},
|
||||
showUi = {},
|
||||
hideUi = {},
|
||||
seekPositionChanged = {},
|
||||
seekingFinished = {},
|
||||
embeddedDraggedDownBy = {},
|
||||
fastSeek = {},
|
||||
finishFastSeek = {},
|
||||
brightnessChange = {a, b ->},
|
||||
volumeChange = {})
|
||||
VideoPlayerControllerUI(
|
||||
viewModel = VideoPlayerViewModelDummy(),
|
||||
uiState = VideoPlayerUIState.DEFAULT.copy(
|
||||
playing = true,
|
||||
fullscreen = false,
|
||||
uiVissible = true,
|
||||
seekerPosition = 0.3f,
|
||||
isLoading = false,
|
||||
durationInMs = 9 * 60 * 1000,
|
||||
playbackPositionInMs = 6 * 60 * 1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
fastSeekSeconds = 10,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import net.newpipe.newplayer.R
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.ui.seeker.DefaultSeekerColor
|
||||
import net.newpipe.newplayer.ui.seeker.Seeker
|
||||
import net.newpipe.newplayer.ui.seeker.SeekerColors
|
||||
|
@ -52,39 +55,33 @@ import kotlin.math.min
|
|||
|
||||
@Composable
|
||||
fun BottomUI(
|
||||
modifier: Modifier,
|
||||
isFullscreen: Boolean,
|
||||
seekPosition: Float,
|
||||
durationInMs: Long,
|
||||
playbackPositionInMs: Long,
|
||||
bufferedPercentage: Float,
|
||||
switchToFullscreen: () -> Unit,
|
||||
switchToEmbeddedView: () -> Unit,
|
||||
seekPositionChanged: (Float) -> Unit,
|
||||
seekingFinished: () -> Unit
|
||||
modifier: Modifier, viewModel: VideoPlayerViewModel, uiState: VideoPlayerUIState
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(getTimeStringFromMs(playbackPositionInMs, getLocale() ?: Locale.US))
|
||||
Text(getTimeStringFromMs(uiState.playbackPositionInMs, getLocale() ?: Locale.US))
|
||||
Seeker(
|
||||
Modifier.weight(1F),
|
||||
value = seekPosition,
|
||||
onValueChange = seekPositionChanged,
|
||||
onValueChangeFinished = seekingFinished,
|
||||
readAheadValue = bufferedPercentage,
|
||||
value = uiState.seekerPosition,
|
||||
onValueChange = viewModel::seekPositionChanged,
|
||||
onValueChangeFinished = viewModel::seekingFinished,
|
||||
readAheadValue = uiState.bufferedPercentage,
|
||||
colors = customizedSeekerColors()
|
||||
)
|
||||
|
||||
//Slider(value = 0.4F, onValueChange = {}, modifier = Modifier.weight(1F))
|
||||
|
||||
Text(getTimeStringFromMs(durationInMs, getLocale() ?: Locale.US))
|
||||
Text(getTimeStringFromMs(uiState.durationInMs, getLocale() ?: Locale.US))
|
||||
|
||||
IconButton(onClick = if (isFullscreen) switchToEmbeddedView else switchToFullscreen) {
|
||||
IconButton(
|
||||
onClick = if (uiState.fullscreen) viewModel::switchToEmbeddedView
|
||||
else viewModel::switchToFullscreen
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isFullscreen) Icons.Filled.FullscreenExit
|
||||
imageVector = if (uiState.fullscreen) Icons.Filled.FullscreenExit
|
||||
else Icons.Filled.Fullscreen,
|
||||
contentDescription = stringResource(R.string.widget_description_toggle_fullscreen)
|
||||
)
|
||||
|
@ -93,7 +90,7 @@ fun BottomUI(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun customizedSeekerColors() : SeekerColors {
|
||||
private fun customizedSeekerColors(): SeekerColors {
|
||||
val colors = DefaultSeekerColor(
|
||||
progressColor = MaterialTheme.colorScheme.primary,
|
||||
thumbColor = MaterialTheme.colorScheme.primary,
|
||||
|
@ -124,7 +121,7 @@ private const val MILLIS_PER_DAY =
|
|||
private const val MILLIS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND
|
||||
private const val MILLIS_PER_MINUTE = SECONDS_PER_MINUTE * MILLIS_PER_SECOND
|
||||
|
||||
private fun getTimeStringFromMs(timeSpanInMs: Long, locale: Locale) : String {
|
||||
private fun getTimeStringFromMs(timeSpanInMs: Long, locale: Locale): String {
|
||||
val days = timeSpanInMs / MILLIS_PER_DAY
|
||||
val millisThisDay = timeSpanInMs - days * MILLIS_PER_DAY
|
||||
val hours = millisThisDay / MILLIS_PER_HOUR
|
||||
|
@ -153,15 +150,14 @@ fun VideoPlayerControllerBottomUIPreview() {
|
|||
Surface(color = Color.Black) {
|
||||
BottomUI(
|
||||
modifier = Modifier,
|
||||
isFullscreen = true,
|
||||
seekPosition = 0.4F,
|
||||
durationInMs = 90 * 60 * 1000,
|
||||
playbackPositionInMs = 3 * 60 * 1000,
|
||||
bufferedPercentage = 0.4f,
|
||||
switchToFullscreen = { },
|
||||
switchToEmbeddedView = { },
|
||||
seekPositionChanged = {},
|
||||
seekingFinished = {}
|
||||
viewModel = VideoPlayerViewModelDummy(),
|
||||
uiState = VideoPlayerUIState.DEFAULT.copy(
|
||||
fullscreen = true,
|
||||
seekerPosition = 0.4f,
|
||||
durationInMs = 90 * 60 * 1000,
|
||||
playbackPositionInMs = 3 * 60 * 1000,
|
||||
bufferedPercentage = 0.4f
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,41 +42,41 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.newpipe.newplayer.R
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelImpl
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
|
||||
@Composable
|
||||
fun CenterUI(
|
||||
modifier: Modifier,
|
||||
isPlaying: Boolean,
|
||||
isLoading: Boolean,
|
||||
play: () -> Unit,
|
||||
pause: () -> Unit,
|
||||
nextStream: () -> Unit,
|
||||
prevStream: () -> Unit
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: VideoPlayerViewModel,
|
||||
uiState: VideoPlayerUIState
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = modifier,
|
||||
) {
|
||||
if (!isLoading) {
|
||||
if (!uiState.isLoading) {
|
||||
CenterControllButton(
|
||||
buttonModifier = Modifier.size(80.dp),
|
||||
iconModifier = Modifier.size(40.dp),
|
||||
icon = Icons.Filled.SkipPrevious,
|
||||
contentDescriptoion = stringResource(R.string.widget_description_previous_stream),
|
||||
onClick = prevStream
|
||||
onClick = viewModel::prevStream
|
||||
)
|
||||
|
||||
CenterControllButton(
|
||||
buttonModifier = Modifier.size(80.dp),
|
||||
iconModifier = Modifier.size(60.dp),
|
||||
icon = if (isPlaying) Icons.Filled.Pause else Icons.Filled.PlayArrow,
|
||||
icon = if (uiState.playing) Icons.Filled.Pause else Icons.Filled.PlayArrow,
|
||||
contentDescriptoion = stringResource(
|
||||
if (isPlaying) R.string.widget_description_pause
|
||||
if (uiState.playing) R.string.widget_description_pause
|
||||
else R.string.widget_description_play
|
||||
),
|
||||
onClick = if (isPlaying) pause else play
|
||||
onClick = if (uiState.playing) viewModel::pause else viewModel::play
|
||||
)
|
||||
|
||||
CenterControllButton(
|
||||
|
@ -84,7 +84,7 @@ fun CenterUI(
|
|||
iconModifier = Modifier.size(40.dp),
|
||||
icon = Icons.Filled.SkipNext,
|
||||
contentDescriptoion = stringResource(R.string.widget_description_next_stream),
|
||||
onClick = nextStream
|
||||
onClick = viewModel::nextStream
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -122,13 +122,12 @@ fun VideoPlayerControllerUICenterUIPreview() {
|
|||
VideoPlayerTheme {
|
||||
Surface(color = Color.Black) {
|
||||
CenterUI(
|
||||
modifier = Modifier,
|
||||
isPlaying = true,
|
||||
isLoading = false,
|
||||
play = { },
|
||||
pause = { },
|
||||
nextStream = { }) {
|
||||
}
|
||||
viewModel = VideoPlayerViewModelDummy(),
|
||||
uiState = VideoPlayerUIState.DEFAULT.copy(
|
||||
isLoading = false,
|
||||
playing = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ package net.newpipe.newplayer.ui.videoplayer
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.ui.videoplayer.gesture_ui.EmbeddedGestureUI
|
||||
import net.newpipe.newplayer.ui.videoplayer.gesture_ui.FullscreenGestureUI
|
||||
|
||||
|
@ -39,54 +41,15 @@ val INDICATOR_BACKGROUND_COLOR = Color.Black.copy(alpha = 0.3f)
|
|||
|
||||
@Composable
|
||||
fun GestureUI(
|
||||
modifier: Modifier,
|
||||
hideUi: () -> Unit,
|
||||
showUi: () -> Unit,
|
||||
uiVissible: Boolean,
|
||||
fullscreen: Boolean,
|
||||
fastSeekSeconds: Int,
|
||||
brightnes: Float,
|
||||
soundVolume: Float,
|
||||
switchToFullscreen: () -> Unit,
|
||||
switchToEmbeddedView: () -> Unit,
|
||||
embeddedDraggedDownBy: (Float) -> Unit,
|
||||
fastSeek: (Int) -> Unit,
|
||||
fastSeekFinished: () -> Unit,
|
||||
volumeChange: (Float) -> Unit,
|
||||
brightnessChange: (Float) -> Unit,
|
||||
modifier: Modifier, viewModel: VideoPlayerViewModel, uiState: VideoPlayerUIState
|
||||
) {
|
||||
val defaultOnRegularTap = {
|
||||
if (uiVissible) {
|
||||
hideUi()
|
||||
} else {
|
||||
showUi()
|
||||
}
|
||||
}
|
||||
|
||||
if (fullscreen) {
|
||||
if (uiState.fullscreen) {
|
||||
FullscreenGestureUI(
|
||||
modifier = modifier,
|
||||
uiVisible = uiVissible,
|
||||
fastSeekSeconds = fastSeekSeconds,
|
||||
hideUi = hideUi,
|
||||
showUi = showUi,
|
||||
fastSeek = fastSeek,
|
||||
brightnes = brightnes,
|
||||
volume = soundVolume,
|
||||
switchToEmbeddedView = switchToEmbeddedView,
|
||||
fastSeekFinished = fastSeekFinished,
|
||||
volumeChange = volumeChange,
|
||||
brightnesChange = brightnessChange)
|
||||
modifier = modifier, viewModel = viewModel, uiState = uiState
|
||||
)
|
||||
} else {
|
||||
EmbeddedGestureUI(
|
||||
modifier = modifier,
|
||||
fastSeekSeconds = fastSeekSeconds,
|
||||
uiVissible = uiVissible,
|
||||
switchToFullscreen = switchToFullscreen,
|
||||
embeddedDraggedDownBy = embeddedDraggedDownBy,
|
||||
fastSeek = fastSeek,
|
||||
fastSeekFinished = fastSeekFinished,
|
||||
hideUi = hideUi,
|
||||
showUi = showUi)
|
||||
modifier = modifier, viewModel = viewModel, uiState = uiState
|
||||
)
|
||||
}
|
||||
}
|
|
@ -32,6 +32,9 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
import net.newpipe.newplayer.ui.videoplayer.FAST_SEEK_MODE_DURATION
|
||||
|
||||
|
@ -39,49 +42,34 @@ private const val TAG = "EmbeddedGestureUI"
|
|||
|
||||
@Composable
|
||||
fun EmbeddedGestureUI(
|
||||
modifier: Modifier = Modifier,
|
||||
fastSeekSeconds: Int,
|
||||
uiVissible: Boolean,
|
||||
switchToFullscreen: () -> Unit,
|
||||
embeddedDraggedDownBy: (Float) -> Unit,
|
||||
fastSeek: (Int) -> Unit,
|
||||
fastSeekFinished: () -> Unit,
|
||||
hideUi: () -> Unit,
|
||||
showUi: () -> Unit
|
||||
modifier: Modifier = Modifier, viewModel: VideoPlayerViewModel, uiState: VideoPlayerUIState
|
||||
) {
|
||||
|
||||
val handleDownwardMovement = { movement: TouchedPosition ->
|
||||
Log.d(TAG, "${movement.x}:${movement.y}")
|
||||
if (0 < movement.y) {
|
||||
embeddedDraggedDownBy(movement.y)
|
||||
viewModel.embeddedDraggedDown(movement.y)
|
||||
} else {
|
||||
switchToFullscreen()
|
||||
viewModel.switchToFullscreen()
|
||||
}
|
||||
}
|
||||
|
||||
val defaultOnRegularTap = {
|
||||
if (uiVissible) {
|
||||
hideUi()
|
||||
if (uiState.uiVissible) {
|
||||
viewModel.hideUi()
|
||||
} else {
|
||||
showUi()
|
||||
viewModel.showUi()
|
||||
}
|
||||
}
|
||||
|
||||
Row(modifier = modifier) {
|
||||
GestureSurface(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
multiTapTimeoutInMs = FAST_SEEK_MODE_DURATION,
|
||||
onRegularTap = defaultOnRegularTap,
|
||||
onMultiTap = {
|
||||
fastSeek(-it)
|
||||
},
|
||||
onMultiTapFinished = fastSeekFinished,
|
||||
onMovement = handleDownwardMovement
|
||||
modifier = Modifier.weight(1f), onRegularTap = defaultOnRegularTap, onMultiTap = {
|
||||
viewModel.fastSeek(-it)
|
||||
}, onMultiTapFinished = viewModel::finishFastSeek, onMovement = handleDownwardMovement
|
||||
) {
|
||||
FadedAnimationForSeekFeedback(
|
||||
fastSeekSeconds,
|
||||
backwards = true
|
||||
uiState.fastSeekSeconds, backwards = true
|
||||
) { fastSeekSecondsToDisplay ->
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
FastSeekVisualFeedback(
|
||||
|
@ -93,15 +81,13 @@ fun EmbeddedGestureUI(
|
|||
}
|
||||
}
|
||||
GestureSurface(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
multiTapTimeoutInMs = FAST_SEEK_MODE_DURATION,
|
||||
modifier = Modifier.weight(1f),
|
||||
onRegularTap = defaultOnRegularTap,
|
||||
onMovement = handleDownwardMovement,
|
||||
onMultiTap = fastSeek,
|
||||
onMultiTapFinished = fastSeekFinished
|
||||
onMultiTap = viewModel::fastSeek,
|
||||
onMultiTapFinished = viewModel::finishFastSeek
|
||||
) {
|
||||
FadedAnimationForSeekFeedback(fastSeekSeconds) { fastSeekSecondsToDisplay ->
|
||||
FadedAnimationForSeekFeedback(uiState.fastSeekSeconds) { fastSeekSecondsToDisplay ->
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
FastSeekVisualFeedback(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
|
@ -122,14 +108,21 @@ fun EmbeddedGestureUIPreview() {
|
|||
Surface(modifier = Modifier.wrapContentSize(), color = Color.DarkGray) {
|
||||
EmbeddedGestureUI(
|
||||
modifier = Modifier,
|
||||
hideUi = { },
|
||||
showUi = { },
|
||||
uiVissible = false,
|
||||
fastSeekSeconds = 0,
|
||||
switchToFullscreen = { println("switch to fullscreen") },
|
||||
embeddedDraggedDownBy = { println("embedded dragged down") },
|
||||
fastSeek = { println("Fast seek by $it steps") },
|
||||
fastSeekFinished = {})
|
||||
viewModel = object : VideoPlayerViewModelDummy() {
|
||||
override fun switchToEmbeddedView() {
|
||||
println("switch to fullscreen")
|
||||
}
|
||||
|
||||
override fun embeddedDraggedDown(offset: Float) {
|
||||
println("embedded view dragged down by $offset")
|
||||
}
|
||||
|
||||
override fun fastSeek(steps: Int) {
|
||||
println("fast seek by $steps steps")
|
||||
}
|
||||
},
|
||||
uiState = VideoPlayerUIState.DEFAULT,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,12 @@
|
|||
|
||||
package net.newpipe.newplayer.ui.videoplayer.gesture_ui
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
|
@ -44,9 +42,13 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
import net.newpipe.newplayer.ui.videoplayer.FAST_SEEK_MODE_DURATION
|
||||
import net.newpipe.newplayer.utils.getDefaultBrightness
|
||||
|
||||
private enum class IndicatorMode {
|
||||
NONE,
|
||||
|
@ -57,17 +59,8 @@ private enum class IndicatorMode {
|
|||
@Composable
|
||||
fun FullscreenGestureUI(
|
||||
modifier: Modifier = Modifier,
|
||||
uiVisible: Boolean,
|
||||
fastSeekSeconds: Int,
|
||||
volume: Float,
|
||||
brightnes: Float,
|
||||
hideUi: () -> Unit,
|
||||
showUi: () -> Unit,
|
||||
fastSeek: (Int) -> Unit,
|
||||
fastSeekFinished: () -> Unit,
|
||||
switchToEmbeddedView: () -> Unit,
|
||||
volumeChange: (Float) -> Unit,
|
||||
brightnesChange: (Float) -> Unit
|
||||
viewModel: VideoPlayerViewModel,
|
||||
uiState: VideoPlayerUIState
|
||||
) {
|
||||
|
||||
var heightPx by remember {
|
||||
|
@ -80,13 +73,17 @@ fun FullscreenGestureUI(
|
|||
|
||||
val defaultOnRegularTap = {
|
||||
|
||||
if (uiVisible) {
|
||||
hideUi()
|
||||
if (uiState.uiVisible) {
|
||||
viewModel.hideUi()
|
||||
} else {
|
||||
showUi()
|
||||
viewModel.showUi()
|
||||
}
|
||||
}
|
||||
|
||||
val activity = LocalContext.current as Activity
|
||||
|
||||
val defaultBrightness = getDefaultBrightness(activity)
|
||||
|
||||
Box(modifier = modifier.onGloballyPositioned { coordinates ->
|
||||
heightPx = coordinates.size.height.toFloat()
|
||||
}) {
|
||||
|
@ -97,9 +94,9 @@ fun FullscreenGestureUI(
|
|||
onRegularTap = defaultOnRegularTap,
|
||||
onMultiTap = {
|
||||
println("multitap ${-it}")
|
||||
fastSeek(-it)
|
||||
viewModel.fastSeek(-it)
|
||||
},
|
||||
onMultiTapFinished = fastSeekFinished,
|
||||
onMultiTapFinished = viewModel::finishFastSeek,
|
||||
onUp = {
|
||||
indicatorMode = IndicatorMode.NONE
|
||||
},
|
||||
|
@ -110,13 +107,13 @@ fun FullscreenGestureUI(
|
|||
indicatorMode = IndicatorMode.BRIGHTNESS_INDICATOR_VISSIBLE
|
||||
|
||||
if (heightPx != 0f) {
|
||||
brightnesChange(-change.y / heightPx)
|
||||
viewModel.brightnessChange(-change.y / heightPx, defaultBrightness)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
FadedAnimationForSeekFeedback(
|
||||
fastSeekSeconds,
|
||||
uiState.fastSeekSeconds,
|
||||
backwards = true
|
||||
) { fastSeekSecondsToDisplay ->
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
|
@ -134,7 +131,7 @@ fun FullscreenGestureUI(
|
|||
onRegularTap = defaultOnRegularTap,
|
||||
onMovement = { movement ->
|
||||
if (0 < movement.y) {
|
||||
switchToEmbeddedView()
|
||||
viewModel.switchToEmbeddedView()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -142,8 +139,8 @@ fun FullscreenGestureUI(
|
|||
modifier = Modifier
|
||||
.weight(1f),
|
||||
onRegularTap = defaultOnRegularTap,
|
||||
onMultiTap = fastSeek,
|
||||
onMultiTapFinished = fastSeekFinished,
|
||||
onMultiTap = viewModel::fastSeek,
|
||||
onMultiTapFinished = viewModel::finishFastSeek,
|
||||
onUp = {
|
||||
indicatorMode = IndicatorMode.NONE
|
||||
},
|
||||
|
@ -153,12 +150,12 @@ fun FullscreenGestureUI(
|
|||
) {
|
||||
indicatorMode = IndicatorMode.VOLUME_INDICATOR_VISSIBLE
|
||||
if (heightPx != 0f) {
|
||||
volumeChange(-change.y / heightPx)
|
||||
viewModel.volumeChange(-change.y / heightPx)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
FadedAnimationForSeekFeedback(fastSeekSeconds) { fastSeekSecondsToDisplay ->
|
||||
FadedAnimationForSeekFeedback(uiState.fastSeekSeconds) { fastSeekSecondsToDisplay ->
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
FastSeekVisualFeedback(
|
||||
modifier = Modifier.align(Alignment.CenterStart),
|
||||
|
@ -174,7 +171,7 @@ fun FullscreenGestureUI(
|
|||
modifier = Modifier.align(Alignment.Center),
|
||||
visible = indicatorMode == IndicatorMode.VOLUME_INDICATOR_VISSIBLE,
|
||||
) {
|
||||
VolumeCircle(volumeFraction = volume)
|
||||
VolumeCircle(volumeFraction = uiState.soundVolume)
|
||||
}
|
||||
|
||||
IndicatorAnimation(
|
||||
|
@ -182,7 +179,7 @@ fun FullscreenGestureUI(
|
|||
visible = indicatorMode == IndicatorMode.BRIGHTNESS_INDICATOR_VISSIBLE,
|
||||
) {
|
||||
VolumeCircle(
|
||||
volumeFraction = brightnes,
|
||||
volumeFraction = uiState.brightness ?: defaultBrightness,
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
isBrightness = true
|
||||
)
|
||||
|
@ -233,17 +230,13 @@ fun FullscreenGestureUIPreview() {
|
|||
Surface(modifier = Modifier.wrapContentSize(), color = Color.DarkGray) {
|
||||
FullscreenGestureUI(
|
||||
modifier = Modifier,
|
||||
hideUi = { },
|
||||
showUi = { },
|
||||
uiVisible = false,
|
||||
fastSeekSeconds = 0,
|
||||
volume = 0f,
|
||||
brightnes = 0f,
|
||||
fastSeek = { println("fast seek by $it steps") },
|
||||
fastSeekFinished = {},
|
||||
switchToEmbeddedView = {},
|
||||
brightnesChange = {},
|
||||
volumeChange = {})
|
||||
object : VideoPlayerViewModelDummy() {
|
||||
override fun fastSeek(steps: Int) {
|
||||
println("fast seek by $steps steps")
|
||||
}
|
||||
},
|
||||
VideoPlayerUIState.DEFAULT
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +249,7 @@ fun FullscreenGestureUIPreviewInteractive() {
|
|||
mutableStateOf(0)
|
||||
}
|
||||
|
||||
var brightnesValue by remember {
|
||||
var brightnessValue by remember {
|
||||
mutableStateOf(0f)
|
||||
}
|
||||
|
||||
|
@ -272,23 +265,38 @@ fun FullscreenGestureUIPreviewInteractive() {
|
|||
Surface(modifier = Modifier.wrapContentSize(), color = Color.Gray) {
|
||||
FullscreenGestureUI(
|
||||
modifier = Modifier,
|
||||
hideUi = { uiVisible = false },
|
||||
showUi = { uiVisible = true },
|
||||
uiVisible = uiVisible,
|
||||
fastSeekSeconds = seekSeconds,
|
||||
volume = soundVolume,
|
||||
brightnes = brightnesValue,
|
||||
fastSeek = { seekSeconds = it * 10 },
|
||||
fastSeekFinished = {
|
||||
seekSeconds = 0
|
||||
object : VideoPlayerViewModelDummy() {
|
||||
override fun hideUi() {
|
||||
uiVisible = false
|
||||
}
|
||||
|
||||
override fun showUi() {
|
||||
uiVisible = true
|
||||
}
|
||||
|
||||
override fun fastSeek(steps: Int) {
|
||||
seekSeconds = steps * 10
|
||||
}
|
||||
|
||||
override fun finishFastSeek() {
|
||||
seekSeconds = 0
|
||||
}
|
||||
|
||||
override fun brightnessChange(changeRate: Float, currentValue: Float) {
|
||||
brightnessValue = (brightnessValue + changeRate).coerceIn(0f, 1f)
|
||||
}
|
||||
|
||||
override fun volumeChange(changeRate: Float) {
|
||||
soundVolume = (soundVolume + changeRate).coerceIn(0f, 1f)
|
||||
}
|
||||
},
|
||||
switchToEmbeddedView = {},
|
||||
brightnesChange = {
|
||||
brightnesValue = (brightnesValue + it).coerceIn(0f, 1f)
|
||||
},
|
||||
volumeChange = {
|
||||
soundVolume = (soundVolume + it).coerceIn(0f, 1f)
|
||||
})
|
||||
uiState = VideoPlayerUIState.DEFAULT.copy(
|
||||
uiVissible = uiVisible,
|
||||
fastSeekSeconds = seekSeconds,
|
||||
soundVolume = soundVolume,
|
||||
brightness = brightnessValue
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(uiVisible) {
|
||||
|
|
|
@ -24,7 +24,6 @@ import android.annotation.SuppressLint
|
|||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
|
@ -45,14 +44,14 @@ fun LockScreenOrientation(orientation: Int) {
|
|||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
fun getScreenBrightnes(activity: Activity) : Float {
|
||||
fun getDefaultBrightness(activity: Activity) : Float {
|
||||
val window = activity.window
|
||||
val layout = window.attributes as WindowManager.LayoutParams
|
||||
return layout.screenBrightness
|
||||
return if(layout.screenBrightness < 0) 0.5f else layout.screenBrightness
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
fun setScreenBrightnes(value:Float, activity: Activity) {
|
||||
fun setScreenBrightness(value:Float, activity: Activity) {
|
||||
val window = activity.window
|
||||
val layout = window.attributes as WindowManager.LayoutParams
|
||||
layout.screenBrightness = value
|
||||
|
|
Loading…
Reference in New Issue