Few UI improvments & fixes (#1229)

## Description
- Add indicator to mark the chosen version on the choose version dialog
- Add an option for album's context menu to add it to the now playing
queue
- Fix how season cards refresh on the series detail page so the images
don't glitch

### Related issues
Related to #1220

### Testing
Emulator mostly

## Screenshots

The indicator shows which version will play, whether explicitly chosen
by the user or implicitly picked by Wholphin.
![choose_version_indicator
Large](https://github.com/user-attachments/assets/7440ee1a-b9eb-4b34-ac39-86206c2eca09)

## AI or LLM usage
None
This commit is contained in:
Ray 2026-04-10 14:56:43 -04:00 committed by GitHub
parent ff37eff27d
commit 97e10f57ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 117 additions and 34 deletions

View file

@ -279,6 +279,7 @@ class MusicService
onMain { player.addMediaItems(mediaItems) } onMain { player.addMediaItems(mediaItems) }
} }
updateQueueSize() updateQueueSize()
start()
} }
/** /**

View file

@ -64,6 +64,7 @@ import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.FavoriteWatchManager import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.MediaManagementService import com.github.damontecres.wholphin.services.MediaManagementService
import com.github.damontecres.wholphin.services.MediaReportService import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.MusicService
import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.ThemeSongPlayer import com.github.damontecres.wholphin.services.ThemeSongPlayer
import com.github.damontecres.wholphin.services.UserPreferencesService import com.github.damontecres.wholphin.services.UserPreferencesService
@ -80,6 +81,7 @@ import com.github.damontecres.wholphin.ui.detail.MoreDialogActions
import com.github.damontecres.wholphin.ui.detail.PlaylistDialog import com.github.damontecres.wholphin.ui.detail.PlaylistDialog
import com.github.damontecres.wholphin.ui.detail.PlaylistLoadingState import com.github.damontecres.wholphin.ui.detail.PlaylistLoadingState
import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForHome import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForHome
import com.github.damontecres.wholphin.ui.detail.music.addToQueue
import com.github.damontecres.wholphin.ui.equalsNotNull import com.github.damontecres.wholphin.ui.equalsNotNull
import com.github.damontecres.wholphin.ui.launchDefault import com.github.damontecres.wholphin.ui.launchDefault
import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.launchIO
@ -139,6 +141,7 @@ class CollectionFolderViewModel
private val themeSongPlayer: ThemeSongPlayer, private val themeSongPlayer: ThemeSongPlayer,
private val userPreferencesService: UserPreferencesService, private val userPreferencesService: UserPreferencesService,
private val mediaManagementService: MediaManagementService, private val mediaManagementService: MediaManagementService,
private val musicService: MusicService,
val mediaReportService: MediaReportService, val mediaReportService: MediaReportService,
@Assisted itemId: String, @Assisted itemId: String,
@Assisted initialSortAndDirection: SortAndDirection?, @Assisted initialSortAndDirection: SortAndDirection?,
@ -532,6 +535,11 @@ class CollectionFolderViewModel
item: BaseItem, item: BaseItem,
appPreferences: AppPreferences, appPreferences: AppPreferences,
): Boolean = mediaManagementService.canDelete(item, appPreferences) ): Boolean = mediaManagementService.canDelete(item, appPreferences)
fun addToQueue(
item: BaseItem,
index: Int,
) = addToQueue(api, musicService, item, index)
} }
/** /**
@ -776,6 +784,9 @@ fun CollectionFolderGrid(
onClickGoTo = { onClickGoTo = {
onClickItem.invoke(position, it) onClickItem.invoke(position, it)
}, },
onClickAddToQueue = {
viewModel.addToQueue(it, 0)
},
), ),
), ),
onDismissRequest = { moreDialog.makeAbsent() }, onDismissRequest = { moreDialog.makeAbsent() },

View file

@ -76,6 +76,8 @@ import kotlinx.coroutines.launch
import org.jellyfin.sdk.model.api.MediaSourceInfo import org.jellyfin.sdk.model.api.MediaSourceInfo
import org.jellyfin.sdk.model.api.MediaStream import org.jellyfin.sdk.model.api.MediaStream
import org.jellyfin.sdk.model.api.MediaStreamType import org.jellyfin.sdk.model.api.MediaStreamType
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
import java.util.UUID
/** /**
* Parameters for rendering a [DialogPopup] * Parameters for rendering a [DialogPopup]
@ -597,6 +599,7 @@ fun ConfirmDeleteDialog(
fun chooseVersionParams( fun chooseVersionParams(
context: Context, context: Context,
sources: List<MediaSourceInfo>, sources: List<MediaSourceInfo>,
chosenSourceId: UUID?,
onClick: (Int) -> Unit, onClick: (Int) -> Unit,
): DialogParams = ): DialogParams =
DialogParams( DialogParams(
@ -604,6 +607,7 @@ fun chooseVersionParams(
title = context.getString(R.string.choose_stream, context.getString(R.string.version)), title = context.getString(R.string.choose_stream, context.getString(R.string.version)),
items = items =
sources.filter { it.id.isNotNullOrBlank() }.mapIndexed { index, source -> sources.filter { it.id.isNotNullOrBlank() }.mapIndexed { index, source ->
val uuid = source.id?.toUUIDOrNull()
val videoStream = val videoStream =
source.mediaStreams?.firstOrNull { it.type == MediaStreamType.VIDEO } source.mediaStreams?.firstOrNull { it.type == MediaStreamType.VIDEO }
val title = source.name ?: source.path ?: source.id ?: "" val title = source.name ?: source.path ?: source.id ?: ""
@ -611,6 +615,9 @@ fun chooseVersionParams(
headlineContent = { headlineContent = {
Text(text = title) Text(text = title)
}, },
leadingContent = {
SelectedLeadingContent(uuid != null && uuid == chosenSourceId)
},
supportingContent = { supportingContent = {
videoStream?.displayTitle?.let { Text(text = it) } videoStream?.displayTitle?.let { Text(text = it) }
}, },

View file

@ -26,6 +26,7 @@ import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.FavoriteWatchManager import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.MediaManagementService import com.github.damontecres.wholphin.services.MediaManagementService
import com.github.damontecres.wholphin.services.MediaReportService import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.MusicService
import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.deleteItem import com.github.damontecres.wholphin.services.deleteItem
import com.github.damontecres.wholphin.ui.OneTimeLaunchedEffect import com.github.damontecres.wholphin.ui.OneTimeLaunchedEffect
@ -35,6 +36,7 @@ import com.github.damontecres.wholphin.ui.detail.MoreDialogActions
import com.github.damontecres.wholphin.ui.detail.PlaylistDialog import com.github.damontecres.wholphin.ui.detail.PlaylistDialog
import com.github.damontecres.wholphin.ui.detail.PlaylistLoadingState import com.github.damontecres.wholphin.ui.detail.PlaylistLoadingState
import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForHome import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForHome
import com.github.damontecres.wholphin.ui.detail.music.addToQueue
import com.github.damontecres.wholphin.ui.launchDefault import com.github.damontecres.wholphin.ui.launchDefault
import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.main.HomePageContent import com.github.damontecres.wholphin.ui.main.HomePageContent
@ -48,6 +50,7 @@ import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.model.api.MediaType import org.jellyfin.sdk.model.api.MediaType
import java.util.UUID import java.util.UUID
@ -56,9 +59,11 @@ import java.util.UUID
*/ */
abstract class RecommendedViewModel( abstract class RecommendedViewModel(
@param:ApplicationContext val context: Context, @param:ApplicationContext val context: Context,
val api: ApiClient,
val navigationManager: NavigationManager, val navigationManager: NavigationManager,
val favoriteWatchManager: FavoriteWatchManager, val favoriteWatchManager: FavoriteWatchManager,
val mediaReportService: MediaReportService, val mediaReportService: MediaReportService,
private val musicService: MusicService,
private val backdropService: BackdropService, private val backdropService: BackdropService,
private val mediaManagementService: MediaManagementService, private val mediaManagementService: MediaManagementService,
) : ViewModel() { ) : ViewModel() {
@ -147,6 +152,11 @@ abstract class RecommendedViewModel(
item: BaseItem, item: BaseItem,
appPreferences: AppPreferences, appPreferences: AppPreferences,
): Boolean = mediaManagementService.canDelete(item, appPreferences) ): Boolean = mediaManagementService.canDelete(item, appPreferences)
fun addToQueue(
item: BaseItem,
index: Int,
) = addToQueue(api, musicService, item, index)
} }
@Composable @Composable
@ -244,6 +254,9 @@ fun RecommendedContent(
}, },
onSendMediaInfo = viewModel.mediaReportService::sendReportFor, onSendMediaInfo = viewModel.mediaReportService::sendReportFor,
onClickDelete = { showDeleteDialog = RowColumnItem(position, item) }, onClickDelete = { showDeleteDialog = RowColumnItem(position, item) },
onClickAddToQueue = {
viewModel.addToQueue(it, 0)
},
), ),
), ),
onDismissRequest = { moreDialog.makeAbsent() }, onDismissRequest = { moreDialog.makeAbsent() },

