Add more sort options to different types (#1488)

## Description
Adds more sorting options, notably premier date & ratings, to different
media types.

### Related issues
Closes #1417
Closes #1429
Replaces #1420

### Testing
Emulator on movie genre's items and music video libraries

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Damontecres 2026-05-30 16:56:33 -04:00 • committed by GitHub
parent 81e5f31401
commit 273a6138c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 63 additions and 0 deletions

View file

@ -24,6 +24,7 @@ import kotlinx.serialization.Transient
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
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
import org.jellyfin.sdk.model.api.CollectionType
import org.jellyfin.sdk.model.extensions.ticks import org.jellyfin.sdk.model.extensions.ticks
import java.util.Locale import java.util.Locale
import java.util.UUID import java.util.UUID
@ -283,6 +284,7 @@ fun createGenreDestination(
parentId: UUID, parentId: UUID,
parentName: String?, parentName: String?,
includeItemTypes: List<BaseItemKind>?, includeItemTypes: List<BaseItemKind>?,
collectionType: CollectionType,
) = Destination.FilteredCollection( ) = Destination.FilteredCollection(
itemId = parentId, itemId = parentId,
parentType = BaseItemKind.GENRE, parentType = BaseItemKind.GENRE,
@ -301,6 +303,7 @@ fun createGenreDestination(
useSavedLibraryDisplayInfo = false, useSavedLibraryDisplayInfo = false,
), ),
recursive = true, recursive = true,
collectionType = collectionType,
) )
fun createStudioDestination( fun createStudioDestination(
@ -327,6 +330,7 @@ fun createStudioDestination(
useSavedLibraryDisplayInfo = false, useSavedLibraryDisplayInfo = false,
), ),
recursive = true, recursive = true,
collectionType = CollectionType.UNKNOWN,
) )
val BaseItem.studioNames get() = data.studios?.mapNotNull { it.name }.orEmpty() val BaseItem.studioNames get() = data.studios?.mapNotNull { it.name }.orEmpty()

View file

@ -693,6 +693,9 @@ class HomeSettingsService
listOf(it) listOf(it)
} }
}, },
collectionType =
library?.collectionType
?: CollectionType.UNKNOWN,
), ),
) )
} }

View file

@ -51,6 +51,7 @@ import kotlinx.coroutines.withContext
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.userLibraryApi import org.jellyfin.sdk.api.client.extensions.userLibraryApi
import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CollectionType
import org.jellyfin.sdk.model.api.ImageType import org.jellyfin.sdk.model.api.ImageType
import org.jellyfin.sdk.model.api.ItemFields import org.jellyfin.sdk.model.api.ItemFields
import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.ItemSortBy
@ -255,6 +256,7 @@ data class Genre(
fun GenreCardGrid( fun GenreCardGrid(
itemId: UUID, itemId: UUID,
includeItemTypes: List<BaseItemKind>?, includeItemTypes: List<BaseItemKind>?,
collectionType: CollectionType,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
initialPosition: Int = 0, initialPosition: Int = 0,
viewModel: GenreViewModel = viewModel: GenreViewModel =
@ -308,6 +310,7 @@ fun GenreCardGrid(
parentId = itemId, parentId = itemId,
parentName = item.title, parentName = item.title,
includeItemTypes = includeItemTypes, includeItemTypes = includeItemTypes,
collectionType = collectionType,
), ),
) )
}, },

View file

