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