View file

@ -16,6 +16,7 @@ import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.FavoriteWatchManager import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.MediaManagementService import com.github.damontecres.wholphin.services.MediaManagementService
import com.github.damontecres.wholphin.services.MediaReportService import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.MusicService
import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.SuggestionService import com.github.damontecres.wholphin.services.SuggestionService
import com.github.damontecres.wholphin.services.SuggestionsResource import com.github.damontecres.wholphin.services.SuggestionsResource
@ -55,7 +56,8 @@ class RecommendedMovieViewModel
@AssistedInject @AssistedInject
constructor( constructor(
@ApplicationContext context: Context, @ApplicationContext context: Context,
private val api: ApiClient, api: ApiClient,
musicService: MusicService,
private val serverRepository: ServerRepository, private val serverRepository: ServerRepository,
private val preferencesDataStore: DataStore<AppPreferences>, private val preferencesDataStore: DataStore<AppPreferences>,
private val suggestionService: SuggestionService, private val suggestionService: SuggestionService,
@ -67,9 +69,11 @@ class RecommendedMovieViewModel
mediaManagementService: MediaManagementService, mediaManagementService: MediaManagementService,
) : RecommendedViewModel( ) : RecommendedViewModel(
context, context,
api,
navigationManager, navigationManager,
favoriteWatchManager, favoriteWatchManager,
mediaReportService, mediaReportService,
musicService,
backdropService, backdropService,
mediaManagementService, mediaManagementService,
) { ) {

View file

@ -17,6 +17,7 @@ import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.FavoriteWatchManager import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.MediaManagementService import com.github.damontecres.wholphin.services.MediaManagementService
import com.github.damontecres.wholphin.services.MediaReportService import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.MusicService
import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.SuggestionService import com.github.damontecres.wholphin.services.SuggestionService
import com.github.damontecres.wholphin.services.SuggestionsResource import com.github.damontecres.wholphin.services.SuggestionsResource
@ -54,7 +55,8 @@ class RecommendedMusicViewModel
@AssistedInject @AssistedInject
constructor( constructor(
@ApplicationContext context: Context, @ApplicationContext context: Context,
private val api: ApiClient, api: ApiClient,
musicService: MusicService,
private val serverRepository: ServerRepository, private val serverRepository: ServerRepository,
private val preferencesDataStore: DataStore<AppPreferences>, private val preferencesDataStore: DataStore<AppPreferences>,
private val suggestionService: SuggestionService, private val suggestionService: SuggestionService,
@ -66,9 +68,11 @@ class RecommendedMusicViewModel
mediaManagementService: MediaManagementService, mediaManagementService: MediaManagementService,
) : RecommendedViewModel( ) : RecommendedViewModel(
context, context,
api,
navigationManager, navigationManager,
favoriteWatchManager, favoriteWatchManager,
mediaReportService, mediaReportService,
musicService,
backdropService, backdropService,
mediaManagementService, mediaManagementService,
) { ) {

View file

@ -16,6 +16,7 @@ import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.LatestNextUpService import com.github.damontecres.wholphin.services.LatestNextUpService
import com.github.damontecres.wholphin.services.MediaManagementService import com.github.damontecres.wholphin.services.MediaManagementService
import com.github.damontecres.wholphin.services.MediaReportService import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.MusicService
import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.SuggestionService import com.github.damontecres.wholphin.services.SuggestionService
import com.github.damontecres.wholphin.services.SuggestionsResource import com.github.damontecres.wholphin.services.SuggestionsResource
@ -58,7 +59,8 @@ class RecommendedTvShowViewModel
@AssistedInject @AssistedInject
constructor( constructor(
@ApplicationContext context: Context, @ApplicationContext context: Context,
private val api: ApiClient, api: ApiClient,
musicService: MusicService,
private val serverRepository: ServerRepository, private val serverRepository: ServerRepository,
private val preferencesDataStore: DataStore<AppPreferences>, private val preferencesDataStore: DataStore<AppPreferences>,
private val lastestNextUpService: LatestNextUpService, private val lastestNextUpService: LatestNextUpService,
@ -71,9 +73,11 @@ class RecommendedTvShowViewModel
mediaManagementService: MediaManagementService, mediaManagementService: MediaManagementService,
) : RecommendedViewModel( ) : RecommendedViewModel(
context, context,
api,
navigationManager, navigationManager,
favoriteWatchManager, favoriteWatchManager,
mediaReportService, mediaReportService,
musicService,
backdropService, backdropService,
mediaManagementService, mediaManagementService,
) { ) {

View file

@ -3,6 +3,7 @@ package com.github.damontecres.wholphin.ui.detail
import android.content.Context import android.content.Context
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowForward 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.ArrowForward
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Info
@ -32,6 +33,7 @@ data class MoreDialogActions(
val onClickDelete: (BaseItem) -> Unit, val onClickDelete: (BaseItem) -> Unit,
val onClickGoTo: (BaseItem) -> Unit = { navigateTo(it.destination()) }, val onClickGoTo: (BaseItem) -> Unit = { navigateTo(it.destination()) },
val onClickRemoveFromNextUp: (BaseItem) -> Unit = {}, val onClickRemoveFromNextUp: (BaseItem) -> Unit = {},
val onClickAddToQueue: (BaseItem) -> Unit = {},
) )
enum class ClearChosenStreams { enum class ClearChosenStreams {
@ -331,6 +333,16 @@ fun buildMoreDialogItemsForHome(
) )
} }
} }
if (item.type == BaseItemKind.MUSIC_ALBUM) {
add(
DialogItem(
context.getString(R.string.add_to_queue),
Icons.Default.Add,
) {
actions.onClickAddToQueue(item)
},
)
}
add( add(
DialogItem( DialogItem(
text = R.string.add_to_playlist, text = R.string.add_to_playlist,

View file

@ -430,6 +430,7 @@ fun PlaylistDetails(
}, },
onSendMediaInfo = viewModel::sendMediaReport, onSendMediaInfo = viewModel::sendMediaReport,
onClickDelete = { showDeleteDialog = it }, onClickDelete = { showDeleteDialog = it },
onClickAddToQueue = { viewModel.addToQueue(it, 0) },
) )
PlaylistDetailsContent( PlaylistDetailsContent(

View file

@ -124,6 +124,7 @@ fun CollectionDetails(
}, },
onSendMediaInfo = viewModel.mediaReportService::sendReportFor, onSendMediaInfo = viewModel.mediaReportService::sendReportFor,
onClickDelete = { item -> showDeleteDialog = Pair(position, item) }, onClickDelete = { item -> showDeleteDialog = Pair(position, item) },
onClickAddToQueue = { viewModel.addToQueue(it, 0) },
), ),
) )
moreDialog = moreDialog =
@ -244,6 +245,7 @@ fun CollectionDetails(
}, },
onSendMediaInfo = viewModel.mediaReportService::sendReportFor, onSendMediaInfo = viewModel.mediaReportService::sendReportFor,
onClickDelete = { item -> showDeleteDialog = Pair(null, item) }, onClickDelete = { item -> showDeleteDialog = Pair(null, item) },
onClickAddToQueue = { viewModel.addToQueue(it, 0) },
), ),
) )
moreDialog = moreDialog =