@ -1,8 +1,12 @@
package com.github.damontecres.wholphin.ui.data package com.github.damontecres.wholphin.ui.data
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.R
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CollectionType
import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.ItemSortBy
import org.jellyfin.sdk.model.api.SortOrder import org.jellyfin.sdk.model.api.SortOrder
@ -46,6 +50,7 @@ val SeriesSortOptions =
ItemSortBy.DATE_LAST_CONTENT_ADDED, ItemSortBy.DATE_LAST_CONTENT_ADDED,
ItemSortBy.DATE_PLAYED, ItemSortBy.DATE_PLAYED,
ItemSortBy.COMMUNITY_RATING, ItemSortBy.COMMUNITY_RATING,
ItemSortBy.CRITIC_RATING,
ItemSortBy.OFFICIAL_RATING, ItemSortBy.OFFICIAL_RATING,
ItemSortBy.RANDOM, ItemSortBy.RANDOM,
) )
@ -53,19 +58,27 @@ val SeriesSortOptions =
val EpisodeSortOptions = val EpisodeSortOptions =
listOf( listOf(
ItemSortBy.SORT_NAME, ItemSortBy.SORT_NAME,
ItemSortBy.PREMIERE_DATE,
ItemSortBy.DATE_CREATED, ItemSortBy.DATE_CREATED,
ItemSortBy.DATE_PLAYED, ItemSortBy.DATE_PLAYED,
ItemSortBy.AIRED_EPISODE_ORDER, ItemSortBy.AIRED_EPISODE_ORDER,
ItemSortBy.COMMUNITY_RATING,
ItemSortBy.CRITIC_RATING,
ItemSortBy.OFFICIAL_RATING, ItemSortBy.OFFICIAL_RATING,
ItemSortBy.RUNTIME, ItemSortBy.RUNTIME,
ItemSortBy.PLAY_COUNT,
ItemSortBy.RANDOM, ItemSortBy.RANDOM,
) )
val VideoSortOptions = val VideoSortOptions =
listOf( listOf(
ItemSortBy.SORT_NAME, ItemSortBy.SORT_NAME,
ItemSortBy.PREMIERE_DATE,
ItemSortBy.DATE_CREATED, ItemSortBy.DATE_CREATED,
ItemSortBy.DATE_PLAYED, ItemSortBy.DATE_PLAYED,
ItemSortBy.COMMUNITY_RATING,
ItemSortBy.CRITIC_RATING,
ItemSortBy.OFFICIAL_RATING,
ItemSortBy.RUNTIME, ItemSortBy.RUNTIME,
ItemSortBy.PLAY_COUNT, ItemSortBy.PLAY_COUNT,
ItemSortBy.RANDOM, ItemSortBy.RANDOM,
@ -80,6 +93,7 @@ val PlaylistSortOptions =
ItemSortBy.DATE_PLAYED, ItemSortBy.DATE_PLAYED,
ItemSortBy.COMMUNITY_RATING, ItemSortBy.COMMUNITY_RATING,
ItemSortBy.CRITIC_RATING, ItemSortBy.CRITIC_RATING,
ItemSortBy.OFFICIAL_RATING,
ItemSortBy.RUNTIME, ItemSortBy.RUNTIME,
ItemSortBy.PLAY_COUNT, ItemSortBy.PLAY_COUNT,
ItemSortBy.RANDOM, ItemSortBy.RANDOM,
@ -180,3 +194,31 @@ fun getStringRes(sort: ItemSortBy): Int =
else -> throw IllegalArgumentException("Unsupported sort option: $sort") else -> throw IllegalArgumentException("Unsupported sort option: $sort")
} }
@Composable
fun rememberSortOptions(collectionType: CollectionType): List<ItemSortBy> =
remember(collectionType) {
when (collectionType) {
CollectionType.MOVIES -> MovieSortOptions
CollectionType.TVSHOWS -> SeriesSortOptions
CollectionType.MUSIC -> AlbumSortOptions
CollectionType.BOXSETS -> BoxSetSortOptions
else -> VideoSortOptions
}
}
@Composable
fun rememberSortOptions(type: BaseItemKind): List<ItemSortBy> =
remember(type) {
when (type) {
BaseItemKind.MOVIE -> MovieSortOptions
BaseItemKind.SERIES -> SeriesSortOptions
BaseItemKind.SEASON -> SeriesSortOptions
BaseItemKind.EPISODE -> EpisodeSortOptions
BaseItemKind.AUDIO -> SongSortOptions
BaseItemKind.MUSIC_ALBUM -> AlbumSortOptions
BaseItemKind.MUSIC_ARTIST -> ArtistSortOptions
BaseItemKind.BOX_SET -> BoxSetSortOptions
else -> VideoSortOptions
}
}

View file

