From b40db0074f214e7725a693919ff183cc03a1986f Mon Sep 17 00:00:00 2001 From: Damontecres Date: Mon, 13 Oct 2025 21:58:55 -0400 Subject: [PATCH] Support collections --- .../damontecres/dolphin/ui/cards/GridCard.kt | 4 +-- .../ui/components/CollectionFolderGrid.kt | 35 +++++++++++++++---- .../damontecres/dolphin/ui/detail/CardGrid.kt | 4 +-- .../ui/detail/CollectionFolderGeneric.kt | 2 ++ .../ui/detail/CollectionFolderMovie.kt | 1 + .../dolphin/ui/detail/CollectionFolderTv.kt | 1 + .../dolphin/ui/detail/ItemViewModel.kt | 8 +++-- .../dolphin/ui/nav/DestinationContent.kt | 18 ++++++++++ .../damontecres/dolphin/ui/nav/NavDrawer.kt | 2 ++ .../damontecres/dolphin/util/Constants.kt | 1 + app/src/main/res/values/fa_strings.xml | 2 ++ 11 files changed, 64 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/cards/GridCard.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/cards/GridCard.kt index 6137a859..9480531e 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/cards/GridCard.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/cards/GridCard.kt @@ -98,7 +98,7 @@ fun GridCard( .fillMaxWidth(), ) { Text( - text = item?.name ?: "", + text = item?.title ?: "", maxLines = 1, textAlign = TextAlign.Center, overflow = TextOverflow.Ellipsis, @@ -109,7 +109,7 @@ fun GridCard( .enableMarquee(focusedAfterDelay), ) Text( - text = item?.data?.productionYear?.toString() ?: "", + text = item?.subtitle ?: "", maxLines = 1, textAlign = TextAlign.Center, modifier = diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/components/CollectionFolderGrid.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/components/CollectionFolderGrid.kt index cd81afe8..a5c90ff6 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/components/CollectionFolderGrid.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/components/CollectionFolderGrid.kt @@ -72,6 +72,7 @@ class CollectionFolderViewModel itemId: UUID, potential: BaseItem?, sortAndDirection: SortAndDirection, + recursive: Boolean, ): Job = viewModelScope.launch( LoadingExceptionHandler( @@ -80,10 +81,13 @@ class CollectionFolderViewModel ) + Dispatchers.IO, ) { fetchItem(itemId, potential) - loadResults(sortAndDirection) + loadResults(sortAndDirection, recursive) } - fun loadResults(sortAndDirection: SortAndDirection) { + fun loadResults( + sortAndDirection: SortAndDirection, + recursive: Boolean, + ) { item.value?.let { item -> viewModelScope.launch(Dispatchers.IO) { withContext(Dispatchers.Main) { @@ -96,6 +100,15 @@ class CollectionFolderViewModel CollectionType.MOVIES -> listOf(BaseItemKind.MOVIE) CollectionType.TVSHOWS -> listOf(BaseItemKind.SERIES) CollectionType.HOMEVIDEOS -> listOf(BaseItemKind.VIDEO) + CollectionType.MUSIC -> + listOf( + BaseItemKind.AUDIO, + BaseItemKind.MUSIC_ARTIST, + BaseItemKind.MUSIC_ALBUM, + ) + + CollectionType.BOXSETS -> listOf(BaseItemKind.BOX_SET) + CollectionType.PLAYLISTS -> listOf(BaseItemKind.PLAYLIST) else -> listOf() } @@ -104,7 +117,8 @@ class CollectionFolderViewModel parentId = item.id, enableImageTypes = listOf(ImageType.PRIMARY, ImageType.THUMB), includeItemTypes = includeItemTypes, - recursive = true, + recursive = recursive, + excludeItemIds = listOf(item.id), sortBy = listOf( sortAndDirection.sort, @@ -120,7 +134,13 @@ class CollectionFolderViewModel fields = DefaultItemFields, ) val newPager = - ApiRequestPager(api, request, GetItemsRequestHandler, viewModelScope) + ApiRequestPager( + api, + request, + GetItemsRequestHandler, + viewModelScope, + useSeriesForPrimary = true, + ) newPager.init() if (newPager.isNotEmpty()) newPager.getBlocking(0) withContext(Dispatchers.Main) { @@ -164,6 +184,7 @@ class CollectionFolderViewModel fun CollectionFolderGrid( preferences: UserPreferences, destination: Destination.MediaItem, + recursive: Boolean, onClickItem: (BaseItem) -> Unit, modifier: Modifier = Modifier, viewModel: CollectionFolderViewModel = hiltViewModel(), @@ -176,7 +197,7 @@ fun CollectionFolderGrid( positionCallback: ((columns: Int, position: Int) -> Unit)? = null, ) { OneTimeLaunchedEffect { - viewModel.init(destination.itemId, destination.item, initialSortAndDirection) + viewModel.init(destination.itemId, destination.item, initialSortAndDirection, recursive) } val sortAndDirection by viewModel.sortAndDirection.observeAsState(initialSortAndDirection) val loading by viewModel.loading.observeAsState(LoadingState.Loading) @@ -198,7 +219,7 @@ fun CollectionFolderGrid( modifier = modifier, onClickItem = onClickItem, onSortChange = { - viewModel.loadResults(it) + viewModel.loadResults(it, recursive) }, showTitle = showTitle, positionCallback = positionCallback, @@ -263,7 +284,7 @@ fun CollectionFolderGridContent( CardGrid( pager = pager, onClickItem = onClickItem, - longClicker = {}, + onLongClickItem = {}, letterPosition = letterPosition, gridFocusRequester = gridFocusRequester, showJumpButtons = false, // TODO add preference diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CardGrid.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CardGrid.kt index 17cb2607..da5e80a8 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CardGrid.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CardGrid.kt @@ -69,7 +69,7 @@ private const val DEBUG = false fun CardGrid( pager: List, onClickItem: (BaseItem) -> Unit, - longClicker: (BaseItem) -> Unit, + onLongClickItem: (BaseItem) -> Unit, letterPosition: suspend (Char) -> Int, gridFocusRequester: FocusRequester, showJumpButtons: Boolean, @@ -257,7 +257,7 @@ fun CardGrid( onClickItem.invoke(item) } }, - onLongClick = { if (item != null) longClicker.invoke(item) }, + onLongClick = { if (item != null) onLongClickItem.invoke(item) }, modifier = mod .ifElse(index == 0, Modifier.focusRequester(zeroFocus)) diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderGeneric.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderGeneric.kt index 69d356af..01d5aa19 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderGeneric.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderGeneric.kt @@ -18,6 +18,7 @@ import com.github.damontecres.dolphin.ui.preferences.PreferencesViewModel fun CollectionFolderGeneric( preferences: UserPreferences, destination: Destination.MediaItem, + recursive: Boolean, modifier: Modifier = Modifier, preferencesViewModel: PreferencesViewModel = hiltViewModel(), ) { @@ -27,6 +28,7 @@ fun CollectionFolderGeneric( onClickItem = { preferencesViewModel.navigationManager.navigateTo(it.destination()) }, destination = destination, showTitle = showHeader, + recursive = recursive, modifier = modifier .padding(start = 16.dp), diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderMovie.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderMovie.kt index 5be4e02f..8aea2b1b 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderMovie.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderMovie.kt @@ -156,6 +156,7 @@ fun CollectionFolderMovie( onClickItem = onClickItem, destination = destination, showTitle = false, + recursive = true, modifier = Modifier .padding(start = 16.dp) diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderTv.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderTv.kt index 5d25dee4..16702d2f 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderTv.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/CollectionFolderTv.kt @@ -155,6 +155,7 @@ fun CollectionFolderTv( preferences = preferences, destination = destination, showTitle = false, + recursive = true, modifier = Modifier .padding(start = 16.dp) diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/ItemViewModel.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/ItemViewModel.kt index 49123c44..5b7001b6 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/ItemViewModel.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/ItemViewModel.kt @@ -61,13 +61,14 @@ abstract class ItemViewModel( abstract class LoadingItemViewModel( api: ApiClient, ) : ItemViewModel(api) { - val loading = MutableLiveData(LoadingState.Loading) + val loading = MutableLiveData(LoadingState.Pending) open fun init( itemId: UUID, potential: BaseItem?, - ): Job? = - viewModelScope.launch( + ): Job? { + loading.value = LoadingState.Loading + return viewModelScope.launch( LoadingExceptionHandler( loading, "Error loading item $itemId", @@ -85,4 +86,5 @@ abstract class LoadingItemViewModel( loading.value = LoadingState.Error("Error loading item $itemId", e) } } + } } diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/nav/DestinationContent.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/nav/DestinationContent.kt index 05914f03..2f971c17 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/nav/DestinationContent.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/nav/DestinationContent.kt @@ -106,6 +106,14 @@ fun DestinationContent( modifier, ) + BaseItemKind.BOX_SET -> + CollectionFolderGeneric( + preferences, + destination, + false, + modifier, + ) + BaseItemKind.COLLECTION_FOLDER -> { when (destination.item?.data?.collectionType) { CollectionType.TVSHOWS -> @@ -122,10 +130,19 @@ fun DestinationContent( modifier, ) + CollectionType.BOXSETS -> + CollectionFolderGeneric( + preferences, + destination, + true, + modifier, + ) + else -> CollectionFolderGeneric( preferences, destination, + false, modifier, ) } @@ -141,6 +158,7 @@ fun DestinationContent( CollectionFolderGeneric( preferences, destination, + true, modifier, ) diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/nav/NavDrawer.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/nav/NavDrawer.kt index ac53ff41..40a6a6a0 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/nav/NavDrawer.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/nav/NavDrawer.kt @@ -318,6 +318,8 @@ fun NavigationDrawerScope.LibraryNavItem( CollectionType.HOMEVIDEOS -> R.string.fa_video CollectionType.LIVETV -> R.string.fa_tv CollectionType.MUSIC -> R.string.fa_music + CollectionType.BOXSETS -> R.string.fa_open_folder + CollectionType.PLAYLISTS -> R.string.fa_list_ul else -> R.string.fa_film } val isFocused = interactionSource.collectIsFocusedAsState().value diff --git a/app/src/main/java/com/github/damontecres/dolphin/util/Constants.kt b/app/src/main/java/com/github/damontecres/dolphin/util/Constants.kt index e65b2c7a..aa8a2ab9 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/util/Constants.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/util/Constants.kt @@ -28,4 +28,5 @@ val supportedCollectionTypes = CollectionType.TVSHOWS, CollectionType.HOMEVIDEOS, CollectionType.PLAYLISTS, + CollectionType.BOXSETS, ) diff --git a/app/src/main/res/values/fa_strings.xml b/app/src/main/res/values/fa_strings.xml index 8b6e56df..68a0990e 100644 --- a/app/src/main/res/values/fa_strings.xml +++ b/app/src/main/res/values/fa_strings.xml @@ -32,4 +32,6 @@ + +