View file

@ -19,6 +19,7 @@ import com.github.damontecres.wholphin.services.ImageUrlService
import com.github.damontecres.wholphin.services.KeyValueService import com.github.damontecres.wholphin.services.KeyValueService
import com.github.damontecres.wholphin.services.MediaManagementService import com.github.damontecres.wholphin.services.MediaManagementService
import com.github.damontecres.wholphin.services.MediaReportService import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.MusicService
import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.ThemeSongPlayer import com.github.damontecres.wholphin.services.ThemeSongPlayer
import com.github.damontecres.wholphin.services.UserPreferencesService import com.github.damontecres.wholphin.services.UserPreferencesService
@ -27,6 +28,7 @@ import com.github.damontecres.wholphin.ui.SlimItemFields
import com.github.damontecres.wholphin.ui.collectLatestIn import com.github.damontecres.wholphin.ui.collectLatestIn
import com.github.damontecres.wholphin.ui.data.RowColumn import com.github.damontecres.wholphin.ui.data.RowColumn
import com.github.damontecres.wholphin.ui.data.SortAndDirection import com.github.damontecres.wholphin.ui.data.SortAndDirection
import com.github.damontecres.wholphin.ui.detail.music.addToQueue
import com.github.damontecres.wholphin.ui.formatTypeName import com.github.damontecres.wholphin.ui.formatTypeName
import com.github.damontecres.wholphin.ui.launchDefault import com.github.damontecres.wholphin.ui.launchDefault
import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.launchIO
@ -86,6 +88,7 @@ class CollectionViewModel
private val keyValueService: KeyValueService, private val keyValueService: KeyValueService,
private val libraryDisplayInfoDao: LibraryDisplayInfoDao, private val libraryDisplayInfoDao: LibraryDisplayInfoDao,
private val imageUrlService: ImageUrlService, private val imageUrlService: ImageUrlService,
private val musicService: MusicService,
val mediaReportService: MediaReportService, val mediaReportService: MediaReportService,
@Assisted private val itemId: UUID, @Assisted private val itemId: UUID,
) : ViewModel() { ) : ViewModel() {
@ -462,6 +465,11 @@ class CollectionViewModel
} }
} }
fun addToQueue(
item: BaseItem,
index: Int,
) = addToQueue(api, musicService, item, index)
companion object { companion object {
val typesInCollection = val typesInCollection =
listOf( listOf(

View file

@ -176,6 +176,7 @@ fun EpisodeDetails(
chooseVersionParams( chooseVersionParams(
context, context,
ep.data.mediaSources!!, ep.data.mediaSources!!,
chosenStreams?.source?.id?.toUUIDOrNull(),
) { idx -> ) { idx ->
val source = ep.data.mediaSources!![idx] val source = ep.data.mediaSources!![idx]
viewModel.savePlayVersion( viewModel.savePlayVersion(

View file

@ -210,6 +210,7 @@ fun MovieDetails(
chooseVersionParams( chooseVersionParams(
context, context,
movie.data.mediaSources!!, movie.data.mediaSources!!,
chosenStreams?.source?.id?.toUUIDOrNull(),
) { idx -> ) { idx ->
val source = movie.data.mediaSources!![idx] val source = movie.data.mediaSources!![idx]
viewModel.savePlayVersion( viewModel.savePlayVersion(

View file

@ -81,35 +81,7 @@ abstract class MusicViewModel(
fun addToQueue( fun addToQueue(
item: BaseItem, item: BaseItem,
index: Int, index: Int,
) { ) = addToQueue(api, musicService, item, index)
viewModelScope.launchIO {
Timber.v("addToQueue %s %s", item.type, item.id)
when (item.type) {
BaseItemKind.AUDIO -> {
musicService.addAllToQueue(BlockingList.of(listOf(item)), 0)
}
BaseItemKind.MUSIC_ALBUM -> {
val pager = getPagerForAlbum(api, item.id)
musicService.addAllToQueue(pager, 0)
}
BaseItemKind.MUSIC_ARTIST -> {
val pager = getPagerForArtist(api, item.id)
musicService.addAllToQueue(pager, 0)
}
BaseItemKind.PLAYLIST -> {
val pager = getPagerForPlaylist(api, item.id)
musicService.addAllToQueue(pager, 0)
}
else -> {
Timber.w("Unknown item type to queue for music: %s", item.type)
}
}
}
}
fun startInstantMix(itemId: UUID) { fun startInstantMix(itemId: UUID) {
viewModelScope.launchIO { viewModelScope.launchIO {
@ -140,3 +112,38 @@ abstract class MusicViewModel(
internal abstract fun init() internal abstract fun init()
} }
fun ViewModel.addToQueue(
api: ApiClient,
musicService: MusicService,
item: BaseItem,
index: Int,
) {
viewModelScope.launchIO {
Timber.v("addToQueue %s %s", item.type, item.id)
when (item.type) {
BaseItemKind.AUDIO -> {
musicService.addAllToQueue(BlockingList.of(listOf(item)), 0)
}
BaseItemKind.MUSIC_ALBUM -> {
val pager = getPagerForAlbum(api, item.id)
musicService.addAllToQueue(pager, 0)
}
BaseItemKind.MUSIC_ARTIST -> {
val pager = getPagerForArtist(api, item.id)
musicService.addAllToQueue(pager, 0)
}
BaseItemKind.PLAYLIST -> {
val pager = getPagerForPlaylist(api, item.id)
musicService.addAllToQueue(pager, 0)
}
else -> {
Timber.w("Unknown item type to queue for music: %s", item.type)
}
}
}
}

View file

@ -225,6 +225,7 @@ fun SeriesOverview(
chooseVersionParams( chooseVersionParams(
context, context,
ep.data.mediaSources!!, ep.data.mediaSources!!,
chosenStreams?.source?.id?.toUUIDOrNull(),
) { idx -> ) { idx ->
val source = ep.data.mediaSources!![idx] val source = ep.data.mediaSources!![idx]
viewModel.savePlayVersion( viewModel.savePlayVersion(

View file

@ -287,8 +287,7 @@ class SeriesViewModel
item.value?.let { item -> item.value?.let { item ->
if (loading.value == LoadingState.Success) { if (loading.value == LoadingState.Success) {
viewModelScope.launchIO { viewModelScope.launchIO {
val seasons = getSeasons(item, null).await() (seasons.value as? ApiRequestPager<*>)?.refresh()
this@SeriesViewModel.seasons.setValueOnMain(seasons)
} }
} }
} }

View file

@ -107,6 +107,13 @@ abstract class RequestPager<T>(
} }
} }
suspend fun refresh() {
cachedPages.asMap().keys.forEachIndexed { index, pageNum ->
if (DEBUG) Timber.v("refresh: pageNum=%s", pageNum)
fetchPageBlocking(pageNum * pageSize, index == 0)
}
}
protected abstract suspend fun fetchPage( protected abstract suspend fun fetchPage(
pageNumber: Int, pageNumber: Int,
includeTotalCount: Boolean, includeTotalCount: Boolean,