mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-11-08 16:28:36 +01:00
Play or shuffle series, season, collections, & playlists from context menu (#1544)
## Description Adds options to the context menu to play or shuffle items in a series, season, collection, or playlist. So you can long click a TV show and play it directly. Playing a TV show will play the next up episode (same as the play button on the series detail page). Playing a season, collection, or playlist will start from the beginning. Also, removes the green play arrows and uses the same neutral color as other icons. ### Related issues Closes #1451 Closes #1507 ### Testing Emulator from library pages & series detail pages ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
f7f0ea9cca
commit
38b4a8c4de
10 changed files with 107 additions and 233 deletions
|
|
@ -23,6 +23,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.jellyfin.sdk.api.client.ApiClient
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
import org.jellyfin.sdk.api.client.extensions.playlistsApi
|
import org.jellyfin.sdk.api.client.extensions.playlistsApi
|
||||||
|
import org.jellyfin.sdk.api.client.extensions.tvShowsApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.videosApi
|
import org.jellyfin.sdk.api.client.extensions.videosApi
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
|
|
@ -202,28 +203,72 @@ class PlaylistCreator
|
||||||
BaseItemKind.SEASON -> {
|
BaseItemKind.SEASON -> {
|
||||||
val seriesId = item.seriesId
|
val seriesId = item.seriesId
|
||||||
if (seriesId != null) {
|
if (seriesId != null) {
|
||||||
PlaylistCreationResult.Success(
|
if (shuffled) {
|
||||||
createFromEpisode(
|
api.tvShowsApi
|
||||||
seriesId = seriesId,
|
.getEpisodes(
|
||||||
seasonId = item.id,
|
seriesId = seriesId,
|
||||||
episodeId = null,
|
seasonId = item.id,
|
||||||
shuffled = shuffled,
|
limit = Playlist.MAX_SIZE,
|
||||||
),
|
sortBy = ItemSortBy.RANDOM,
|
||||||
)
|
fields = DefaultItemFields,
|
||||||
|
).content.items
|
||||||
|
.convertAndAddParts()
|
||||||
|
.let {
|
||||||
|
PlaylistCreationResult.Success(Playlist(it))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PlaylistCreationResult.Success(
|
||||||
|
createFromEpisode(
|
||||||
|
seriesId = seriesId,
|
||||||
|
seasonId = item.id,
|
||||||
|
episodeId = null,
|
||||||
|
shuffled = shuffled,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PlaylistCreationResult.Error(null, "Episode has no seriesId")
|
PlaylistCreationResult.Error(null, "Episode has no seriesId")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseItemKind.SERIES -> {
|
BaseItemKind.SERIES -> {
|
||||||
PlaylistCreationResult.Success(
|
if (shuffled) {
|
||||||
createFromEpisode(
|
api.tvShowsApi
|
||||||
seriesId = item.id,
|
.getEpisodes(
|
||||||
seasonId = null,
|
seriesId = item.id,
|
||||||
episodeId = null,
|
limit = Playlist.MAX_SIZE,
|
||||||
shuffled = shuffled,
|
sortBy = ItemSortBy.RANDOM,
|
||||||
),
|
fields = DefaultItemFields,
|
||||||
)
|
).content.items
|
||||||
|
.convertAndAddParts()
|
||||||
|
.let {
|
||||||
|
PlaylistCreationResult.Success(Playlist(it))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val result by api.tvShowsApi.getNextUp(seriesId = item.id)
|
||||||
|
val nextUp =
|
||||||
|
result.items.firstOrNull() ?: api.tvShowsApi
|
||||||
|
.getEpisodes(
|
||||||
|
item.id,
|
||||||
|
limit = 1,
|
||||||
|
).content.items
|
||||||
|
.firstOrNull()
|
||||||
|
if (nextUp != null) {
|
||||||
|
PlaylistCreationResult.Success(
|
||||||
|
createFromEpisode(
|
||||||
|
seriesId = item.id,
|
||||||
|
seasonId = null,
|
||||||
|
episodeId = nextUp.id,
|
||||||
|
shuffled = shuffled,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
PlaylistCreationResult.Error(
|
||||||
|
null,
|
||||||
|
"Could not determine next up episode for series: " + item.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseItemKind.PLAYLIST -> {
|
BaseItemKind.PLAYLIST -> {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import com.github.damontecres.wholphin.preferences.PlayerBackend
|
||||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
import com.github.damontecres.wholphin.util.supportedPlayableTypes
|
import com.github.damontecres.wholphin.util.supportedPlayableTypes
|
||||||
|
import com.github.damontecres.wholphin.util.supportedShufflableTypes
|
||||||
import org.jellyfin.sdk.model.UUID
|
import org.jellyfin.sdk.model.UUID
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
|
|
@ -355,7 +356,6 @@ private fun buildContextMenuItems(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
resources.getString(R.string.resume),
|
resources.getString(R.string.resume),
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
dismissOnClick = true,
|
dismissOnClick = true,
|
||||||
) {
|
) {
|
||||||
actions.navigateTo(
|
actions.navigateTo(
|
||||||
|
|
@ -385,7 +385,6 @@ private fun buildContextMenuItems(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
resources.getString(R.string.play),
|
resources.getString(R.string.play),
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
dismissOnClick = true,
|
dismissOnClick = true,
|
||||||
) {
|
) {
|
||||||
actions.navigateTo(
|
actions.navigateTo(
|
||||||
|
|
@ -398,6 +397,22 @@ private fun buildContextMenuItems(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (item.type in supportedShufflableTypes) {
|
||||||
|
add(
|
||||||
|
DialogItem(
|
||||||
|
resources.getString(R.string.shuffle),
|
||||||
|
R.string.fa_shuffle,
|
||||||
|
dismissOnClick = true,
|
||||||
|
) {
|
||||||
|
actions.navigateTo(
|
||||||
|
Destination.PlaybackList(
|
||||||
|
itemId = item.id,
|
||||||
|
shuffle = true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
if (showStreamChoices) {
|
if (showStreamChoices) {
|
||||||
item.data.mediaSources?.letNotEmpty { sources ->
|
item.data.mediaSources?.letNotEmpty { sources ->
|
||||||
val source =
|
val source =
|
||||||
|
|
@ -734,7 +749,6 @@ fun buildContextForMusic(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
resources.getString(R.string.play),
|
resources.getString(R.string.play),
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
dismissOnClick = true,
|
dismissOnClick = true,
|
||||||
) {
|
) {
|
||||||
actions.onClickPlay(index, item)
|
actions.onClickPlay(index, item)
|
||||||
|
|
@ -744,7 +758,6 @@ fun buildContextForMusic(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
resources.getString(R.string.play_next),
|
resources.getString(R.string.play_next),
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
dismissOnClick = true,
|
dismissOnClick = true,
|
||||||
) {
|
) {
|
||||||
actions.onClickPlayNext(index, item)
|
actions.onClickPlayNext(index, item)
|
||||||
|
|
@ -867,7 +880,6 @@ fun buildContextForMusicQueue(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
resources.getString(R.string.play),
|
resources.getString(R.string.play),
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
dismissOnClick = true,
|
dismissOnClick = true,
|
||||||
) {
|
) {
|
||||||
actions.onClickPlay(index, item)
|
actions.onClickPlay(index, item)
|
||||||
|
|
@ -877,7 +889,6 @@ fun buildContextForMusicQueue(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
resources.getString(R.string.play_next),
|
resources.getString(R.string.play_next),
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
dismissOnClick = true,
|
dismissOnClick = true,
|
||||||
) {
|
) {
|
||||||
actions.onClickPlayNext(index, item)
|
actions.onClickPlayNext(index, item)
|
||||||
|
|
|
||||||
|
|
@ -1,193 +0,0 @@
|
||||||
package com.github.damontecres.wholphin.ui.detail
|
|
||||||
|
|
||||||
import android.content.res.Resources
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowForward
|
|
||||||
import androidx.compose.material.icons.filled.Add
|
|
||||||
import androidx.compose.material.icons.filled.ArrowForward
|
|
||||||
import androidx.compose.material.icons.filled.Delete
|
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import com.github.damontecres.wholphin.R
|
|
||||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
|
||||||
import com.github.damontecres.wholphin.ui.components.DialogItem
|
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
|
||||||
import com.github.damontecres.wholphin.util.supportedPlayableTypes
|
|
||||||
import org.jellyfin.sdk.model.UUID
|
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
|
||||||
import kotlin.time.Duration
|
|
||||||
import kotlin.time.Duration.Companion.seconds
|
|
||||||
|
|
||||||
data class MoreDialogActions(
|
|
||||||
val navigateTo: (Destination) -> Unit,
|
|
||||||
val onClickWatch: (UUID, Boolean) -> Unit,
|
|
||||||
val onClickFavorite: (UUID, Boolean) -> Unit,
|
|
||||||
val onClickAddPlaylist: (UUID) -> Unit,
|
|
||||||
val onSendMediaInfo: (UUID) -> Unit,
|
|
||||||
val onClickDelete: (BaseItem) -> Unit,
|
|
||||||
val onClickGoTo: (BaseItem) -> Unit = { navigateTo(it.destination()) },
|
|
||||||
val onClickRemoveFromNextUp: (BaseItem) -> Unit = {},
|
|
||||||
val onClickAddToQueue: (BaseItem) -> Unit = {},
|
|
||||||
)
|
|
||||||
|
|
||||||
fun buildMoreDialogItemsForHome(
|
|
||||||
resources: Resources,
|
|
||||||
item: BaseItem,
|
|
||||||
seriesId: UUID?,
|
|
||||||
playbackPosition: Duration,
|
|
||||||
watched: Boolean,
|
|
||||||
favorite: Boolean,
|
|
||||||
canDelete: Boolean,
|
|
||||||
actions: MoreDialogActions,
|
|
||||||
canRemoveContinueWatching: Boolean = false,
|
|
||||||
canRemoveNextUp: Boolean = false,
|
|
||||||
): List<DialogItem> =
|
|
||||||
buildList {
|
|
||||||
val itemId = item.id
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
resources.getString(R.string.go_to),
|
|
||||||
Icons.Default.ArrowForward,
|
|
||||||
) {
|
|
||||||
actions.onClickGoTo(item)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if (item.type in supportedPlayableTypes) {
|
|
||||||
if (playbackPosition >= 1.seconds) {
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
resources.getString(R.string.resume),
|
|
||||||
Icons.Default.PlayArrow,
|
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
) {
|
|
||||||
actions.navigateTo(
|
|
||||||
Destination.Playback(
|
|
||||||
itemId,
|
|
||||||
playbackPosition.inWholeMilliseconds,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
resources.getString(R.string.restart),
|
|
||||||
Icons.Default.Refresh,
|
|
||||||
// iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
) {
|
|
||||||
actions.navigateTo(
|
|
||||||
Destination.Playback(
|
|
||||||
itemId,
|
|
||||||
0L,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
resources.getString(R.string.play),
|
|
||||||
Icons.Default.PlayArrow,
|
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
) {
|
|
||||||
actions.navigateTo(
|
|
||||||
Destination.Playback(
|
|
||||||
itemId,
|
|
||||||
0L,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (item.type == BaseItemKind.MUSIC_ALBUM) {
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
resources.getString(R.string.add_to_queue),
|
|
||||||
Icons.Default.Add,
|
|
||||||
) {
|
|
||||||
actions.onClickAddToQueue(item)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
text = R.string.add_to_playlist,
|
|
||||||
iconStringRes = R.string.fa_list_ul,
|
|
||||||
) {
|
|
||||||
actions.onClickAddPlaylist.invoke(itemId)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if (canDelete) {
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
resources.getString(R.string.delete),
|
|
||||||
Icons.Default.Delete,
|
|
||||||
iconColor = Color.Red.copy(alpha = .8f),
|
|
||||||
) {
|
|
||||||
actions.onClickDelete.invoke(item)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (canRemoveContinueWatching && !watched && playbackPosition > Duration.ZERO) {
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
text = R.string.remove_continue_watching,
|
|
||||||
iconStringRes = R.string.fa_eye,
|
|
||||||
) {
|
|
||||||
actions.onClickWatch.invoke(itemId, false)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (canRemoveNextUp && item.type == BaseItemKind.EPISODE && item.data.seriesId != null) {
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
text = R.string.remove_next_up,
|
|
||||||
iconStringRes = R.string.fa_tag,
|
|
||||||
) {
|
|
||||||
actions.onClickRemoveFromNextUp.invoke(item)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
text = if (watched) R.string.mark_unwatched else R.string.mark_watched,
|
|
||||||
iconStringRes = if (watched) R.string.fa_eye else R.string.fa_eye_slash,
|
|
||||||
) {
|
|
||||||
actions.onClickWatch.invoke(itemId, !watched)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
text = if (favorite) R.string.remove_favorite else R.string.add_favorite,
|
|
||||||
iconStringRes = R.string.fa_heart,
|
|
||||||
iconColor = if (favorite) Color.Red else Color.Unspecified,
|
|
||||||
) {
|
|
||||||
actions.onClickFavorite.invoke(itemId, !favorite)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
seriesId?.let {
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
resources.getString(R.string.go_to_series),
|
|
||||||
Icons.AutoMirrored.Filled.ArrowForward,
|
|
||||||
) {
|
|
||||||
actions.navigateTo(
|
|
||||||
Destination.MediaItem(
|
|
||||||
it,
|
|
||||||
BaseItemKind.SERIES,
|
|
||||||
null,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
add(
|
|
||||||
DialogItem(
|
|
||||||
text = R.string.send_media_info_log_to_server,
|
|
||||||
iconStringRes = R.string.fa_file_video,
|
|
||||||
) {
|
|
||||||
actions.onSendMediaInfo.invoke(itemId)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -27,7 +27,6 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -113,7 +112,6 @@ fun PlaylistList(
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Add,
|
imageVector = Icons.Default.Add,
|
||||||
tint = Color.Green.copy(.7f),
|
|
||||||
contentDescription = "Add",
|
contentDescription = "Add",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalResources
|
import androidx.compose.ui.platform.LocalResources
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -518,7 +517,6 @@ fun buildDialogForSeason(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
resources.getString(R.string.play),
|
resources.getString(R.string.play),
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
) {
|
) {
|
||||||
onClickPlay.invoke(false)
|
onClickPlay.invoke(false)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,6 @@ fun ProgramDialog(
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.PlayArrow,
|
imageVector = Icons.Default.PlayArrow,
|
||||||
contentDescription = stringResource(R.string.delete),
|
contentDescription = stringResource(R.string.delete),
|
||||||
tint = Color.Green.copy(alpha = .75f),
|
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.watch_live),
|
text = stringResource(R.string.watch_live),
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,6 @@ fun TvGuideGrid(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
watchLiveStr,
|
watchLiveStr,
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
dismissOnClick = true,
|
dismissOnClick = true,
|
||||||
) {
|
) {
|
||||||
viewModel.navigationManager.navigateTo(
|
viewModel.navigationManager.navigateTo(
|
||||||
|
|
|
||||||
|
|
@ -742,7 +742,6 @@ fun buildDialogForSeason(
|
||||||
DialogItem(
|
DialogItem(
|
||||||
resources.getString(R.string.play),
|
resources.getString(R.string.play),
|
||||||
Icons.Default.PlayArrow,
|
Icons.Default.PlayArrow,
|
||||||
iconColor = Color.Green.copy(alpha = .8f),
|
|
||||||
) {
|
) {
|
||||||
onClickPlay.invoke(false)
|
onClickPlay.invoke(false)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -315,16 +315,24 @@ class PlaybackViewModel
|
||||||
val playlistItem =
|
val playlistItem =
|
||||||
if (queriedItem.type.playable) {
|
if (queriedItem.type.playable) {
|
||||||
PlaylistItem.Media(BaseItem(queriedItem, false))
|
PlaylistItem.Media(BaseItem(queriedItem, false))
|
||||||
} else if (destination is Destination.PlaybackList) {
|
} else {
|
||||||
val playlistResult =
|
val playlistResult =
|
||||||
playlistCreator.createFrom(
|
if (destination is Destination.PlaybackList) {
|
||||||
item = queriedItem,
|
playlistCreator.createFrom(
|
||||||
startIndex = destination.startIndex ?: 0,
|
item = queriedItem,
|
||||||
sortAndDirection = destination.sortAndDirection,
|
startIndex = destination.startIndex ?: 0,
|
||||||
shuffled = destination.shuffle,
|
sortAndDirection = destination.sortAndDirection,
|
||||||
recursive = destination.recursive,
|
shuffled = destination.shuffle,
|
||||||
filter = destination.filter,
|
recursive = destination.recursive,
|
||||||
)
|
filter = destination.filter,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Try to create a playlist
|
||||||
|
playlistCreator.createFrom(
|
||||||
|
item = queriedItem,
|
||||||
|
recursive = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
when (val r = playlistResult) {
|
when (val r = playlistResult) {
|
||||||
is PlaylistCreationResult.Error -> {
|
is PlaylistCreationResult.Error -> {
|
||||||
_state.update { it.copy(loading = LoadingState.Error(r.message, r.ex)) }
|
_state.update { it.copy(loading = LoadingState.Error(r.message, r.ex)) }
|
||||||
|
|
@ -343,8 +351,6 @@ class PlaybackViewModel
|
||||||
r.playlist.items.first()
|
r.playlist.items.first()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
throw IllegalArgumentException("Item is not playable and not PlaybackList: ${queriedItem.type}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModelScope.launch(ExceptionHandler()) { controllerViewState.observe() }
|
viewModelScope.launch(ExceptionHandler()) { controllerViewState.observe() }
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,16 @@ val supportedPlayableTypes =
|
||||||
BaseItemKind.TV_CHANNEL,
|
BaseItemKind.TV_CHANNEL,
|
||||||
BaseItemKind.TV_PROGRAM,
|
BaseItemKind.TV_PROGRAM,
|
||||||
BaseItemKind.RECORDING,
|
BaseItemKind.RECORDING,
|
||||||
|
BaseItemKind.SEASON,
|
||||||
|
BaseItemKind.SERIES,
|
||||||
|
BaseItemKind.BOX_SET,
|
||||||
|
BaseItemKind.PLAYLIST,
|
||||||
|
)
|
||||||
|
|
||||||
|
val supportedShufflableTypes =
|
||||||
|
setOf(
|
||||||
|
BaseItemKind.SEASON,
|
||||||
|
BaseItemKind.SERIES,
|
||||||
|
BaseItemKind.BOX_SET,
|
||||||
|
BaseItemKind.PLAYLIST,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue