Fix possible TV guide crash & update Play All libraries (#315)

- Fixes a possible crash if the server has Live TV enabled, but no
channels
- Disable Play All/Shuffle for Collections "library"
This commit is contained in:
damontecres 2025-11-24 11:40:15 -05:00 committed by GitHub
parent 6004687deb
commit 7be4fb5fdf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 156 additions and 131 deletions

View file

@ -30,7 +30,7 @@ class AddPlaylistViewModel
viewModelScope.launchIO {
this@AddPlaylistViewModel.playlistState.setValueOnMain(PlaylistLoadingState.Loading)
try {
val playlists = playlistCreator.getPlaylists(mediaType, viewModelScope)
val playlists = playlistCreator.getServerPlaylists(mediaType, viewModelScope)
this@AddPlaylistViewModel.playlistState.setValueOnMain(PlaylistLoadingState.Success(playlists))
} catch (ex: Exception) {
playlistState.setValueOnMain(PlaylistLoadingState.Error(ex))
@ -43,7 +43,7 @@ class AddPlaylistViewModel
itemId: UUID,
) {
viewModelScope.launchIO(ExceptionHandler(autoToast = true)) {
playlistCreator.addToPlaylist(playlistId, itemId)
playlistCreator.addToServerPlaylist(playlistId, itemId)
}
}
@ -52,7 +52,7 @@ class AddPlaylistViewModel
itemId: UUID,
) {
viewModelScope.launchIO(ExceptionHandler(autoToast = true)) {
val playlistId = playlistCreator.createPlaylist(playlistName, listOf(itemId))
val playlistId = playlistCreator.createServerPlaylist(playlistName, listOf(itemId))
if (playlistId == null) {
showToast(context, "Error creating playlist", Toast.LENGTH_LONG)
}

View file

@ -27,6 +27,7 @@ fun CollectionFolderBoxSet(
modifier: Modifier = Modifier,
filter: GetItemsFilter = GetItemsFilter(),
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
playEnabled: Boolean = false,
) {
var showHeader by remember { mutableStateOf(true) }
CollectionFolderGrid(
@ -44,6 +45,6 @@ fun CollectionFolderBoxSet(
showHeader = position < columns
},
params = CollectionFolderGridParameters.POSTER,
playEnabled = true,
playEnabled = playEnabled,
)
}

View file

@ -95,50 +95,57 @@ fun TvGuideGrid(
}
}
Column(modifier = modifier) {
TvGuideGridContent(
loading = state is LoadingState.Loading,
channels = channels,
programs = programs,
channelProgramCount = viewModel.channelProgramCount,
start = viewModel.guideStart,
onClickChannel = { index, channel ->
viewModel.navigationManager.navigateTo(
Destination.Playback(
itemId = channel.id,
positionMs = 0L,
),
)
},
onFocus = {
onRowPosition.invoke(it.row)
viewModel.onFocusChannel(it)
},
onClickProgram = { index, program ->
if (program.isFake) {
val now = LocalDateTime.now()
if (now.isAfter(program.start) && now.isBefore(program.end)) {
viewModel.navigationManager.navigateTo(
Destination.Playback(
itemId = program.channelId,
positionMs = 0L,
),
)
if (channels.isEmpty()) {
ErrorMessage("Live TV is enabled, but no channels were found.", null)
} else {
TvGuideGridContent(
loading = state is LoadingState.Loading,
channels = channels,
programs = programs,
channelProgramCount = viewModel.channelProgramCount,
start = viewModel.guideStart,
onClickChannel = { index, channel ->
viewModel.navigationManager.navigateTo(
Destination.Playback(
itemId = channel.id,
positionMs = 0L,
),
)
},
onFocus = {
onRowPosition.invoke(it.row)
viewModel.onFocusChannel(it)
},
onClickProgram = { index, program ->
if (program.isFake) {
val now = LocalDateTime.now()
if (now.isAfter(program.start) && now.isBefore(program.end)) {
viewModel.navigationManager.navigateTo(
Destination.Playback(
itemId = program.channelId,
positionMs = 0L,
),
)
} else {
Toast
.makeText(
context,
"No guide data found!",
Toast.LENGTH_SHORT,
).show()
}
} else {
Toast
.makeText(context, "No guide data found!", Toast.LENGTH_SHORT)
.show()
viewModel.getItem(program.id)
showItemDialog = index
}
} else {
viewModel.getItem(program.id)
showItemDialog = index
}
},
modifier =
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface)
.focusRequester(focusRequester),
)
},
modifier =
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface)
.focusRequester(focusRequester),
)
}
}
if (showItemDialog != null) {
val onDismissRequest = { showItemDialog = null }

View file

@ -103,11 +103,12 @@ fun DestinationContent(
BaseItemKind.BOX_SET ->
CollectionFolderBoxSet(
preferences,
destination.itemId,
destination.item,
false,
modifier,
preferences = preferences,
itemId = destination.itemId,
item = destination.item,
recursive = false,
playEnabled = true,
modifier = modifier,
)
BaseItemKind.PLAYLIST ->

View file

@ -37,21 +37,24 @@ val PrefContentScale.scale: ContentScale
val BaseItemKind.playable: Boolean
get() =
when (this) {
BaseItemKind.EPISODE,
BaseItemKind.MOVIE,
BaseItemKind.MUSIC_VIDEO,
BaseItemKind.TRAILER,
BaseItemKind.VIDEO,
-> true
// TODO add support for these eventually
BaseItemKind.LIVE_TV_CHANNEL,
BaseItemKind.LIVE_TV_PROGRAM,
BaseItemKind.PROGRAM,
BaseItemKind.RECORDING,
BaseItemKind.TV_CHANNEL,
BaseItemKind.TV_PROGRAM,
BaseItemKind.AUDIO_BOOK,
BaseItemKind.AUDIO,
BaseItemKind.CHANNEL,
BaseItemKind.EPISODE,
BaseItemKind.MOVIE,
BaseItemKind.LIVE_TV_CHANNEL,
BaseItemKind.LIVE_TV_PROGRAM,
BaseItemKind.MUSIC_VIDEO,
BaseItemKind.PROGRAM,
BaseItemKind.RECORDING,
BaseItemKind.TRAILER,
BaseItemKind.TV_CHANNEL,
BaseItemKind.TV_PROGRAM,
BaseItemKind.VIDEO,
-> true
-> false
BaseItemKind.AGGREGATE_FOLDER,
BaseItemKind.BASE_PLUGIN_FOLDER,