make shuffle and repeatmode work

This commit is contained in:
Christian Schabesberger 2024-09-03 13:54:33 +02:00
parent c0a006f238
commit 9a71e8f0b5
6 changed files with 75 additions and 39 deletions

View File

@ -53,6 +53,12 @@ enum class PlayMode {
AUDIO_FOREGROUND, AUDIO_FOREGROUND,
} }
enum class RepeatMode {
DONT_REPEAT,
REPEAT_ALL,
REPEAT_ONE
}
private val TAG = "NewPlayer" private val TAG = "NewPlayer"
interface NewPlayer { interface NewPlayer {
@ -68,6 +74,8 @@ interface NewPlayer {
var fastSeekAmountSec: Int var fastSeekAmountSec: Int
var playBackMode: PlayMode var playBackMode: PlayMode
var playMode: StateFlow<PlayMode?> var playMode: StateFlow<PlayMode?>
var shuffle: Boolean
var repeatMode: RepeatMode
val playlist: StateFlow<List<PlaylistItem>> val playlist: StateFlow<List<PlaylistItem>>
@ -154,6 +162,27 @@ class NewPlayerImpl(
var mutablePlayMode = MutableStateFlow<PlayMode?>(null) var mutablePlayMode = MutableStateFlow<PlayMode?>(null)
override var playMode = mutablePlayMode.asStateFlow() override var playMode = mutablePlayMode.asStateFlow()
override var shuffle: Boolean
get() = internalPlayer.shuffleModeEnabled
set(value) {
internalPlayer.shuffleModeEnabled = value
}
override var repeatMode: RepeatMode
get() = when(internalPlayer.repeatMode) {
Player.REPEAT_MODE_OFF -> RepeatMode.DONT_REPEAT
Player.REPEAT_MODE_ALL -> RepeatMode.REPEAT_ALL
Player.REPEAT_MODE_ONE -> RepeatMode.REPEAT_ONE
else -> throw NewPlayerException("Unknown Repeatmode option returned by ExoPlayer: ${internalPlayer.repeatMode}")
}
set(value) {
when(value) {
RepeatMode.DONT_REPEAT -> internalPlayer.repeatMode = Player.REPEAT_MODE_OFF
RepeatMode.REPEAT_ALL -> internalPlayer.repeatMode = Player.REPEAT_MODE_ALL
RepeatMode.REPEAT_ONE -> internalPlayer.repeatMode = Player.REPEAT_MODE_ONE
}
}
var mutableOnEvent = MutableSharedFlow<Pair<Player, Player.Events>>() var mutableOnEvent = MutableSharedFlow<Pair<Player, Player.Events>>()
override val onExoPlayerEvent: SharedFlow<Pair<Player, Player.Events>> = override val onExoPlayerEvent: SharedFlow<Pair<Player, Player.Events>> =
mutableOnEvent.asSharedFlow() mutableOnEvent.asSharedFlow()

View File

@ -22,6 +22,7 @@ package net.newpipe.newplayer.model
import androidx.media3.common.Player import androidx.media3.common.Player
import net.newpipe.newplayer.Chapter import net.newpipe.newplayer.Chapter
import net.newpipe.newplayer.RepeatMode
import net.newpipe.newplayer.playerInternals.PlaylistItem import net.newpipe.newplayer.playerInternals.PlaylistItem
import net.newpipe.newplayer.ui.ContentScale import net.newpipe.newplayer.ui.ContentScale
@ -43,7 +44,7 @@ data class VideoPlayerUIState(
val playList: List<PlaylistItem>, val playList: List<PlaylistItem>,
val chapters: List<Chapter>, val chapters: List<Chapter>,
val shuffleEnabled: Boolean, val shuffleEnabled: Boolean,
val repeatMode: Int, val repeatMode: RepeatMode,
val playListDurationInS: Int val playListDurationInS: Int
) { ) {
companion object { companion object {
@ -68,7 +69,7 @@ data class VideoPlayerUIState(
playList = emptyList(), playList = emptyList(),
chapters = emptyList(), chapters = emptyList(),
shuffleEnabled = false, shuffleEnabled = false,
repeatMode = Player.REPEAT_MODE_OFF, repeatMode = RepeatMode.DONT_REPEAT,
playListDurationInS = 0 playListDurationInS = 0
) )
} }

View File

@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import net.newpipe.newplayer.Chapter import net.newpipe.newplayer.Chapter
import net.newpipe.newplayer.NewPlayer import net.newpipe.newplayer.NewPlayer
import net.newpipe.newplayer.RepeatMode
import net.newpipe.newplayer.ui.ContentScale import net.newpipe.newplayer.ui.ContentScale
import net.newpipe.newplayer.utils.Thumbnail import net.newpipe.newplayer.utils.Thumbnail
@ -60,8 +61,8 @@ interface VideoPlayerViewModel {
fun closeStreamSelection() fun closeStreamSelection()
fun chapterSelected(chapter: Chapter) fun chapterSelected(chapter: Chapter)
fun streamSelected(streamId: Int) fun streamSelected(streamId: Int)
fun setRepeatmode(repeatMode: Int) fun cycleRepeatmode()
fun setSuffleEnabled(enabled: Boolean) fun toggleShuffle()
fun onStorePlaylist() fun onStorePlaylist()
fun movePlaylistItem(from: Int, to: Int) fun movePlaylistItem(from: Int, to: Int)
fun removePlaylistItem(index: Int) fun removePlaylistItem(index: Int)

View File

@ -45,6 +45,7 @@ import kotlinx.coroutines.launch
import net.newpipe.newplayer.Chapter import net.newpipe.newplayer.Chapter
import net.newpipe.newplayer.utils.VideoSize import net.newpipe.newplayer.utils.VideoSize
import net.newpipe.newplayer.NewPlayer import net.newpipe.newplayer.NewPlayer
import net.newpipe.newplayer.RepeatMode
import net.newpipe.newplayer.ui.ContentScale import net.newpipe.newplayer.ui.ContentScale
import java.util.LinkedList import java.util.LinkedList
@ -132,7 +133,8 @@ class VideoPlayerViewModelImpl @Inject constructor(
override val onBackPressed: SharedFlow<Unit> = mutableOnBackPressed.asSharedFlow() override val onBackPressed: SharedFlow<Unit> = mutableOnBackPressed.asSharedFlow()
private fun installNewPlayer() { private fun installNewPlayer() {
newPlayer?.internalPlayer?.let { player -> newPlayer?.let { newPlayer ->
val player = newPlayer.internalPlayer
Log.d(TAG, "Install player: ${player.videoSize.width}") Log.d(TAG, "Install player: ${player.videoSize.width}")
player.addListener(object : Player.Listener { player.addListener(object : Player.Listener {
@ -157,6 +159,20 @@ class VideoPlayerViewModelImpl @Inject constructor(
it.copy(isLoading = isLoading) it.copy(isLoading = isLoading)
} }
} }
override fun onRepeatModeChanged(repeatMode: Int) {
super.onRepeatModeChanged(repeatMode)
mutableUiState.update {
it.copy(repeatMode = newPlayer.repeatMode)
}
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
super.onShuffleModeEnabledChanged(shuffleModeEnabled)
mutableUiState.update {
it.copy(shuffleEnabled = newPlayer.shuffle)
}
}
}) })
} }
newPlayer?.let { newPlayer -> newPlayer?.let { newPlayer ->
@ -406,19 +422,20 @@ class VideoPlayerViewModelImpl @Inject constructor(
println("stream selected: $streamId") println("stream selected: $streamId")
} }
override fun setRepeatmode(repeatMode: Int) { override fun cycleRepeatmode() {
assert( newPlayer?.let {
repeatMode == Player.REPEAT_MODE_ALL it.repeatMode = when (it.repeatMode) {
|| repeatMode == Player.REPEAT_MODE_OFF RepeatMode.DONT_REPEAT -> RepeatMode.REPEAT_ALL
|| repeatMode == Player.REPEAT_MODE_ONE RepeatMode.REPEAT_ALL -> RepeatMode.REPEAT_ONE
) { RepeatMode.REPEAT_ONE -> RepeatMode.DONT_REPEAT
"Illegal repeat mode: $repeatMode" }
} }
TODO("Not yet implemented")
} }
override fun setSuffleEnabled(enabled: Boolean) { override fun toggleShuffle() {
TODO("Not yet implemented") newPlayer?.let {
it.shuffle = !it.shuffle
}
} }
override fun onStorePlaylist() { override fun onStorePlaylist() {
@ -453,7 +470,6 @@ class VideoPlayerViewModelImpl @Inject constructor(
} }
private fun updateUiMode(newState: UIModeState) { private fun updateUiMode(newState: UIModeState) {
val newPlayMode = newState.toPlayMode() val newPlayMode = newState.toPlayMode()
val currentPlayMode = mutableUiState.value.uiMode.toPlayMode() val currentPlayMode = mutableUiState.value.uiMode.toPlayMode()

View File

@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
import net.newpipe.newplayer.Chapter import net.newpipe.newplayer.Chapter
import net.newpipe.newplayer.NewPlayer import net.newpipe.newplayer.NewPlayer
import net.newpipe.newplayer.RepeatMode
import net.newpipe.newplayer.ui.ContentScale import net.newpipe.newplayer.ui.ContentScale
open class VideoPlayerViewModelDummy : VideoPlayerViewModel { open class VideoPlayerViewModelDummy : VideoPlayerViewModel {
@ -91,12 +92,12 @@ open class VideoPlayerViewModelDummy : VideoPlayerViewModel {
println("dummy impl stream selected: $streamId") println("dummy impl stream selected: $streamId")
} }
override fun setRepeatmode(repeatMode: Int) { override fun cycleRepeatmode() {
println("dummy impl repeat mode: $repeatMode") println("dummy impl")
} }
override fun setSuffleEnabled(enabled: Boolean) { override fun toggleShuffle() {
println("dummy impl shuffle enabled: $enabled") println("dummy impl")
} }
override fun onStorePlaylist() { override fun onStorePlaylist() {

View File

@ -46,6 +46,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.media3.common.Player import androidx.media3.common.Player
import net.newpipe.newplayer.NewPlayerException import net.newpipe.newplayer.NewPlayerException
import net.newpipe.newplayer.R import net.newpipe.newplayer.R
import net.newpipe.newplayer.RepeatMode
import net.newpipe.newplayer.model.VideoPlayerUIState import net.newpipe.newplayer.model.VideoPlayerUIState
import net.newpipe.newplayer.model.VideoPlayerViewModel import net.newpipe.newplayer.model.VideoPlayerViewModel
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
@ -75,41 +76,28 @@ fun StreamSelectTopBar(
) )
}, actions = { }, actions = {
IconButton( IconButton(
onClick = { onClick = viewModel::cycleRepeatmode
viewModel.setRepeatmode(
when (uiState.repeatMode) {
Player.REPEAT_MODE_OFF -> Player.REPEAT_MODE_ALL
Player.REPEAT_MODE_ALL -> Player.REPEAT_MODE_ONE
Player.REPEAT_MODE_ONE -> Player.REPEAT_MODE_OFF
else -> throw NewPlayerException("Unknown repeat mode: ${uiState.repeatMode}")
}
)
}
) { ) {
when (uiState.repeatMode) { when (uiState.repeatMode) {
Player.REPEAT_MODE_OFF -> Icon( RepeatMode.DONT_REPEAT -> Icon(
imageVector = Icons.Filled.Repeat, imageVector = Icons.Filled.Repeat,
contentDescription = stringResource(R.string.repeat_mode_no_repeat) contentDescription = stringResource(R.string.repeat_mode_no_repeat)
) )
Player.REPEAT_MODE_ALL -> Icon( RepeatMode.REPEAT_ALL -> Icon(
imageVector = Icons.Filled.RepeatOn, imageVector = Icons.Filled.RepeatOn,
contentDescription = stringResource(R.string.repeat_mode_repeat_all) contentDescription = stringResource(R.string.repeat_mode_repeat_all)
) )
Player.REPEAT_MODE_ONE -> Icon( RepeatMode.REPEAT_ONE -> Icon(
imageVector = Icons.Filled.RepeatOneOn, imageVector = Icons.Filled.RepeatOneOn,
contentDescription = stringResource(R.string.repeat_mode_repeat_all) contentDescription = stringResource(R.string.repeat_mode_repeat_all)
) )
else -> throw NewPlayerException("Unknown repeat mode: ${uiState.repeatMode}")
} }
} }
IconButton( IconButton(
onClick = { onClick = viewModel::toggleShuffle
viewModel.setSuffleEnabled(!uiState.shuffleEnabled)
}
) { ) {
if (uiState.shuffleEnabled) { if (uiState.shuffleEnabled) {
Icon( Icon(