@ -36,6 +36,7 @@ import com.github.damontecres.wholphin.ui.logTab
import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel
import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CollectionType
@Composable @Composable
fun CollectionFolderMovie( fun CollectionFolderMovie(
@ -173,6 +174,7 @@ fun CollectionFolderMovie(
GenreCardGrid( GenreCardGrid(
itemId = destination.itemId, itemId = destination.itemId,
includeItemTypes = listOf(BaseItemKind.MOVIE), includeItemTypes = listOf(BaseItemKind.MOVIE),
collectionType = CollectionType.MOVIES,
modifier = modifier =
Modifier Modifier
.fillMaxSize() .fillMaxSize()

View file

@ -53,6 +53,7 @@ import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CollectionType
import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest
import java.util.UUID import java.util.UUID
@ -267,6 +268,7 @@ fun CollectionFolderMusic(
GenreCardGrid( GenreCardGrid(
itemId = destination.itemId, itemId = destination.itemId,
includeItemTypes = listOf(BaseItemKind.MUSIC_ALBUM), includeItemTypes = listOf(BaseItemKind.MUSIC_ALBUM),
collectionType = CollectionType.MUSIC,
modifier = modifier =
Modifier Modifier
.fillMaxSize() .fillMaxSize()

View file

@ -39,6 +39,7 @@ import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel
import com.github.damontecres.wholphin.ui.tryRequestFocus import com.github.damontecres.wholphin.ui.tryRequestFocus
import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CollectionType
@Composable @Composable
fun CollectionFolderTv( fun CollectionFolderTv(
@ -148,6 +149,7 @@ fun CollectionFolderTv(
GenreCardGrid( GenreCardGrid(
itemId = destination.itemId, itemId = destination.itemId,
includeItemTypes = listOf(BaseItemKind.SERIES), includeItemTypes = listOf(BaseItemKind.SERIES),
collectionType = CollectionType.TVSHOWS,
modifier = modifier =
Modifier Modifier
.fillMaxSize() .fillMaxSize()

View file

@ -73,6 +73,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jellyfin.sdk.model.api.CollectionType
import org.jellyfin.sdk.model.api.MediaType import org.jellyfin.sdk.model.api.MediaType
import timber.log.Timber import timber.log.Timber
import java.util.UUID import java.util.UUID
@ -299,6 +300,7 @@ fun HomeRowGrid(
includeItemTypes = null, includeItemTypes = null,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
initialPosition = destination.initialPosition, initialPosition = destination.initialPosition,
collectionType = CollectionType.UNKNOWN,
) )
} }

View file

@ -106,6 +106,7 @@ sealed class Destination(
val parentType: BaseItemKind, val parentType: BaseItemKind,
val filter: CollectionFolderFilter, val filter: CollectionFolderFilter,
val recursive: Boolean, val recursive: Boolean,
val collectionType: CollectionType,
) : Destination(false) ) : Destination(false)
@Serializable @Serializable

View file

@ -13,6 +13,7 @@ import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.ui.components.ItemGrid import com.github.damontecres.wholphin.ui.components.ItemGrid
import com.github.damontecres.wholphin.ui.components.LicenseInfo import com.github.damontecres.wholphin.ui.components.LicenseInfo
import com.github.damontecres.wholphin.ui.data.MovieSortOptions import com.github.damontecres.wholphin.ui.data.MovieSortOptions
import com.github.damontecres.wholphin.ui.data.rememberSortOptions
import com.github.damontecres.wholphin.ui.detail.CollectionFolderGeneric import com.github.damontecres.wholphin.ui.detail.CollectionFolderGeneric
import com.github.damontecres.wholphin.ui.detail.CollectionFolderLiveTv import com.github.damontecres.wholphin.ui.detail.CollectionFolderLiveTv
import com.github.damontecres.wholphin.ui.detail.CollectionFolderMovie import com.github.damontecres.wholphin.ui.detail.CollectionFolderMovie
@ -286,6 +287,7 @@ fun DestinationContent(
BaseItemKind.STUDIO -> DefaultForStudiosFilterOptions BaseItemKind.STUDIO -> DefaultForStudiosFilterOptions
else -> throw IllegalArgumentException("Unsupported parentType ${destination.parentType}") else -> throw IllegalArgumentException("Unsupported parentType ${destination.parentType}")
}, },
sortOptions = rememberSortOptions(destination.collectionType),
modifier = modifier, modifier = modifier,
) )
} }