endtangle StreamSelect and ChapterSelect and fix glitches asociated with them
This commit is contained in:
parent
a4f8e490ae
commit
de507b2291
|
@ -330,18 +330,23 @@ class NewPlayerViewModelImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun changeUiMode(newUiModeState: UIModeState, embeddedUiConfig: EmbeddedUiConfig) {
|
override fun changeUiMode(newUiModeState: UIModeState, embeddedUiConfig: EmbeddedUiConfig) {
|
||||||
if (!uiState.value.uiMode.fullscreen) {
|
if (!uiState.value.uiMode.fullscreen && newUiModeState.fullscreen) {
|
||||||
this.embeddedUiConfig = embeddedUiConfig
|
this.embeddedUiConfig = embeddedUiConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!(newUiModeState == UIModeState.EMBEDDED_VIDEO_CONTROLLER_UI ||
|
||||||
|
newUiModeState == UIModeState.FULLSCREEN_VIDEO_CONTROLLER_UI)) {
|
||||||
|
uiVisibilityJob?.cancel()
|
||||||
|
} else {
|
||||||
|
resetHideUiDelayedJob()
|
||||||
|
}
|
||||||
|
|
||||||
if (newUiModeState.isStreamSelect) {
|
if (newUiModeState.isStreamSelect) {
|
||||||
resetPlaylistProgressUpdaterJob()
|
resetPlaylistProgressUpdaterJob()
|
||||||
uiVisibilityJob?.cancel()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newUiModeState.isChapterSelect) {
|
if (newUiModeState.isChapterSelect) {
|
||||||
resetPlaylistProgressUpdaterJob()
|
resetPlaylistProgressUpdaterJob()
|
||||||
uiVisibilityJob?.cancel()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uiState.value.uiMode.isStreamSelect || uiState.value.uiMode.isChapterSelect)
|
if ((uiState.value.uiMode.isStreamSelect || uiState.value.uiMode.isChapterSelect)
|
||||||
|
@ -351,16 +356,6 @@ class NewPlayerViewModelImpl @Inject constructor(
|
||||||
progressUpdaterJob?.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)
|
updateUiMode(newUiModeState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,10 +368,17 @@ class NewPlayerViewModelImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resetHideUiDelayedJob() {
|
private fun resetHideUiDelayedJob() {
|
||||||
|
var ex:Exception? = null
|
||||||
|
try {
|
||||||
|
throw Exception()
|
||||||
|
} catch(e: Exception) {
|
||||||
|
ex = e
|
||||||
|
}
|
||||||
uiVisibilityJob?.cancel()
|
uiVisibilityJob?.cancel()
|
||||||
uiVisibilityJob = viewModelScope.launch {
|
uiVisibilityJob = viewModelScope.launch {
|
||||||
delay(2000)
|
delay(2000)
|
||||||
hideUi()
|
hideUi()
|
||||||
|
ex?.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
/* NewPlayer
|
|
||||||
*
|
|
||||||
* @author Christian Schabesberger
|
|
||||||
*
|
|
||||||
* Copyright (C) NewPipe e.V. 2024 <code(at)newpipe-ev.de>
|
|
||||||
*
|
|
||||||
* NewPlayer is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPlayer is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPlayer. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.newpipe.newplayer.model
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.media3.common.MediaItem
|
|
||||||
import androidx.media3.common.Player
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import net.newpipe.newplayer.MediaRepository
|
|
||||||
import net.newpipe.newplayer.NewPlayerException
|
|
||||||
import net.newpipe.newplayer.utils.Thumbnail
|
|
||||||
import kotlin.coroutines.coroutineContext
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ 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.model.UIModeState
|
||||||
import net.newpipe.newplayer.ui.common.NewPlayerSeeker
|
import net.newpipe.newplayer.ui.common.NewPlayerSeeker
|
||||||
|
import net.newpipe.newplayer.ui.streamselect.ChapterSelectUI
|
||||||
import net.newpipe.newplayer.ui.streamselect.StreamSelectUI
|
import net.newpipe.newplayer.ui.streamselect.StreamSelectUI
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.utils.Thumbnail
|
import net.newpipe.newplayer.utils.Thumbnail
|
||||||
|
@ -85,7 +86,7 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
enter = UI_ENTER_ANIMATION,
|
enter = UI_ENTER_ANIMATION,
|
||||||
exit = UI_EXIT_ANIMATION
|
exit = UI_EXIT_ANIMATION
|
||||||
) {
|
) {
|
||||||
StreamSelectUI(viewModel = viewModel, uiState = uiState, isChapterSelect = true)
|
ChapterSelectUI(viewModel = viewModel, uiState = uiState)
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
|
@ -93,7 +94,7 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
enter = UI_ENTER_ANIMATION,
|
enter = UI_ENTER_ANIMATION,
|
||||||
exit = UI_EXIT_ANIMATION
|
exit = UI_EXIT_ANIMATION
|
||||||
) {
|
) {
|
||||||
StreamSelectUI(viewModel = viewModel, uiState = uiState, isChapterSelect = false)
|
StreamSelectUI(viewModel = viewModel, uiState = uiState)
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
/* NewPlayer
|
||||||
|
*
|
||||||
|
* @author Christian Schabesberger
|
||||||
|
*
|
||||||
|
* Copyright (C) NewPipe e.V. 2024 <code(at)newpipe-ev.de>
|
||||||
|
*
|
||||||
|
* NewPlayer is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPlayer is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPlayer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
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.utils.getEmbeddedUiConfig
|
||||||
|
import net.newpipe.newplayer.utils.getInsets
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
@Composable
|
||||||
|
fun ChapterSelectUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
|
val insets = getInsets()
|
||||||
|
|
||||||
|
val embeddedUiConfig = if (LocalContext.current is Activity)
|
||||||
|
getEmbeddedUiConfig(activity = LocalContext.current as Activity)
|
||||||
|
else
|
||||||
|
EmbeddedUiConfig.DUMMY
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.windowInsetsPadding(insets),
|
||||||
|
containerColor = Color.Transparent,
|
||||||
|
topBar = {
|
||||||
|
ChapterSelectTopBar(
|
||||||
|
onClose = {
|
||||||
|
viewModel.changeUiMode(
|
||||||
|
uiState.uiMode.getNextModeWhenBackPressed() ?: uiState.uiMode,
|
||||||
|
embeddedUiConfig
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { innerPadding ->
|
||||||
|
Box(modifier = Modifier.padding(innerPadding)) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 5.dp, end = 5.dp)
|
||||||
|
.fillMaxSize(),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(5.dp),
|
||||||
|
) {
|
||||||
|
items(uiState.chapters.size) { chapterIndex ->
|
||||||
|
val chapter = uiState.chapters[chapterIndex]
|
||||||
|
ChapterItem(
|
||||||
|
id = chapterIndex,
|
||||||
|
chapterTitle = chapter.chapterTitle ?: "",
|
||||||
|
chapterStartInMs = chapter.chapterStartInMs,
|
||||||
|
thumbnail = chapter.thumbnail,
|
||||||
|
onClicked = {
|
||||||
|
viewModel.chapterSelected(chapterIndex)
|
||||||
|
},
|
||||||
|
isCurrentChapter = isActiveChapter(
|
||||||
|
chapterIndex,
|
||||||
|
uiState.chapters,
|
||||||
|
uiState.playbackPositionInMs
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
@Preview(device = "id:pixel_5")
|
||||||
|
@Composable
|
||||||
|
fun VideoPlayerChannelSelectUIPreview() {
|
||||||
|
VideoPlayerTheme {
|
||||||
|
Surface(modifier = Modifier.fillMaxSize(), color = Color.Red) {
|
||||||
|
ChapterSelectUI(
|
||||||
|
viewModel = NewPlayerViewModelDummy(),
|
||||||
|
uiState = NewPlayerUIState.DUMMY
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,74 +59,28 @@ val ITEM_CORNER_SHAPE = RoundedCornerShape(10.dp)
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun StreamSelectUI(
|
fun StreamSelectUI(
|
||||||
isChapterSelect: Boolean = false,
|
|
||||||
viewModel: NewPlayerViewModel,
|
viewModel: NewPlayerViewModel,
|
||||||
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
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(insets),
|
.windowInsetsPadding(insets),
|
||||||
containerColor = Color.Transparent,
|
containerColor = Color.Transparent,
|
||||||
topBar = {
|
topBar = {
|
||||||
if (isChapterSelect) {
|
StreamSelectTopBar(viewModel = viewModel, uiState = uiState)
|
||||||
ChapterSelectTopBar(
|
|
||||||
onClose = {
|
|
||||||
viewModel.changeUiMode(
|
|
||||||
uiState.uiMode.getNextModeWhenBackPressed() ?: uiState.uiMode,
|
|
||||||
embeddedUiConfig
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
StreamSelectTopBar(viewModel = viewModel, uiState = uiState)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
Box(modifier = Modifier.padding(innerPadding)) {
|
Box(modifier = Modifier.padding(innerPadding)) {
|
||||||
if (isChapterSelect) {
|
ReorderableStreamItemsList(
|
||||||
LazyColumn(
|
padding = PaddingValues(start = 5.dp, end = 5.dp),
|
||||||
modifier = Modifier
|
viewModel = viewModel,
|
||||||
.padding(start = 5.dp, end = 5.dp)
|
uiState = uiState
|
||||||
.fillMaxSize(),
|
)
|
||||||
verticalArrangement = Arrangement.spacedBy(5.dp),
|
|
||||||
) {
|
|
||||||
items(uiState.chapters.size) { chapterIndex ->
|
|
||||||
val chapter = uiState.chapters[chapterIndex]
|
|
||||||
ChapterItem(
|
|
||||||
id = chapterIndex,
|
|
||||||
chapterTitle = chapter.chapterTitle ?: "",
|
|
||||||
chapterStartInMs = chapter.chapterStartInMs,
|
|
||||||
thumbnail = chapter.thumbnail,
|
|
||||||
onClicked = {
|
|
||||||
viewModel.chapterSelected(chapterIndex)
|
|
||||||
},
|
|
||||||
isCurrentChapter = isActiveChapter(
|
|
||||||
chapterIndex,
|
|
||||||
uiState.chapters,
|
|
||||||
uiState.playbackPositionInMs
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ReorderableStreamItemsList(
|
|
||||||
padding = PaddingValues(start = 5.dp, end = 5.dp),
|
|
||||||
viewModel = viewModel,
|
|
||||||
uiState = uiState
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
|
@ -176,21 +130,6 @@ fun ReorderableStreamItemsList(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
|
||||||
@Preview(device = "id:pixel_5")
|
|
||||||
@Composable
|
|
||||||
fun VideoPlayerChannelSelectUIPreview() {
|
|
||||||
VideoPlayerTheme {
|
|
||||||
Surface(modifier = Modifier.fillMaxSize(), color = Color.Red) {
|
|
||||||
StreamSelectUI(
|
|
||||||
isChapterSelect = true,
|
|
||||||
viewModel = NewPlayerViewModelDummy(),
|
|
||||||
uiState = NewPlayerUIState.DUMMY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "id:pixel_5")
|
@Preview(device = "id:pixel_5")
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -198,7 +137,6 @@ fun VideoPlayerStreamSelectUIPreview() {
|
||||||
VideoPlayerTheme {
|
VideoPlayerTheme {
|
||||||
Surface(modifier = Modifier.fillMaxSize(), color = Color.Red) {
|
Surface(modifier = Modifier.fillMaxSize(), color = Color.Red) {
|
||||||
StreamSelectUI(
|
StreamSelectUI(
|
||||||
isChapterSelect = false,
|
|
||||||
viewModel = NewPlayerViewModelDummy(),
|
viewModel = NewPlayerViewModelDummy(),
|
||||||
uiState = NewPlayerUIState.DUMMY
|
uiState = NewPlayerUIState.DUMMY
|
||||||
)
|
)
|
||||||
|
|
|
@ -47,6 +47,7 @@ import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.ui.PlaySurface
|
import net.newpipe.newplayer.ui.PlaySurface
|
||||||
import net.newpipe.newplayer.ui.streamselect.StreamSelectUI
|
import net.newpipe.newplayer.ui.streamselect.StreamSelectUI
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
import net.newpipe.newplayer.ui.streamselect.ChapterSelectUI
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -116,7 +117,6 @@ fun VideoPlayerUi(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
StreamSelectUI(
|
StreamSelectUI(
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
uiState = uiState,
|
uiState = uiState,
|
||||||
isChapterSelect = false
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ fun VideoPlayerUi(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = STREAMSELECT_UI_BACKGROUND_COLOR
|
color = STREAMSELECT_UI_BACKGROUND_COLOR
|
||||||
) {
|
) {
|
||||||
StreamSelectUI(viewModel = viewModel, uiState = uiState, isChapterSelect = true)
|
ChapterSelectUI(viewModel = viewModel, uiState = uiState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue