endtangle StreamSelect and ChapterSelect and fix glitches asociated with them

This commit is contained in:
Christian Schabesberger 2024-09-23 18:05:22 +02:00
parent a4f8e490ae
commit de507b2291
6 changed files with 142 additions and 118 deletions

View File

@ -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()
} }
} }

View File

@ -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

View File

@ -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(

View File

@ -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
)
}
}
}

View File

@ -59,65 +59,21 @@ 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) {
ChapterSelectTopBar(
onClose = {
viewModel.changeUiMode(
uiState.uiMode.getNextModeWhenBackPressed() ?: uiState.uiMode,
embeddedUiConfig
)
}
)
} else {
StreamSelectTopBar(viewModel = viewModel, uiState = uiState) StreamSelectTopBar(viewModel = viewModel, uiState = uiState)
} }
}
) { innerPadding -> ) { innerPadding ->
Box(modifier = Modifier.padding(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( ReorderableStreamItemsList(
padding = PaddingValues(start = 5.dp, end = 5.dp), padding = PaddingValues(start = 5.dp, end = 5.dp),
viewModel = viewModel, viewModel = viewModel,
@ -127,8 +83,6 @@ fun StreamSelectUI(
} }
} }
}
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
@Composable @Composable
fun ReorderableStreamItemsList( fun ReorderableStreamItemsList(
@ -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
) )

View File

@ -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)
} }
} }
} }