handle currently plaing and show title and creator
This commit is contained in:
parent
d97ecc7519
commit
a47ea8e078
|
@ -40,8 +40,8 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import net.newpipe.newplayer.playerInternals.PlaylistItem
|
import net.newpipe.newplayer.playerInternals.PlaylistItem
|
||||||
|
import net.newpipe.newplayer.playerInternals.fetchPlaylistItem
|
||||||
import net.newpipe.newplayer.playerInternals.getPlaylistItemsFromExoplayer
|
import net.newpipe.newplayer.playerInternals.getPlaylistItemsFromExoplayer
|
||||||
import net.newpipe.newplayer.utils.Thumbnail
|
|
||||||
import kotlin.Exception
|
import kotlin.Exception
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
@ -72,12 +72,12 @@ interface NewPlayer {
|
||||||
val sharingLinkWithOffsetPossible: Boolean
|
val sharingLinkWithOffsetPossible: Boolean
|
||||||
var currentPosition: Long
|
var currentPosition: Long
|
||||||
var fastSeekAmountSec: Int
|
var fastSeekAmountSec: Int
|
||||||
var playBackMode: PlayMode
|
val playBackMode: MutableStateFlow<PlayMode?>
|
||||||
var playMode: StateFlow<PlayMode?>
|
|
||||||
var shuffle: Boolean
|
var shuffle: Boolean
|
||||||
var repeatMode: RepeatMode
|
var repeatMode: RepeatMode
|
||||||
|
|
||||||
val playlist: StateFlow<List<PlaylistItem>>
|
val playlist: StateFlow<List<PlaylistItem>>
|
||||||
|
val currentlyPlaying: StateFlow<PlaylistItem?>
|
||||||
|
|
||||||
// callbacks
|
// callbacks
|
||||||
|
|
||||||
|
@ -93,7 +93,6 @@ interface NewPlayer {
|
||||||
fun removePlaylistItem(index: Int)
|
fun removePlaylistItem(index: Int)
|
||||||
fun playStream(item: String, playMode: PlayMode)
|
fun playStream(item: String, playMode: PlayMode)
|
||||||
fun playStream(item: String, streamVariant: String, playMode: PlayMode)
|
fun playStream(item: String, streamVariant: String, playMode: PlayMode)
|
||||||
fun setPlayMode(playMode: PlayMode)
|
|
||||||
|
|
||||||
data class Builder(val app: Application, val repository: MediaRepository) {
|
data class Builder(val app: Application, val repository: MediaRepository) {
|
||||||
private var mediaSourceFactory: MediaSource.Factory? = null
|
private var mediaSourceFactory: MediaSource.Factory? = null
|
||||||
|
@ -155,12 +154,10 @@ class NewPlayerImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override var fastSeekAmountSec: Int = 10
|
override var fastSeekAmountSec: Int = 10
|
||||||
override var playBackMode: PlayMode = PlayMode.EMBEDDED_VIDEO
|
|
||||||
|
|
||||||
private var playerScope = CoroutineScope(Dispatchers.Main + Job())
|
private var playerScope = CoroutineScope(Dispatchers.Main + Job())
|
||||||
|
|
||||||
var mutablePlayMode = MutableStateFlow<PlayMode?>(null)
|
override var playBackMode = MutableStateFlow<PlayMode?>(null)
|
||||||
override var playMode = mutablePlayMode.asStateFlow()
|
|
||||||
|
|
||||||
override var shuffle: Boolean
|
override var shuffle: Boolean
|
||||||
get() = internalPlayer.shuffleModeEnabled
|
get() = internalPlayer.shuffleModeEnabled
|
||||||
|
@ -169,21 +166,21 @@ class NewPlayerImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override var repeatMode: RepeatMode
|
override var repeatMode: RepeatMode
|
||||||
get() = when(internalPlayer.repeatMode) {
|
get() = when (internalPlayer.repeatMode) {
|
||||||
Player.REPEAT_MODE_OFF -> RepeatMode.DONT_REPEAT
|
Player.REPEAT_MODE_OFF -> RepeatMode.DONT_REPEAT
|
||||||
Player.REPEAT_MODE_ALL -> RepeatMode.REPEAT_ALL
|
Player.REPEAT_MODE_ALL -> RepeatMode.REPEAT_ALL
|
||||||
Player.REPEAT_MODE_ONE -> RepeatMode.REPEAT_ONE
|
Player.REPEAT_MODE_ONE -> RepeatMode.REPEAT_ONE
|
||||||
else -> throw NewPlayerException("Unknown Repeatmode option returned by ExoPlayer: ${internalPlayer.repeatMode}")
|
else -> throw NewPlayerException("Unknown Repeatmode option returned by ExoPlayer: ${internalPlayer.repeatMode}")
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
when(value) {
|
when (value) {
|
||||||
RepeatMode.DONT_REPEAT -> internalPlayer.repeatMode = Player.REPEAT_MODE_OFF
|
RepeatMode.DONT_REPEAT -> internalPlayer.repeatMode = Player.REPEAT_MODE_OFF
|
||||||
RepeatMode.REPEAT_ALL -> internalPlayer.repeatMode = Player.REPEAT_MODE_ALL
|
RepeatMode.REPEAT_ALL -> internalPlayer.repeatMode = Player.REPEAT_MODE_ALL
|
||||||
RepeatMode.REPEAT_ONE -> internalPlayer.repeatMode = Player.REPEAT_MODE_ONE
|
RepeatMode.REPEAT_ONE -> internalPlayer.repeatMode = Player.REPEAT_MODE_ONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var mutableOnEvent = MutableSharedFlow<Pair<Player, Player.Events>>()
|
private 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()
|
||||||
|
|
||||||
|
@ -197,10 +194,13 @@ class NewPlayerImpl(
|
||||||
override val duration: Long
|
override val duration: Long
|
||||||
get() = internalPlayer.duration
|
get() = internalPlayer.duration
|
||||||
|
|
||||||
val mutablePlaylist = MutableStateFlow<List<PlaylistItem>>(emptyList())
|
private val mutablePlaylist = MutableStateFlow<List<PlaylistItem>>(emptyList())
|
||||||
override val playlist: StateFlow<List<PlaylistItem>> =
|
override val playlist: StateFlow<List<PlaylistItem>> =
|
||||||
mutablePlaylist.asStateFlow()
|
mutablePlaylist.asStateFlow()
|
||||||
|
|
||||||
|
private val mutableCurrentlyPlaying = MutableStateFlow<PlaylistItem?>(null)
|
||||||
|
override val currentlyPlaying: StateFlow<PlaylistItem?> = mutableCurrentlyPlaying.asStateFlow()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
println("gurken init")
|
println("gurken init")
|
||||||
internalPlayer.addListener(object : Player.Listener {
|
internalPlayer.addListener(object : Player.Listener {
|
||||||
|
@ -227,12 +227,37 @@ class NewPlayerImpl(
|
||||||
super.onTimelineChanged(timeline, reason)
|
super.onTimelineChanged(timeline, reason)
|
||||||
updatePlaylistItems()
|
updatePlaylistItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||||
|
super.onMediaItemTransition(mediaItem, reason)
|
||||||
|
mediaItem?.let {
|
||||||
|
val playlistItem = getPlaylistItem(mediaItem.mediaId.toLong())
|
||||||
|
if (playlistItem != null) {
|
||||||
|
mutableCurrentlyPlaying.update {
|
||||||
|
playlistItem
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
launchJobAndCollectError {
|
||||||
|
val item = fetchPlaylistItem(
|
||||||
|
uniqueId = mediaItem.mediaId.toLong(),
|
||||||
|
mediaRepo = repository,
|
||||||
|
idLookupTable = uniqueIdToIdLookup
|
||||||
|
)
|
||||||
|
mutableCurrentlyPlaying.update { item }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePlaylistItems() {
|
private fun updatePlaylistItems() {
|
||||||
playerScope.launch {
|
playerScope.launch {
|
||||||
val playlist = getPlaylistItemsFromExoplayer(internalPlayer, repository, uniqueIdToIdLookup)
|
val playlist =
|
||||||
|
getPlaylistItemsFromExoplayer(internalPlayer, repository, uniqueIdToIdLookup)
|
||||||
var playlistDuration = 0
|
var playlistDuration = 0
|
||||||
for (item in playlist) {
|
for (item in playlist) {
|
||||||
playlistDuration += item.lengthInS
|
playlistDuration += item.lengthInS
|
||||||
|
@ -244,6 +269,15 @@ class NewPlayerImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getPlaylistItem(uniqueId: Long): PlaylistItem? {
|
||||||
|
for (item in playlist.value) {
|
||||||
|
if (item.uniqueId == uniqueId) {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
override fun prepare() {
|
override fun prepare() {
|
||||||
internalPlayer.prepare()
|
internalPlayer.prepare()
|
||||||
}
|
}
|
||||||
|
@ -289,15 +323,12 @@ class NewPlayerImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setPlayMode(playMode: PlayMode) {
|
|
||||||
this.mutablePlayMode.update { playMode }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun internalPlayStream(mediaItem: MediaItem, playMode: PlayMode) {
|
private fun internalPlayStream(mediaItem: MediaItem, playMode: PlayMode) {
|
||||||
if (internalPlayer.playbackState == Player.STATE_IDLE) {
|
if (internalPlayer.playbackState == Player.STATE_IDLE) {
|
||||||
internalPlayer.prepare()
|
internalPlayer.prepare()
|
||||||
}
|
}
|
||||||
this.mutablePlayMode.update { playMode }
|
this.playBackMode.update { playMode }
|
||||||
this.internalPlayer.setMediaItem(mediaItem)
|
this.internalPlayer.setMediaItem(mediaItem)
|
||||||
this.internalPlayer.play()
|
this.internalPlayer.play()
|
||||||
}
|
}
|
||||||
|
@ -305,7 +336,7 @@ class NewPlayerImpl(
|
||||||
private suspend fun toMediaItem(item: String, streamVariant: String): MediaItem {
|
private suspend fun toMediaItem(item: String, streamVariant: String): MediaItem {
|
||||||
val dataStream = repository.getStream(item, streamVariant)
|
val dataStream = repository.getStream(item, streamVariant)
|
||||||
val uniqueId = Random.nextLong()
|
val uniqueId = Random.nextLong()
|
||||||
uniqueIdToIdLookup.set(uniqueId, item)
|
uniqueIdToIdLookup[uniqueId] = item
|
||||||
val mediaItem = MediaItem.Builder().setMediaId(uniqueId.toString()).setUri(dataStream)
|
val mediaItem = MediaItem.Builder().setMediaId(uniqueId.toString()).setUri(dataStream)
|
||||||
return mediaItem.build()
|
return mediaItem.build()
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
package net.newpipe.newplayer.model
|
package net.newpipe.newplayer.model
|
||||||
|
|
||||||
import androidx.media3.common.Player
|
|
||||||
import net.newpipe.newplayer.Chapter
|
import net.newpipe.newplayer.Chapter
|
||||||
import net.newpipe.newplayer.RepeatMode
|
import net.newpipe.newplayer.RepeatMode
|
||||||
import net.newpipe.newplayer.playerInternals.PlaylistItem
|
import net.newpipe.newplayer.playerInternals.PlaylistItem
|
||||||
|
@ -45,14 +44,12 @@ data class VideoPlayerUIState(
|
||||||
val chapters: List<Chapter>,
|
val chapters: List<Chapter>,
|
||||||
val shuffleEnabled: Boolean,
|
val shuffleEnabled: Boolean,
|
||||||
val repeatMode: RepeatMode,
|
val repeatMode: RepeatMode,
|
||||||
val playListDurationInS: Int
|
val playListDurationInS: Int,
|
||||||
|
val currentlyPlaying: PlaylistItem
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val DEFAULT = VideoPlayerUIState(
|
val DEFAULT = VideoPlayerUIState(
|
||||||
// TODO: replace this with the placeholder state.
|
|
||||||
// The actual initial state upon starting to play is dictated by the NewPlayer instance
|
|
||||||
uiMode = UIModeState.PLACEHOLDER,
|
uiMode = UIModeState.PLACEHOLDER,
|
||||||
//uiMode = UIModeState.PLACEHOLDER,
|
|
||||||
playing = false,
|
playing = false,
|
||||||
contentRatio = 16 / 9f,
|
contentRatio = 16 / 9f,
|
||||||
embeddedUiRatio = 16f / 9f,
|
embeddedUiRatio = 16f / 9f,
|
||||||
|
@ -70,7 +67,24 @@ data class VideoPlayerUIState(
|
||||||
chapters = emptyList(),
|
chapters = emptyList(),
|
||||||
shuffleEnabled = false,
|
shuffleEnabled = false,
|
||||||
repeatMode = RepeatMode.DONT_REPEAT,
|
repeatMode = RepeatMode.DONT_REPEAT,
|
||||||
playListDurationInS = 0
|
playListDurationInS = 0,
|
||||||
|
currentlyPlaying = PlaylistItem.DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
|
val DUMMY = DEFAULT.copy(
|
||||||
|
uiMode = UIModeState.EMBEDDED_VIDEO,
|
||||||
|
playing = true,
|
||||||
|
seekerPosition = 0.3f,
|
||||||
|
bufferedPercentage = 0.5f,
|
||||||
|
isLoading = false,
|
||||||
|
durationInMs = 420,
|
||||||
|
playbackPositionInMs = 69,
|
||||||
|
fastSeekSeconds = 10,
|
||||||
|
soundVolume = 0.5f,
|
||||||
|
brightness = 0.2f,
|
||||||
|
shuffleEnabled = true,
|
||||||
|
playListDurationInS = 5493,
|
||||||
|
currentlyPlaying = PlaylistItem.DUMMY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -67,4 +67,5 @@ interface VideoPlayerViewModel {
|
||||||
fun movePlaylistItem(from: Int, to: Int)
|
fun movePlaylistItem(from: Int, to: Int)
|
||||||
fun removePlaylistItem(index: Int)
|
fun removePlaylistItem(index: Int)
|
||||||
fun onStreamItemDragFinished()
|
fun onStreamItemDragFinished()
|
||||||
|
fun dialogVisible(visible: Boolean)
|
||||||
}
|
}
|
|
@ -40,12 +40,14 @@ import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
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.RepeatMode
|
||||||
|
import net.newpipe.newplayer.playerInternals.PlaylistItem
|
||||||
import net.newpipe.newplayer.ui.ContentScale
|
import net.newpipe.newplayer.ui.ContentScale
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
|
|
||||||
|
@ -179,7 +181,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
newPlayer?.let { newPlayer ->
|
newPlayer?.let { newPlayer ->
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
newPlayer.playMode.collect { newMode ->
|
newPlayer.playBackMode.collect { newMode ->
|
||||||
val currentMode = mutableUiState.value.uiMode.toPlayMode()
|
val currentMode = mutableUiState.value.uiMode.toPlayMode()
|
||||||
if (currentMode != newMode) {
|
if (currentMode != newMode) {
|
||||||
mutableUiState.update {
|
mutableUiState.update {
|
||||||
|
@ -196,6 +198,13 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
mutableUiState.update { it.copy(playList = playlist) }
|
mutableUiState.update { it.copy(playList = playlist) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
viewModelScope.launch {
|
||||||
|
newPlayer.currentlyPlaying.collect { playlistItem ->
|
||||||
|
mutableUiState.update {
|
||||||
|
it.copy(currentlyPlaying = playlistItem ?: PlaylistItem.DEFAULT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,6 +476,14 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
playlistItemToBeMoved = null
|
playlistItemToBeMoved = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun dialogVisible(visible: Boolean) {
|
||||||
|
if(visible) {
|
||||||
|
uiVisibilityJob?.cancel()
|
||||||
|
} else {
|
||||||
|
resetHideUiDelayedJob()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun removePlaylistItem(index: Int) {
|
override fun removePlaylistItem(index: Int) {
|
||||||
newPlayer?.removePlaylistItem(index)
|
newPlayer?.removePlaylistItem(index)
|
||||||
}
|
}
|
||||||
|
@ -476,7 +493,9 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
val newPlayMode = newState.toPlayMode()
|
val newPlayMode = newState.toPlayMode()
|
||||||
val currentPlayMode = mutableUiState.value.uiMode.toPlayMode()
|
val currentPlayMode = mutableUiState.value.uiMode.toPlayMode()
|
||||||
if (newPlayMode != currentPlayMode) {
|
if (newPlayMode != currentPlayMode) {
|
||||||
newPlayer?.setPlayMode(newPlayMode!!)
|
newPlayer?.playBackMode?.update {
|
||||||
|
newPlayMode!!
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mutableUiState.update {
|
mutableUiState.update {
|
||||||
it.copy(uiMode = newState)
|
it.copy(uiMode = newState)
|
||||||
|
|
|
@ -116,6 +116,10 @@ open class VideoPlayerViewModelDummy : VideoPlayerViewModel {
|
||||||
println("dummy impl")
|
println("dummy impl")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun dialogVisible(visible: Boolean) {
|
||||||
|
println("dummy impl dialog visible: $visible")
|
||||||
|
}
|
||||||
|
|
||||||
override fun pause() {
|
override fun pause() {
|
||||||
println("dummy pause")
|
println("dummy pause")
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
package net.newpipe.newplayer.playerInternals
|
package net.newpipe.newplayer.playerInternals
|
||||||
|
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
|
@ -37,12 +38,55 @@ data class PlaylistItem(
|
||||||
val uniqueId: Long,
|
val uniqueId: Long,
|
||||||
val thumbnail: Thumbnail?,
|
val thumbnail: Thumbnail?,
|
||||||
val lengthInS: Int
|
val lengthInS: Int
|
||||||
)
|
) {
|
||||||
|
companion object {
|
||||||
|
val DEFAULT = PlaylistItem(
|
||||||
|
title = "",
|
||||||
|
creator = "",
|
||||||
|
id = "",
|
||||||
|
uniqueId = -1L,
|
||||||
|
thumbnail = null,
|
||||||
|
lengthInS = 0
|
||||||
|
)
|
||||||
|
|
||||||
suspend fun getPlaylistItemsFromExoplayer(player: Player, mediaRepo: MediaRepository, idLookupTable: HashMap<Long, String>) =
|
val DUMMY = PlaylistItem(
|
||||||
|
title = "Superawesome Video",
|
||||||
|
creator = "Yours truely",
|
||||||
|
id = "some_id",
|
||||||
|
uniqueId = 12345L,
|
||||||
|
thumbnail = null,
|
||||||
|
lengthInS = 420
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun fetchPlaylistItem(
|
||||||
|
uniqueId: Long,
|
||||||
|
mediaRepo: MediaRepository,
|
||||||
|
idLookupTable: HashMap<Long, String>
|
||||||
|
) : PlaylistItem {
|
||||||
|
val id = idLookupTable[uniqueId]
|
||||||
|
?: throw NewPlayerException("Unknown uniqueId: $uniqueId, uniqueId Id mapping error. Something went wrong during datafetching.")
|
||||||
|
val metaInfo = mediaRepo.getMetaInfo(id)
|
||||||
|
|
||||||
|
return PlaylistItem(
|
||||||
|
title = metaInfo.title,
|
||||||
|
creator = metaInfo.channelName,
|
||||||
|
id = id,
|
||||||
|
thumbnail = metaInfo.thumbnail,
|
||||||
|
lengthInS = metaInfo.lengthInS,
|
||||||
|
uniqueId = uniqueId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun getPlaylistItemsFromExoplayer(
|
||||||
|
player: Player,
|
||||||
|
mediaRepo: MediaRepository,
|
||||||
|
idLookupTable: HashMap<Long, String>
|
||||||
|
) =
|
||||||
with(CoroutineScope(coroutineContext)) {
|
with(CoroutineScope(coroutineContext)) {
|
||||||
(0..player.mediaItemCount-1).map { index ->
|
(0..player.mediaItemCount - 1).map { index ->
|
||||||
println("gurken index: $index")
|
|
||||||
val mediaItem = player.getMediaItemAt(index)
|
val mediaItem = player.getMediaItemAt(index)
|
||||||
val uniqueId = mediaItem.mediaId.toLong()
|
val uniqueId = mediaItem.mediaId.toLong()
|
||||||
val id = idLookupTable.get(uniqueId)
|
val id = idLookupTable.get(uniqueId)
|
||||||
|
@ -67,9 +111,9 @@ suspend fun getPlaylistItemsFromExoplayer(player: Player, mediaRepo: MediaReposi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPlaylistDurationInS(items: List<PlaylistItem>) : Int {
|
fun getPlaylistDurationInS(items: List<PlaylistItem>): Int {
|
||||||
var duration = 0
|
var duration = 0
|
||||||
for(item in items) {
|
for (item in items) {
|
||||||
duration += item.lengthInS
|
duration += item.lengthInS
|
||||||
}
|
}
|
||||||
return duration
|
return duration
|
||||||
|
|
|
@ -126,7 +126,7 @@ fun VideoPlayerControllerBottomUIPreview() {
|
||||||
BottomUI(
|
BottomUI(
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
viewModel = VideoPlayerViewModelDummy(),
|
viewModel = VideoPlayerViewModelDummy(),
|
||||||
uiState = VideoPlayerUIState.DEFAULT.copy(
|
uiState = VideoPlayerUIState.DUMMY.copy(
|
||||||
uiMode = UIModeState.FULLSCREEN_VIDEO_CONTROLLER_UI,
|
uiMode = UIModeState.FULLSCREEN_VIDEO_CONTROLLER_UI,
|
||||||
seekerPosition = 0.4f,
|
seekerPosition = 0.4f,
|
||||||
durationInMs = 90 * 60 * 1000,
|
durationInMs = 90 * 60 * 1000,
|
||||||
|
|
|
@ -122,7 +122,7 @@ fun VideoPlayerControllerUICenterUIPreview() {
|
||||||
Surface(color = Color.Black) {
|
Surface(color = Color.Black) {
|
||||||
CenterUI(
|
CenterUI(
|
||||||
viewModel = VideoPlayerViewModelDummy(),
|
viewModel = VideoPlayerViewModelDummy(),
|
||||||
uiState = VideoPlayerUIState.DEFAULT.copy(
|
uiState = VideoPlayerUIState.DUMMY.copy(
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
playing = true
|
playing = true
|
||||||
)
|
)
|
||||||
|
|
|
@ -52,13 +52,16 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.DpOffset
|
import androidx.compose.ui.unit.DpOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import net.newpipe.newplayer.R
|
import net.newpipe.newplayer.R
|
||||||
|
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||||
|
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||||
|
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DropDownMenu() {
|
fun DropDownMenu(viewModel: VideoPlayerViewModel, uiState: VideoPlayerUIState) {
|
||||||
var showMainMenu: Boolean by remember { mutableStateOf(false) }
|
var showMainMenu: Boolean by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
var pixel_density = LocalDensity.current
|
val pixel_density = LocalDensity.current
|
||||||
|
|
||||||
var offsetY by remember {
|
var offsetY by remember {
|
||||||
mutableStateOf(0.dp)
|
mutableStateOf(0.dp)
|
||||||
|
@ -140,8 +143,8 @@ fun DropDownMenu() {
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerControllerDropDownPreview() {
|
fun VideoPlayerControllerDropDownPreview() {
|
||||||
VideoPlayerTheme {
|
VideoPlayerTheme {
|
||||||
Box(Modifier.fillMaxSize()){
|
Box(Modifier.fillMaxSize()) {
|
||||||
DropDownMenu()
|
DropDownMenu(VideoPlayerViewModelDummy(), VideoPlayerUIState.DUMMY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ fun VideoPlayerStreamSelectUIPreview() {
|
||||||
StreamSelectUI(
|
StreamSelectUI(
|
||||||
isChapterSelect = false,
|
isChapterSelect = false,
|
||||||
viewModel = VideoPlayerViewModelDummy(),
|
viewModel = VideoPlayerViewModelDummy(),
|
||||||
uiState = VideoPlayerUIState.DEFAULT.copy(
|
uiState = VideoPlayerUIState.DUMMY.copy(
|
||||||
playList = arrayListOf(
|
playList = arrayListOf(
|
||||||
PlaylistItem(
|
PlaylistItem(
|
||||||
id = "6502",
|
id = "6502",
|
||||||
|
|
|
@ -51,6 +51,7 @@ import net.newpipe.newplayer.R
|
||||||
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
|
||||||
|
import net.newpipe.newplayer.playerInternals.PlaylistItem
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.ui.theme.video_player_onSurface
|
import net.newpipe.newplayer.ui.theme.video_player_onSurface
|
||||||
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
|
@ -67,14 +68,17 @@ fun TopUI(
|
||||||
) {
|
) {
|
||||||
Column(horizontalAlignment = Alignment.Start, modifier = Modifier.weight(1F)) {
|
Column(horizontalAlignment = Alignment.Start, modifier = Modifier.weight(1F)) {
|
||||||
Text(
|
Text(
|
||||||
"The Title",
|
uiState.currentlyPlaying.title,
|
||||||
fontSize = 15.sp,
|
fontSize = 15.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
"The Channel", fontSize = 12.sp, maxLines = 1, overflow = TextOverflow.Ellipsis
|
uiState.currentlyPlaying.creator,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
|
@ -105,9 +109,14 @@ fun TopUI(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
androidx.compose.animation.AnimatedVisibility(visible = 1 < uiState.playList.size) {
|
AnimatedVisibility(visible = 1 < uiState.playList.size) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { viewModel.openStreamSelection(selectChapter = false, embeddedUiConfig) },
|
onClick = {
|
||||||
|
viewModel.openStreamSelection(
|
||||||
|
selectChapter = false,
|
||||||
|
embeddedUiConfig
|
||||||
|
)
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.AutoMirrored.Filled.List,
|
imageVector = Icons.AutoMirrored.Filled.List,
|
||||||
|
@ -115,7 +124,7 @@ fun TopUI(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DropDownMenu()
|
DropDownMenu(viewModel, uiState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +137,9 @@ fun TopUI(
|
||||||
fun VideoPlayerControllerTopUIPreview() {
|
fun VideoPlayerControllerTopUIPreview() {
|
||||||
VideoPlayerTheme {
|
VideoPlayerTheme {
|
||||||
Surface(color = Color.Black) {
|
Surface(color = Color.Black) {
|
||||||
TopUI(modifier = Modifier, VideoPlayerViewModelDummy(), VideoPlayerUIState.DEFAULT)
|
TopUI(
|
||||||
|
modifier = Modifier, VideoPlayerViewModelDummy(), VideoPlayerUIState.DUMMY
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue