From de507b229137c534263f22b22b5c823ea46e28ec Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Mon, 23 Sep 2024 18:05:22 +0200 Subject: [PATCH] endtangle StreamSelect and ChapterSelect and fix glitches asociated with them --- .../newplayer/model/NewPlayerViewModelImpl.kt | 28 +++-- .../newpipe/newplayer/model/PlayListItem.kt | 33 ----- .../newplayer/ui/audioplayer/AudioPlayerUI.kt | 5 +- .../ui/streamselect/ChapterSelectUI.kt | 116 ++++++++++++++++++ .../ui/streamselect/StreamSelectUI.kt | 74 +---------- .../newplayer/ui/videoplayer/VideoPlayerUI.kt | 4 +- 6 files changed, 142 insertions(+), 118 deletions(-) delete mode 100644 new-player/src/main/java/net/newpipe/newplayer/model/PlayListItem.kt create mode 100644 new-player/src/main/java/net/newpipe/newplayer/ui/streamselect/ChapterSelectUI.kt diff --git a/new-player/src/main/java/net/newpipe/newplayer/model/NewPlayerViewModelImpl.kt b/new-player/src/main/java/net/newpipe/newplayer/model/NewPlayerViewModelImpl.kt index 84245af..76c1175 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/model/NewPlayerViewModelImpl.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/model/NewPlayerViewModelImpl.kt @@ -330,18 +330,23 @@ class NewPlayerViewModelImpl @Inject constructor( } override fun changeUiMode(newUiModeState: UIModeState, embeddedUiConfig: EmbeddedUiConfig) { - if (!uiState.value.uiMode.fullscreen) { + if (!uiState.value.uiMode.fullscreen && newUiModeState.fullscreen) { this.embeddedUiConfig = embeddedUiConfig } + if(!(newUiModeState == UIModeState.EMBEDDED_VIDEO_CONTROLLER_UI || + newUiModeState == UIModeState.FULLSCREEN_VIDEO_CONTROLLER_UI)) { + uiVisibilityJob?.cancel() + } else { + resetHideUiDelayedJob() + } + if (newUiModeState.isStreamSelect) { resetPlaylistProgressUpdaterJob() - uiVisibilityJob?.cancel() } if (newUiModeState.isChapterSelect) { resetPlaylistProgressUpdaterJob() - uiVisibilityJob?.cancel() } if ((uiState.value.uiMode.isStreamSelect || uiState.value.uiMode.isChapterSelect) @@ -351,16 +356,6 @@ class NewPlayerViewModelImpl @Inject constructor( progressUpdaterJob?.cancel() } - if(uiState.value.uiMode.fullscreen && !newUiModeState.fullscreen) { - uiVisibilityJob?.cancel() - finishFastSeek() - } - - if(!uiState.value.uiMode.fullscreen && newUiModeState.fullscreen) { - uiVisibilityJob?.cancel() - finishFastSeek() - } - updateUiMode(newUiModeState) } @@ -373,10 +368,17 @@ class NewPlayerViewModelImpl @Inject constructor( } private fun resetHideUiDelayedJob() { + var ex:Exception? = null + try { + throw Exception() + } catch(e: Exception) { + ex = e + } uiVisibilityJob?.cancel() uiVisibilityJob = viewModelScope.launch { delay(2000) hideUi() + ex?.printStackTrace() } } diff --git a/new-player/src/main/java/net/newpipe/newplayer/model/PlayListItem.kt b/new-player/src/main/java/net/newpipe/newplayer/model/PlayListItem.kt deleted file mode 100644 index a99a24a..0000000 --- a/new-player/src/main/java/net/newpipe/newplayer/model/PlayListItem.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* NewPlayer - * - * @author Christian Schabesberger - * - * Copyright (C) NewPipe e.V. 2024 - * - * 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 . - * - */ - -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 - diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/audioplayer/AudioPlayerUI.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/audioplayer/AudioPlayerUI.kt index 95c6eba..bf2f856 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/audioplayer/AudioPlayerUI.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/audioplayer/AudioPlayerUI.kt @@ -55,6 +55,7 @@ import net.newpipe.newplayer.model.NewPlayerViewModel import net.newpipe.newplayer.model.NewPlayerViewModelDummy import net.newpipe.newplayer.model.UIModeState 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.theme.VideoPlayerTheme import net.newpipe.newplayer.utils.Thumbnail @@ -85,7 +86,7 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) { enter = UI_ENTER_ANIMATION, exit = UI_EXIT_ANIMATION ) { - StreamSelectUI(viewModel = viewModel, uiState = uiState, isChapterSelect = true) + ChapterSelectUI(viewModel = viewModel, uiState = uiState) } AnimatedVisibility( @@ -93,7 +94,7 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) { enter = UI_ENTER_ANIMATION, exit = UI_EXIT_ANIMATION ) { - StreamSelectUI(viewModel = viewModel, uiState = uiState, isChapterSelect = false) + StreamSelectUI(viewModel = viewModel, uiState = uiState) } AnimatedVisibility( diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/streamselect/ChapterSelectUI.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/streamselect/ChapterSelectUI.kt new file mode 100644 index 0000000..9d072d8 --- /dev/null +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/streamselect/ChapterSelectUI.kt @@ -0,0 +1,116 @@ +/* NewPlayer + * + * @author Christian Schabesberger + * + * Copyright (C) NewPipe e.V. 2024 + * + * 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 . + */ + +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 + ) + } + } +} \ No newline at end of file diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/streamselect/StreamSelectUI.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/streamselect/StreamSelectUI.kt index 9ad8977..41a8802 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/streamselect/StreamSelectUI.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/streamselect/StreamSelectUI.kt @@ -59,74 +59,28 @@ val ITEM_CORNER_SHAPE = RoundedCornerShape(10.dp) @OptIn(UnstableApi::class) @Composable fun StreamSelectUI( - isChapterSelect: Boolean = false, 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 = { - if (isChapterSelect) { - ChapterSelectTopBar( - onClose = { - viewModel.changeUiMode( - uiState.uiMode.getNextModeWhenBackPressed() ?: uiState.uiMode, - embeddedUiConfig - ) - } - ) - } else { - StreamSelectTopBar(viewModel = viewModel, uiState = uiState) - } + StreamSelectTopBar(viewModel = viewModel, uiState = uiState) } ) { innerPadding -> Box(modifier = Modifier.padding(innerPadding)) { - if (isChapterSelect) { - 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 - ) - ) - } - - } - } else { - ReorderableStreamItemsList( - padding = PaddingValues(start = 5.dp, end = 5.dp), - viewModel = viewModel, - uiState = uiState - ) - } + ReorderableStreamItemsList( + padding = PaddingValues(start = 5.dp, end = 5.dp), + viewModel = viewModel, + uiState = uiState + ) } } - } @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) @Preview(device = "id:pixel_5") @Composable @@ -198,7 +137,6 @@ fun VideoPlayerStreamSelectUIPreview() { VideoPlayerTheme { Surface(modifier = Modifier.fillMaxSize(), color = Color.Red) { StreamSelectUI( - isChapterSelect = false, viewModel = NewPlayerViewModelDummy(), uiState = NewPlayerUIState.DUMMY ) diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/VideoPlayerUI.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/VideoPlayerUI.kt index c0ae262..d32009f 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/VideoPlayerUI.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/videoplayer/VideoPlayerUI.kt @@ -47,6 +47,7 @@ import net.newpipe.newplayer.model.NewPlayerViewModel import net.newpipe.newplayer.ui.PlaySurface import net.newpipe.newplayer.ui.streamselect.StreamSelectUI import androidx.lifecycle.LifecycleEventObserver +import net.newpipe.newplayer.ui.streamselect.ChapterSelectUI @OptIn(UnstableApi::class) @Composable @@ -116,7 +117,6 @@ fun VideoPlayerUi(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) { StreamSelectUI( viewModel = viewModel, uiState = uiState, - isChapterSelect = false ) } } @@ -125,7 +125,7 @@ fun VideoPlayerUi(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) { modifier = Modifier.fillMaxSize(), color = STREAMSELECT_UI_BACKGROUND_COLOR ) { - StreamSelectUI(viewModel = viewModel, uiState = uiState, isChapterSelect = true) + ChapterSelectUI(viewModel = viewModel, uiState = uiState) } } }