simplify ui change
This commit is contained in:
parent
25593c8ed6
commit
87cc8a2c77
|
@ -32,8 +32,10 @@ enum class PlayMode {
|
||||||
EMBEDDED_VIDEO,
|
EMBEDDED_VIDEO,
|
||||||
FULLSCREEN_VIDEO,
|
FULLSCREEN_VIDEO,
|
||||||
PIP,
|
PIP,
|
||||||
BACKGROUND,
|
BACKGROUND_VIDEO,
|
||||||
AUDIO_FOREGROUND,
|
BACKGROUND_AUDIO,
|
||||||
|
FULLSCREEN_AUDIO,
|
||||||
|
EMBEDDED_AUDIO
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class RepeatMode {
|
enum class RepeatMode {
|
||||||
|
|
|
@ -44,8 +44,7 @@ interface NewPlayerViewModel {
|
||||||
fun pause()
|
fun pause()
|
||||||
fun prevStream()
|
fun prevStream()
|
||||||
fun nextStream()
|
fun nextStream()
|
||||||
fun switchToFullscreen(embeddedUiConfig: EmbeddedUiConfig)
|
fun changeUiMode(newUiModeState: UIModeState, embeddedUiConfig: EmbeddedUiConfig)
|
||||||
fun switchToEmbeddedView()
|
|
||||||
fun onBackPressed()
|
fun onBackPressed()
|
||||||
fun showUi()
|
fun showUi()
|
||||||
fun hideUi()
|
fun hideUi()
|
||||||
|
@ -56,8 +55,6 @@ interface NewPlayerViewModel {
|
||||||
fun finishFastSeek()
|
fun finishFastSeek()
|
||||||
fun brightnessChange(changeRate: Float, systemBrightness: Float)
|
fun brightnessChange(changeRate: Float, systemBrightness: Float)
|
||||||
fun volumeChange(changeRate: Float)
|
fun volumeChange(changeRate: Float)
|
||||||
fun openStreamSelection(selectChapter: Boolean, embeddedUiConfig: EmbeddedUiConfig)
|
|
||||||
fun closeStreamSelection()
|
|
||||||
fun chapterSelected(chapterId: Int)
|
fun chapterSelected(chapterId: Int)
|
||||||
fun streamSelected(streamId: Int)
|
fun streamSelected(streamId: Int)
|
||||||
fun cycleRepeatMode()
|
fun cycleRepeatMode()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.newpipe.newplayer.model
|
package net.newpipe.newplayer.model
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
@ -8,6 +9,7 @@ import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import net.newpipe.newplayer.NewPlayer
|
import net.newpipe.newplayer.NewPlayer
|
||||||
import net.newpipe.newplayer.ui.ContentScale
|
import net.newpipe.newplayer.ui.ContentScale
|
||||||
|
|
||||||
|
@UnstableApi
|
||||||
open class NewPlayerViewModelDummy : NewPlayerViewModel {
|
open class NewPlayerViewModelDummy : NewPlayerViewModel {
|
||||||
override var newPlayer: NewPlayer? = null
|
override var newPlayer: NewPlayer? = null
|
||||||
override val uiState = MutableStateFlow(NewPlayerUIState.DEFAULT)
|
override val uiState = MutableStateFlow(NewPlayerUIState.DEFAULT)
|
||||||
|
@ -25,18 +27,10 @@ open class NewPlayerViewModelDummy : NewPlayerViewModel {
|
||||||
println("dummy impl")
|
println("dummy impl")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun switchToEmbeddedView() {
|
|
||||||
println("dummy impl")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
println("dummy impl")
|
println("dummy impl")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun switchToFullscreen(embeddedUiConfig: EmbeddedUiConfig) {
|
|
||||||
println("dummy impl")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showUi() {
|
override fun showUi() {
|
||||||
println("dummy impl")
|
println("dummy impl")
|
||||||
}
|
}
|
||||||
|
@ -73,14 +67,6 @@ open class NewPlayerViewModelDummy : NewPlayerViewModel {
|
||||||
println("dummy impl")
|
println("dummy impl")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openStreamSelection(selectChapter: Boolean, embeddedUiConfig: EmbeddedUiConfig) {
|
|
||||||
println("dummy impl")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun closeStreamSelection() {
|
|
||||||
println("dummy impl")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterSelected(chapterId: Int) {
|
override fun chapterSelected(chapterId: Int) {
|
||||||
println("dummp impl chapter selected: $chapterId")
|
println("dummp impl chapter selected: $chapterId")
|
||||||
}
|
}
|
||||||
|
@ -128,4 +114,8 @@ open class NewPlayerViewModelDummy : NewPlayerViewModel {
|
||||||
override fun nextStream() {
|
override fun nextStream() {
|
||||||
println("dummy impl")
|
println("dummy impl")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun changeUiMode(newUiModeState: UIModeState, embeddedUiConfig: EmbeddedUiConfig) {
|
||||||
|
println("dummy uiMode change: New UI Mode State: $newUiModeState")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ class NewPlayerViewModelImpl @Inject constructor(
|
||||||
mutableUiState.update {
|
mutableUiState.update {
|
||||||
it.copy(playing = isPlaying, isLoading = false)
|
it.copy(playing = isPlaying, isLoading = false)
|
||||||
}
|
}
|
||||||
if (isPlaying && uiState.value.uiMode.controllerUiVisible) {
|
if (isPlaying && uiState.value.uiMode.videoControllerUiVisible) {
|
||||||
resetHideUiDelayedJob()
|
resetHideUiDelayedJob()
|
||||||
} else {
|
} else {
|
||||||
uiVisibilityJob?.cancel()
|
uiVisibilityJob?.cancel()
|
||||||
|
@ -329,6 +329,41 @@ class NewPlayerViewModelImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun changeUiMode(newUiModeState: UIModeState, embeddedUiConfig: EmbeddedUiConfig) {
|
||||||
|
if (!uiState.value.uiMode.fullscreen) {
|
||||||
|
this.embeddedUiConfig = embeddedUiConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newUiModeState.isStreamSelect) {
|
||||||
|
resetPlaylistProgressUpdaterJob()
|
||||||
|
uiVisibilityJob?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newUiModeState.isChapterSelect) {
|
||||||
|
resetPlaylistProgressUpdaterJob()
|
||||||
|
uiVisibilityJob?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uiState.value.uiMode.isStreamSelect || uiState.value.uiMode.isChapterSelect)
|
||||||
|
&& (!newUiModeState.isStreamSelect && !newUiModeState.isChapterSelect)
|
||||||
|
) {
|
||||||
|
playlistProgressUpdaterJob?.cancel()
|
||||||
|
progressUpdaterJob?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uiState.value.uiMode.fullscreen && !newUiModeState.fullscreen) {
|
||||||
|
uiVisibilityJob?.cancel()
|
||||||
|
finishFastSeek()
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!uiState.value.uiMode.fullscreen && newUiModeState.fullscreen) {
|
||||||
|
uiVisibilityJob?.cancel()
|
||||||
|
finishFastSeek()
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUiMode(newUiModeState)
|
||||||
|
}
|
||||||
|
|
||||||
override fun showUi() {
|
override fun showUi() {
|
||||||
mutableUiState.update {
|
mutableUiState.update {
|
||||||
it.copy(uiMode = it.uiMode.getControllerUiVisibleState())
|
it.copy(uiMode = it.uiMode.getControllerUiVisibleState())
|
||||||
|
@ -430,13 +465,13 @@ class NewPlayerViewModelImpl @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mutableUiState.value.uiMode.controllerUiVisible) {
|
if (mutableUiState.value.uiMode.videoControllerUiVisible) {
|
||||||
resetHideUiDelayedJob()
|
resetHideUiDelayedJob()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun finishFastSeek() {
|
override fun finishFastSeek() {
|
||||||
if (mutableUiState.value.uiMode.controllerUiVisible) {
|
if (mutableUiState.value.uiMode.videoControllerUiVisible) {
|
||||||
resetHideUiDelayedJob()
|
resetHideUiDelayedJob()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,34 +517,6 @@ class NewPlayerViewModelImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openStreamSelection(selectChapter: Boolean, embeddedUiConfig: EmbeddedUiConfig) {
|
|
||||||
uiVisibilityJob?.cancel()
|
|
||||||
if (!uiState.value.uiMode.fullscreen) {
|
|
||||||
this.embeddedUiConfig = embeddedUiConfig
|
|
||||||
}
|
|
||||||
updateUiMode(
|
|
||||||
if (selectChapter) uiState.value.uiMode.getChapterSelectUiState()
|
|
||||||
else uiState.value.uiMode.getStreamSelectUiState()
|
|
||||||
)
|
|
||||||
if (selectChapter) {
|
|
||||||
resetProgressUpdatePeriodicallyJob()
|
|
||||||
} else {
|
|
||||||
resetPlaylistProgressUpdaterJob()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun closeStreamSelection() {
|
|
||||||
playlistProgressUpdaterJob?.cancel()
|
|
||||||
progressUpdaterJob?.cancel()
|
|
||||||
updateUiMode(uiState.value.uiMode.getUiHiddenState())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun switchToEmbeddedView() {
|
|
||||||
uiVisibilityJob?.cancel()
|
|
||||||
finishFastSeek()
|
|
||||||
updateUiMode(UIModeState.EMBEDDED_VIDEO)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
val nextMode = uiState.value.uiMode.getNextModeWhenBackPressed()
|
val nextMode = uiState.value.uiMode.getNextModeWhenBackPressed()
|
||||||
if (nextMode != null) {
|
if (nextMode != null) {
|
||||||
|
@ -519,14 +526,6 @@ class NewPlayerViewModelImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun switchToFullscreen(embeddedUiConfig: EmbeddedUiConfig) {
|
|
||||||
uiVisibilityJob?.cancel()
|
|
||||||
finishFastSeek()
|
|
||||||
|
|
||||||
this.embeddedUiConfig = embeddedUiConfig
|
|
||||||
updateUiMode(UIModeState.FULLSCREEN_VIDEO)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterSelected(chapterId: Int) {
|
override fun chapterSelected(chapterId: Int) {
|
||||||
newPlayer?.selectChapter(chapterId)
|
newPlayer?.selectChapter(chapterId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,12 @@ enum class UIModeState {
|
||||||
FULLSCREEN_VIDEO,
|
FULLSCREEN_VIDEO,
|
||||||
FULLSCREEN_VIDEO_CONTROLLER_UI,
|
FULLSCREEN_VIDEO_CONTROLLER_UI,
|
||||||
FULLSCREEN_VIDEO_CHAPTER_SELECT,
|
FULLSCREEN_VIDEO_CHAPTER_SELECT,
|
||||||
FULLSCREEN_VIDEO_STREAM_SELECT;
|
FULLSCREEN_VIDEO_STREAM_SELECT,
|
||||||
|
|
||||||
|
EMBEDDED_AUDIO,
|
||||||
|
FULLSCREEN_AUDIO,
|
||||||
|
AUDIO_CHAPTER_SELECT,
|
||||||
|
AUDIO_STREAM_SELECT;
|
||||||
|
|
||||||
val fullscreen: Boolean
|
val fullscreen: Boolean
|
||||||
get() =
|
get() =
|
||||||
|
@ -44,10 +49,13 @@ enum class UIModeState {
|
||||||
FULLSCREEN_VIDEO_CONTROLLER_UI -> true
|
FULLSCREEN_VIDEO_CONTROLLER_UI -> true
|
||||||
FULLSCREEN_VIDEO_CHAPTER_SELECT -> true
|
FULLSCREEN_VIDEO_CHAPTER_SELECT -> true
|
||||||
FULLSCREEN_VIDEO_STREAM_SELECT -> true
|
FULLSCREEN_VIDEO_STREAM_SELECT -> true
|
||||||
|
FULLSCREEN_AUDIO -> true
|
||||||
|
AUDIO_CHAPTER_SELECT -> true
|
||||||
|
AUDIO_STREAM_SELECT -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
val controllerUiVisible: Boolean
|
val videoControllerUiVisible: Boolean
|
||||||
get() =
|
get() =
|
||||||
when (this) {
|
when (this) {
|
||||||
EMBEDDED_VIDEO_CONTROLLER_UI -> true
|
EMBEDDED_VIDEO_CONTROLLER_UI -> true
|
||||||
|
@ -60,6 +68,7 @@ enum class UIModeState {
|
||||||
when (this) {
|
when (this) {
|
||||||
EMBEDDED_VIDEO_STREAM_SELECT -> true
|
EMBEDDED_VIDEO_STREAM_SELECT -> true
|
||||||
FULLSCREEN_VIDEO_STREAM_SELECT -> true
|
FULLSCREEN_VIDEO_STREAM_SELECT -> true
|
||||||
|
AUDIO_STREAM_SELECT -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +77,7 @@ enum class UIModeState {
|
||||||
when (this) {
|
when (this) {
|
||||||
EMBEDDED_VIDEO_CHAPTER_SELECT -> true
|
EMBEDDED_VIDEO_CHAPTER_SELECT -> true
|
||||||
FULLSCREEN_VIDEO_CHAPTER_SELECT -> true
|
FULLSCREEN_VIDEO_CHAPTER_SELECT -> true
|
||||||
|
AUDIO_CHAPTER_SELECT -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +135,10 @@ enum class UIModeState {
|
||||||
EMBEDDED_VIDEO_CHAPTER_SELECT -> EMBEDDED_VIDEO_STREAM_SELECT
|
EMBEDDED_VIDEO_CHAPTER_SELECT -> EMBEDDED_VIDEO_STREAM_SELECT
|
||||||
EMBEDDED_VIDEO_CONTROLLER_UI -> EMBEDDED_VIDEO_STREAM_SELECT
|
EMBEDDED_VIDEO_CONTROLLER_UI -> EMBEDDED_VIDEO_STREAM_SELECT
|
||||||
|
|
||||||
|
FULLSCREEN_AUDIO -> AUDIO_STREAM_SELECT
|
||||||
|
EMBEDDED_AUDIO -> AUDIO_STREAM_SELECT
|
||||||
|
AUDIO_CHAPTER_SELECT -> AUDIO_STREAM_SELECT
|
||||||
|
|
||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +152,10 @@ enum class UIModeState {
|
||||||
EMBEDDED_VIDEO_STREAM_SELECT -> EMBEDDED_VIDEO_CHAPTER_SELECT
|
EMBEDDED_VIDEO_STREAM_SELECT -> EMBEDDED_VIDEO_CHAPTER_SELECT
|
||||||
EMBEDDED_VIDEO_CONTROLLER_UI -> EMBEDDED_VIDEO_CHAPTER_SELECT
|
EMBEDDED_VIDEO_CONTROLLER_UI -> EMBEDDED_VIDEO_CHAPTER_SELECT
|
||||||
|
|
||||||
|
FULLSCREEN_AUDIO -> AUDIO_CHAPTER_SELECT
|
||||||
|
EMBEDDED_AUDIO -> AUDIO_CHAPTER_SELECT
|
||||||
|
AUDIO_STREAM_SELECT -> AUDIO_CHAPTER_SELECT
|
||||||
|
|
||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +169,10 @@ enum class UIModeState {
|
||||||
FULLSCREEN_VIDEO_CONTROLLER_UI -> PlayMode.FULLSCREEN_VIDEO
|
FULLSCREEN_VIDEO_CONTROLLER_UI -> PlayMode.FULLSCREEN_VIDEO
|
||||||
FULLSCREEN_VIDEO_CHAPTER_SELECT -> PlayMode.FULLSCREEN_VIDEO
|
FULLSCREEN_VIDEO_CHAPTER_SELECT -> PlayMode.FULLSCREEN_VIDEO
|
||||||
FULLSCREEN_VIDEO_STREAM_SELECT -> PlayMode.FULLSCREEN_VIDEO
|
FULLSCREEN_VIDEO_STREAM_SELECT -> PlayMode.FULLSCREEN_VIDEO
|
||||||
|
EMBEDDED_AUDIO -> PlayMode.EMBEDDED_AUDIO
|
||||||
|
FULLSCREEN_AUDIO -> PlayMode.FULLSCREEN_AUDIO
|
||||||
|
AUDIO_CHAPTER_SELECT -> PlayMode.FULLSCREEN_AUDIO
|
||||||
|
AUDIO_STREAM_SELECT -> PlayMode.FULLSCREEN_AUDIO
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNextModeWhenBackPressed() = when (this) {
|
fun getNextModeWhenBackPressed() = when (this) {
|
||||||
|
@ -160,7 +182,13 @@ enum class UIModeState {
|
||||||
FULLSCREEN_VIDEO_STREAM_SELECT -> FULLSCREEN_VIDEO
|
FULLSCREEN_VIDEO_STREAM_SELECT -> FULLSCREEN_VIDEO
|
||||||
FULLSCREEN_VIDEO_CHAPTER_SELECT -> FULLSCREEN_VIDEO
|
FULLSCREEN_VIDEO_CHAPTER_SELECT -> FULLSCREEN_VIDEO
|
||||||
FULLSCREEN_VIDEO_CONTROLLER_UI -> EMBEDDED_VIDEO
|
FULLSCREEN_VIDEO_CONTROLLER_UI -> EMBEDDED_VIDEO
|
||||||
else -> null
|
PLACEHOLDER -> null
|
||||||
|
EMBEDDED_VIDEO -> null
|
||||||
|
EMBEDDED_VIDEO_CONTROLLER_UI -> null
|
||||||
|
EMBEDDED_AUDIO -> null
|
||||||
|
FULLSCREEN_AUDIO -> EMBEDDED_AUDIO
|
||||||
|
AUDIO_CHAPTER_SELECT -> FULLSCREEN_AUDIO
|
||||||
|
AUDIO_STREAM_SELECT -> FULLSCREEN_AUDIO
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -170,8 +198,10 @@ enum class UIModeState {
|
||||||
PlayMode.EMBEDDED_VIDEO -> EMBEDDED_VIDEO
|
PlayMode.EMBEDDED_VIDEO -> EMBEDDED_VIDEO
|
||||||
PlayMode.FULLSCREEN_VIDEO -> FULLSCREEN_VIDEO
|
PlayMode.FULLSCREEN_VIDEO -> FULLSCREEN_VIDEO
|
||||||
PlayMode.PIP -> TODO()
|
PlayMode.PIP -> TODO()
|
||||||
PlayMode.BACKGROUND -> TODO()
|
PlayMode.BACKGROUND_VIDEO -> TODO()
|
||||||
PlayMode.AUDIO_FOREGROUND -> TODO()
|
PlayMode.BACKGROUND_AUDIO -> TODO()
|
||||||
|
PlayMode.FULLSCREEN_AUDIO -> FULLSCREEN_AUDIO
|
||||||
|
PlayMode.EMBEDDED_AUDIO -> EMBEDDED_AUDIO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,7 +40,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerLoadingPlaceholder(aspectRatio: Float = 3F / 1F) {
|
fun LoadingPlaceholder(aspectRatio: Float = 3F / 1F) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -63,6 +63,6 @@ fun VideoPlayerLoadingPlaceholder(aspectRatio: Float = 3F / 1F) {
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerLoaidingPlaceholderPreview() {
|
fun VideoPlayerLoaidingPlaceholderPreview() {
|
||||||
VideoPlayerTheme {
|
VideoPlayerTheme {
|
||||||
VideoPlayerLoadingPlaceholder()
|
LoadingPlaceholder()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,26 +26,16 @@ import android.util.Log
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
@ -59,9 +49,8 @@ import androidx.media3.common.util.UnstableApi
|
||||||
import net.newpipe.newplayer.model.UIModeState
|
import net.newpipe.newplayer.model.UIModeState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
import net.newpipe.newplayer.ui.streamselect.StreamSelectUI
|
import net.newpipe.newplayer.ui.audioplayer.AudioPlayerUI
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.ui.videoplayer.VideoPlayerControllerUI
|
|
||||||
import net.newpipe.newplayer.ui.videoplayer.VideoPlayerUi
|
import net.newpipe.newplayer.ui.videoplayer.VideoPlayerUi
|
||||||
import net.newpipe.newplayer.utils.LockScreenOrientation
|
import net.newpipe.newplayer.utils.LockScreenOrientation
|
||||||
import net.newpipe.newplayer.utils.getDefaultBrightness
|
import net.newpipe.newplayer.utils.getDefaultBrightness
|
||||||
|
@ -75,9 +64,9 @@ fun NewPlayerUI(
|
||||||
viewModel: NewPlayerViewModel?,
|
viewModel: NewPlayerViewModel?,
|
||||||
) {
|
) {
|
||||||
if (viewModel == null) {
|
if (viewModel == null) {
|
||||||
VideoPlayerLoadingPlaceholder()
|
LoadingPlaceholder()
|
||||||
} else if (viewModel.newPlayer == null) {
|
} else if (viewModel.newPlayer == null) {
|
||||||
VideoPlayerLoadingPlaceholder(viewModel.uiState.collectAsState().value.embeddedUiRatio)
|
LoadingPlaceholder(viewModel.uiState.collectAsState().value.embeddedUiRatio)
|
||||||
} else {
|
} else {
|
||||||
val uiState by viewModel.uiState.collectAsState()
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
|
|
||||||
|
@ -142,12 +131,22 @@ fun NewPlayerUI(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set UI
|
if (uiState.uiMode == UIModeState.FULLSCREEN_VIDEO ||
|
||||||
if (uiState.uiMode == UIModeState.PLACEHOLDER) {
|
uiState.uiMode == UIModeState.FULLSCREEN_VIDEO_CONTROLLER_UI ||
|
||||||
VideoPlayerLoadingPlaceholder(uiState.embeddedUiRatio)
|
uiState.uiMode == UIModeState.FULLSCREEN_VIDEO_CHAPTER_SELECT ||
|
||||||
} else {
|
uiState.uiMode == UIModeState.FULLSCREEN_VIDEO_STREAM_SELECT ||
|
||||||
|
uiState.uiMode == UIModeState.EMBEDDED_VIDEO ||
|
||||||
|
uiState.uiMode == UIModeState.EMBEDDED_VIDEO_CONTROLLER_UI ||
|
||||||
|
uiState.uiMode == UIModeState.EMBEDDED_VIDEO_STREAM_SELECT ||
|
||||||
|
uiState.uiMode == UIModeState.EMBEDDED_VIDEO_CHAPTER_SELECT
|
||||||
|
) {
|
||||||
VideoPlayerUi(viewModel = viewModel, uiState = uiState)
|
VideoPlayerUi(viewModel = viewModel, uiState = uiState)
|
||||||
|
} else if (uiState.uiMode == UIModeState.FULLSCREEN_AUDIO) {
|
||||||
|
AudioPlayerUI(viewModel = viewModel, uiState = uiState)
|
||||||
|
} else {
|
||||||
|
LoadingPlaceholder(uiState.embeddedUiRatio)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ import net.newpipe.newplayer.R
|
||||||
import net.newpipe.newplayer.model.EmbeddedUiConfig
|
import net.newpipe.newplayer.model.EmbeddedUiConfig
|
||||||
import net.newpipe.newplayer.model.NewPlayerUIState
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
|
import net.newpipe.newplayer.model.UIModeState
|
||||||
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
|
|
||||||
@androidx.annotation.OptIn(UnstableApi::class)
|
@androidx.annotation.OptIn(UnstableApi::class)
|
||||||
|
@ -59,10 +60,7 @@ fun AudioPlayerTopBar(
|
||||||
AnimatedVisibility(visible = uiState.chapters.isNotEmpty()) {
|
AnimatedVisibility(visible = uiState.chapters.isNotEmpty()) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.openStreamSelection(
|
viewModel.changeUiMode(UIModeState.AUDIO_CHAPTER_SELECT, embeddedUiConfig)
|
||||||
selectChapter = true,
|
|
||||||
embeddedUiConfig
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
|
@ -74,10 +72,7 @@ fun AudioPlayerTopBar(
|
||||||
AnimatedVisibility(visible = 1 < uiState.playList.size) {
|
AnimatedVisibility(visible = 1 < uiState.playList.size) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.openStreamSelection(
|
viewModel.changeUiMode(UIModeState.AUDIO_STREAM_SELECT, embeddedUiConfig)
|
||||||
selectChapter = false,
|
|
||||||
embeddedUiConfig
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
package net.newpipe.newplayer.ui.streamselect
|
package net.newpipe.newplayer.ui.streamselect
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.PlaylistAdd
|
import androidx.compose.material.icons.automirrored.filled.PlaylistAdd
|
||||||
|
@ -37,18 +38,21 @@ import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import net.newpipe.newplayer.R
|
import net.newpipe.newplayer.R
|
||||||
import net.newpipe.newplayer.RepeatMode
|
import net.newpipe.newplayer.RepeatMode
|
||||||
|
import net.newpipe.newplayer.model.EmbeddedUiConfig
|
||||||
import net.newpipe.newplayer.model.NewPlayerUIState
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
import net.newpipe.newplayer.ui.common.RepeatModeButton
|
import net.newpipe.newplayer.ui.common.RepeatModeButton
|
||||||
import net.newpipe.newplayer.ui.common.ShuffleModeButton
|
import net.newpipe.newplayer.ui.common.ShuffleModeButton
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
import net.newpipe.newplayer.utils.getLocale
|
import net.newpipe.newplayer.utils.getLocale
|
||||||
import net.newpipe.newplayer.utils.getPlaylistDurationInMS
|
import net.newpipe.newplayer.utils.getPlaylistDurationInMS
|
||||||
import net.newpipe.newplayer.utils.getTimeStringFromMs
|
import net.newpipe.newplayer.utils.getTimeStringFromMs
|
||||||
|
@ -62,6 +66,12 @@ fun StreamSelectTopBar(
|
||||||
uiState: NewPlayerUIState
|
uiState: NewPlayerUIState
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
val embeddedUiConfig =
|
||||||
|
if (LocalContext.current is Activity)
|
||||||
|
getEmbeddedUiConfig(activity = LocalContext.current as Activity)
|
||||||
|
else
|
||||||
|
EmbeddedUiConfig.DUMMY
|
||||||
|
|
||||||
TopAppBar(modifier = modifier,
|
TopAppBar(modifier = modifier,
|
||||||
colors = topAppBarColors(containerColor = Color.Transparent),
|
colors = topAppBarColors(containerColor = Color.Transparent),
|
||||||
title = {
|
title = {
|
||||||
|
@ -91,7 +101,9 @@ fun StreamSelectTopBar(
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = viewModel::closeStreamSelection
|
onClick = {
|
||||||
|
viewModel.changeUiMode(uiState.uiMode.getUiHiddenState(), embeddedUiConfig)
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Close,
|
imageVector = Icons.Filled.Close,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
package net.newpipe.newplayer.ui.streamselect
|
package net.newpipe.newplayer.ui.streamselect
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
@ -36,15 +37,18 @@ import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import net.newpipe.newplayer.model.EmbeddedUiConfig
|
||||||
import net.newpipe.newplayer.model.NewPlayerUIState
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.ui.videoplayer.STREAMSELECT_UI_BACKGROUND_COLOR
|
import net.newpipe.newplayer.ui.videoplayer.STREAMSELECT_UI_BACKGROUND_COLOR
|
||||||
import net.newpipe.newplayer.utils.ReorderHapticFeedbackType
|
import net.newpipe.newplayer.utils.ReorderHapticFeedbackType
|
||||||
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
import net.newpipe.newplayer.utils.getInsets
|
import net.newpipe.newplayer.utils.getInsets
|
||||||
import net.newpipe.newplayer.utils.rememberReorderHapticFeedback
|
import net.newpipe.newplayer.utils.rememberReorderHapticFeedback
|
||||||
import sh.calvin.reorderable.ReorderableItem
|
import sh.calvin.reorderable.ReorderableItem
|
||||||
|
@ -60,6 +64,12 @@ fun StreamSelectUI(
|
||||||
uiState: NewPlayerUIState
|
uiState: NewPlayerUIState
|
||||||
) {
|
) {
|
||||||
val insets = getInsets()
|
val insets = getInsets()
|
||||||
|
|
||||||
|
val embeddedUiConfig = if (LocalContext.current is Activity)
|
||||||
|
getEmbeddedUiConfig(activity = LocalContext.current as Activity)
|
||||||
|
else
|
||||||
|
EmbeddedUiConfig.DUMMY
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = STREAMSELECT_UI_BACKGROUND_COLOR
|
color = STREAMSELECT_UI_BACKGROUND_COLOR
|
||||||
|
@ -72,8 +82,12 @@ fun StreamSelectUI(
|
||||||
topBar = {
|
topBar = {
|
||||||
if (isChapterSelect) {
|
if (isChapterSelect) {
|
||||||
ChapterSelectTopBar(
|
ChapterSelectTopBar(
|
||||||
onClose =
|
onClose = {
|
||||||
viewModel::closeStreamSelection
|
viewModel.changeUiMode(
|
||||||
|
uiState.uiMode.getUiHiddenState(),
|
||||||
|
embeddedUiConfig
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
StreamSelectTopBar(viewModel = viewModel, uiState = uiState)
|
StreamSelectTopBar(viewModel = viewModel, uiState = uiState)
|
||||||
|
@ -142,7 +156,9 @@ fun ReorderableStreamItemsList(
|
||||||
verticalArrangement = Arrangement.spacedBy(5.dp),
|
verticalArrangement = Arrangement.spacedBy(5.dp),
|
||||||
state = lazyListState
|
state = lazyListState
|
||||||
) {
|
) {
|
||||||
itemsIndexed(uiState.playList, key = { _, item -> item.mediaId.toLong() }) { index, playlistItem ->
|
itemsIndexed(
|
||||||
|
uiState.playList,
|
||||||
|
key = { _, item -> item.mediaId.toLong() }) { index, playlistItem ->
|
||||||
ReorderableItem(
|
ReorderableItem(
|
||||||
state = reorderableLazyListState,
|
state = reorderableLazyListState,
|
||||||
key = playlistItem.mediaId.toLong()
|
key = playlistItem.mediaId.toLong()
|
||||||
|
|
|
@ -60,7 +60,7 @@ fun VideoPlayerControllerUI(
|
||||||
|
|
||||||
val insets = getInsets()
|
val insets = getInsets()
|
||||||
|
|
||||||
AnimatedVisibility(uiState.uiMode.controllerUiVisible) {
|
AnimatedVisibility(uiState.uiMode.videoControllerUiVisible) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(), color = CONTROLLER_UI_BACKGROUND_COLOR
|
modifier = Modifier.fillMaxSize(), color = CONTROLLER_UI_BACKGROUND_COLOR
|
||||||
) {}
|
) {}
|
||||||
|
@ -82,7 +82,7 @@ fun VideoPlayerControllerUI(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(uiState.uiMode.controllerUiVisible) {
|
AnimatedVisibility(uiState.uiMode.videoControllerUiVisible) {
|
||||||
|
|
||||||
AnimatedVisibility(visible = !uiState.isLoading) {
|
AnimatedVisibility(visible = !uiState.isLoading) {
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
|
|
@ -77,10 +77,13 @@ fun BottomUI(
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = if (uiState.uiMode.fullscreen) viewModel::switchToEmbeddedView
|
onClick = if (uiState.uiMode.fullscreen) {
|
||||||
else {
|
{
|
||||||
{ // <- head of lambda ... yea kotlin is weird
|
viewModel.changeUiMode(UIModeState.EMBEDDED_VIDEO, embeddedUiConfig)
|
||||||
viewModel.switchToFullscreen(embeddedUiConfig)
|
}
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
viewModel.changeUiMode(UIModeState.FULLSCREEN_VIDEO, embeddedUiConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
@ -94,7 +97,6 @@ fun BottomUI(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
// Preview
|
// Preview
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -53,6 +53,7 @@ import net.newpipe.newplayer.R
|
||||||
import net.newpipe.newplayer.model.NewPlayerUIState
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
|
import net.newpipe.newplayer.model.UIModeState
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.ui.theme.video_player_onSurface
|
import net.newpipe.newplayer.ui.theme.video_player_onSurface
|
||||||
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
|
@ -103,7 +104,12 @@ fun TopUI(
|
||||||
}
|
}
|
||||||
AnimatedVisibility(visible = uiState.chapters.isNotEmpty()) {
|
AnimatedVisibility(visible = uiState.chapters.isNotEmpty()) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { viewModel.openStreamSelection(selectChapter = true, embeddedUiConfig) },
|
onClick = {
|
||||||
|
viewModel.changeUiMode(
|
||||||
|
uiState.uiMode.getChapterSelectUiState(),
|
||||||
|
embeddedUiConfig
|
||||||
|
)
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.AutoMirrored.Filled.MenuBook,
|
imageVector = Icons.AutoMirrored.Filled.MenuBook,
|
||||||
|
@ -114,8 +120,8 @@ fun TopUI(
|
||||||
AnimatedVisibility(visible = 1 < uiState.playList.size) {
|
AnimatedVisibility(visible = 1 < uiState.playList.size) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.openStreamSelection(
|
viewModel.changeUiMode(
|
||||||
selectChapter = false,
|
uiState.uiMode.getStreamSelectUiState(),
|
||||||
embeddedUiConfig
|
embeddedUiConfig
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,7 @@ package net.newpipe.newplayer.ui.videoplayer.gesture_ui
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.annotation.OptIn
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
@ -38,14 +39,17 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
import net.newpipe.newplayer.model.NewPlayerUIState
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
|
import net.newpipe.newplayer.model.UIModeState
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
|
|
||||||
private const val TAG = "EmbeddedGestureUI"
|
private const val TAG = "EmbeddedGestureUI"
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun EmbeddedGestureUI(
|
fun EmbeddedGestureUI(
|
||||||
modifier: Modifier = Modifier, viewModel: NewPlayerViewModel, uiState: NewPlayerUIState
|
modifier: Modifier = Modifier, viewModel: NewPlayerViewModel, uiState: NewPlayerUIState
|
||||||
|
@ -66,7 +70,7 @@ fun EmbeddedGestureUI(
|
||||||
|
|
||||||
// this check is there to allow a temporary move up in the downward gesture
|
// this check is there to allow a temporary move up in the downward gesture
|
||||||
if (downwardMovementMode == false) {
|
if (downwardMovementMode == false) {
|
||||||
viewModel.switchToFullscreen(embeddedUiConfig)
|
viewModel.changeUiMode(UIModeState.FULLSCREEN_VIDEO, embeddedUiConfig)
|
||||||
} else {
|
} else {
|
||||||
viewModel.embeddedDraggedDown(movement.y)
|
viewModel.embeddedDraggedDown(movement.y)
|
||||||
}
|
}
|
||||||
|
@ -78,7 +82,7 @@ fun EmbeddedGestureUI(
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaultOnRegularTap = {
|
val defaultOnRegularTap = {
|
||||||
if (uiState.uiMode.controllerUiVisible) {
|
if (uiState.uiMode.videoControllerUiVisible) {
|
||||||
viewModel.hideUi()
|
viewModel.hideUi()
|
||||||
} else {
|
} else {
|
||||||
viewModel.showUi()
|
viewModel.showUi()
|
||||||
|
@ -151,6 +155,7 @@ fun EmbeddedGestureUI(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "spec:width=600px,height=400px,dpi=440,orientation=landscape")
|
@Preview(device = "spec:width=600px,height=400px,dpi=440,orientation=landscape")
|
||||||
@Composable
|
@Composable
|
||||||
fun EmbeddedGestureUIPreview() {
|
fun EmbeddedGestureUIPreview() {
|
||||||
|
@ -159,10 +164,6 @@ fun EmbeddedGestureUIPreview() {
|
||||||
EmbeddedGestureUI(
|
EmbeddedGestureUI(
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
viewModel = object : NewPlayerViewModelDummy() {
|
viewModel = object : NewPlayerViewModelDummy() {
|
||||||
override fun switchToEmbeddedView() {
|
|
||||||
println("switch to fullscreen")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun embeddedDraggedDown(offset: Float) {
|
override fun embeddedDraggedDown(offset: Float) {
|
||||||
println("embedded view dragged down by $offset")
|
println("embedded view dragged down by $offset")
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
package net.newpipe.newplayer.ui.videoplayer.gesture_ui
|
package net.newpipe.newplayer.ui.videoplayer.gesture_ui
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import androidx.annotation.OptIn
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.core.Spring
|
import androidx.compose.animation.core.Spring
|
||||||
import androidx.compose.animation.core.spring
|
import androidx.compose.animation.core.spring
|
||||||
|
@ -44,17 +45,20 @@ import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
import net.newpipe.newplayer.model.UIModeState
|
import net.newpipe.newplayer.model.UIModeState
|
||||||
import net.newpipe.newplayer.model.NewPlayerUIState
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.utils.getDefaultBrightness
|
import net.newpipe.newplayer.utils.getDefaultBrightness
|
||||||
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
|
|
||||||
private enum class IndicatorMode {
|
private enum class IndicatorMode {
|
||||||
NONE, VOLUME_INDICATOR_VISSIBLE, BRIGHTNESS_INDICATOR_VISSIBLE
|
NONE, VOLUME_INDICATOR_VISSIBLE, BRIGHTNESS_INDICATOR_VISSIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun FullscreenGestureUI(
|
fun FullscreenGestureUI(
|
||||||
modifier: Modifier = Modifier, viewModel: NewPlayerViewModel, uiState: NewPlayerUIState
|
modifier: Modifier = Modifier, viewModel: NewPlayerViewModel, uiState: NewPlayerUIState
|
||||||
|
@ -69,7 +73,7 @@ fun FullscreenGestureUI(
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaultOnRegularTap = {
|
val defaultOnRegularTap = {
|
||||||
if (uiState.uiMode.controllerUiVisible) {
|
if (uiState.uiMode.videoControllerUiVisible) {
|
||||||
viewModel.hideUi()
|
viewModel.hideUi()
|
||||||
} else {
|
} else {
|
||||||
viewModel.showUi()
|
viewModel.showUi()
|
||||||
|
@ -79,6 +83,7 @@ fun FullscreenGestureUI(
|
||||||
val activity = LocalContext.current as Activity
|
val activity = LocalContext.current as Activity
|
||||||
|
|
||||||
val defaultBrightness = getDefaultBrightness(activity)
|
val defaultBrightness = getDefaultBrightness(activity)
|
||||||
|
val embeddedUiConfig = getEmbeddedUiConfig(activity = activity)
|
||||||
|
|
||||||
Box(modifier = modifier.onGloballyPositioned { coordinates ->
|
Box(modifier = modifier.onGloballyPositioned { coordinates ->
|
||||||
heightPx = coordinates.size.height.toFloat()
|
heightPx = coordinates.size.height.toFloat()
|
||||||
|
@ -119,7 +124,7 @@ fun FullscreenGestureUI(
|
||||||
onRegularTap = defaultOnRegularTap,
|
onRegularTap = defaultOnRegularTap,
|
||||||
onMovement = { movement ->
|
onMovement = { movement ->
|
||||||
if (0 < movement.y) {
|
if (0 < movement.y) {
|
||||||
viewModel.switchToEmbeddedView()
|
viewModel.changeUiMode(UIModeState.EMBEDDED_VIDEO, embeddedUiConfig)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMultiTap = { count ->
|
onMultiTap = { count ->
|
||||||
|
@ -215,6 +220,7 @@ fun IndicatorAnimation(modifier: Modifier, visible: Boolean, content: @Composabl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
|
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
|
||||||
@Composable
|
@Composable
|
||||||
fun FullscreenGestureUIPreview() {
|
fun FullscreenGestureUIPreview() {
|
||||||
|
@ -231,6 +237,7 @@ fun FullscreenGestureUIPreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "spec:parent=pixel_8,orientation=landscape")
|
@Preview(device = "spec:parent=pixel_8,orientation=landscape")
|
||||||
@Composable
|
@Composable
|
||||||
fun FullscreenGestureUIPreviewInteractive() {
|
fun FullscreenGestureUIPreviewInteractive() {
|
||||||
|
@ -255,6 +262,7 @@ fun FullscreenGestureUIPreviewInteractive() {
|
||||||
Surface(modifier = Modifier.wrapContentSize(), color = Color.Gray) {
|
Surface(modifier = Modifier.wrapContentSize(), color = Color.Gray) {
|
||||||
FullscreenGestureUI(
|
FullscreenGestureUI(
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
object : NewPlayerViewModelDummy() {
|
object : NewPlayerViewModelDummy() {
|
||||||
override fun hideUi() {
|
override fun hideUi() {
|
||||||
uiVisible = false
|
uiVisible = false
|
||||||
|
|
Loading…
Reference in New Issue