diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/HomeRowConfig.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/HomeRowConfig.kt index d760d445..27be82ca 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/HomeRowConfig.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/HomeRowConfig.kt @@ -81,6 +81,16 @@ sealed class HomeRowConfig { ) : HomeRowConfig() { override fun updateViewOptions(viewOptions: HomeRowViewOptions): HomeRowConfig = this.copy(viewOptions = viewOptions) } + + @Serializable + @SerialName("Collection") + data class Collection( + override val id: Int, + val collectionId: UUID, + override val viewOptions: HomeRowViewOptions, + ) : HomeRowConfig() { + override fun updateViewOptions(viewOptions: HomeRowViewOptions): HomeRowConfig = this.copy(viewOptions = viewOptions) + } } @Serializable diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomePageSettings.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomePageSettings.kt index 61a2ec2a..a94d56ea 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomePageSettings.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomePageSettings.kt @@ -31,6 +31,7 @@ import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowConfigDisplay import com.github.damontecres.wholphin.data.model.HomeRowViewOptions +import com.github.damontecres.wholphin.preferences.HomePagePreferences import com.github.damontecres.wholphin.services.BackdropService import com.github.damontecres.wholphin.services.ImageUrlService import com.github.damontecres.wholphin.services.LatestNextUpService @@ -46,6 +47,7 @@ import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem import com.github.damontecres.wholphin.util.GetGenresRequestHandler import com.github.damontecres.wholphin.util.GetItemsRequestHandler import com.github.damontecres.wholphin.util.HomeRowLoadingState +import com.github.damontecres.wholphin.util.HomeRowLoadingState.Success import com.github.damontecres.wholphin.util.LoadingState import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext @@ -57,9 +59,11 @@ import org.jellyfin.sdk.api.client.extensions.userLibraryApi import org.jellyfin.sdk.model.api.CollectionType import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.SortOrder +import org.jellyfin.sdk.model.api.UserDto import org.jellyfin.sdk.model.api.request.GetGenresRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetLatestMediaRequest +import org.jellyfin.sdk.model.serializer.toUUID import java.util.UUID import javax.inject.Inject @@ -145,7 +149,19 @@ class HomePageSettingsViewModel ), ) } - val rowConfig = continueWatchingRows + includedIds + val rowConfig = + continueWatchingRows + includedIds + + // TODO remove after testing + listOf( + HomeRowConfigDisplay( + "Collection", + HomeRowConfig.Collection( + 100, + "34ab6fd1f51c41bb014981f2e334f465".toUUID(), + HomeRowViewOptions(), + ), + ), + ) _state.update { it.copy(rows = rowConfig) } @@ -171,166 +187,7 @@ class HomePageSettingsViewModel .map { it.config } .map { row -> // TODO parallelize - when (row) { - is HomeRowConfig.ContinueWatching -> { - val resume = latestNextUpService.getResume(userDto.id, limit, true) - listOf( - HomeRowLoadingState.Success( - title = context.getString(R.string.continue_watching), - items = resume, - viewOptions = row.viewOptions, - ), - ) - } - - is HomeRowConfig.NextUp -> { - val nextUp = - latestNextUpService.getNextUp( - userDto.id, - limit, - prefs.enableRewatchingNextUp, - false, - ) - listOf( - HomeRowLoadingState.Success( - title = context.getString(R.string.next_up), - items = nextUp, - viewOptions = row.viewOptions, - ), - ) - } - - is HomeRowConfig.ContinueWatchingCombined -> { - val resume = - latestNextUpService.getResume(userDto.id, limit, true) - val nextUp = - latestNextUpService.getNextUp( - userDto.id, - limit, - prefs.enableRewatchingNextUp, - false, - ) - - listOf( - HomeRowLoadingState.Success( - title = context.getString(R.string.continue_watching), - items = - latestNextUpService.buildCombined( - resume, - nextUp, - ), - viewOptions = row.viewOptions, - ), - ) - } - - is HomeRowConfig.Genres -> { - val request = - GetGenresRequest( - parentId = row.parentId, - userId = userDto.id, - limit = limit, - ) - val items = - GetGenresRequestHandler - .execute(api, request) - .content.items - val genreIds = items.map { it.id } - val genreImages = - getGenreImageMap( - api = api, - imageUrlService = imageUrlService, - genres = genreIds, - parentId = row.parentId, - includeItemTypes = null, - cardWidthPx = null, - ) - val genres = - items.map { - BaseItem(it, false, genreImages[it.id]) - } - - val name = - _state.value.libraries - .firstOrNull { it.itemId == row.parentId } - ?.name - val title = - name?.let { context.getString(R.string.genres_in, it) } - ?: context.getString(R.string.genres) - listOf( - HomeRowLoadingState.Success( - title, - genres, - viewOptions = row.viewOptions, - ), - ) - } - - is HomeRowConfig.RecentlyAdded -> { - val name = - _state.value.libraries - .firstOrNull { it.itemId == row.parentId } - ?.name - val title = - name?.let { context.getString(R.string.recently_added_in, it) } - ?: context.getString(R.string.recently_added) - val request = - GetLatestMediaRequest( - fields = SlimItemFields, - imageTypeLimit = 1, - parentId = row.parentId, - groupItems = true, - limit = limit, - isPlayed = null, // Server will handle user's preference - ) - val latest = - api.userLibraryApi - .getLatestMedia(request) - .content - .map { BaseItem.from(it, api, true) } - .let { - HomeRowLoadingState.Success( - title, - it, - row.viewOptions, - ) - } - listOf(latest) - } - - is HomeRowConfig.RecentlyReleased -> { - val name = - _state.value.libraries - .firstOrNull { it.itemId == row.parentId } - ?.name - val title = - name?.let { - context.getString(R.string.recently_released_in, it) - } ?: context.getString(R.string.recently_released) - val request = - GetItemsRequest( - parentId = row.parentId, - limit = limit, - sortBy = listOf(ItemSortBy.PREMIERE_DATE), - sortOrder = listOf(SortOrder.DESCENDING), - fields = DefaultItemFields, - recursive = true, - ) - GetItemsRequestHandler - .execute(api, request) - .content.items - .map { BaseItem.from(it, api, true) } - .let { - listOf( - HomeRowLoadingState.Success( - title, - it, - row.viewOptions, - ), - ) - } - } - } + parseRow(prefs, userDto, row, limit) }.flatten() } rows?.let { rows -> @@ -340,6 +197,197 @@ class HomePageSettingsViewModel } } + private suspend fun parseRow( + prefs: HomePagePreferences, + userDto: UserDto, + row: HomeRowConfig, + limit: Int, + ): List = + when (row) { + is HomeRowConfig.ContinueWatching -> { + val resume = latestNextUpService.getResume(userDto.id, limit, true) + listOf( + Success( + title = context.getString(R.string.continue_watching), + items = resume, + viewOptions = row.viewOptions, + ), + ) + } + + is HomeRowConfig.NextUp -> { + val nextUp = + latestNextUpService.getNextUp( + userDto.id, + limit, + prefs.enableRewatchingNextUp, + false, + ) + listOf( + Success( + title = context.getString(R.string.next_up), + items = nextUp, + viewOptions = row.viewOptions, + ), + ) + } + + is HomeRowConfig.ContinueWatchingCombined -> { + val resume = + latestNextUpService.getResume(userDto.id, limit, true) + val nextUp = + latestNextUpService.getNextUp( + userDto.id, + limit, + prefs.enableRewatchingNextUp, + false, + ) + + listOf( + Success( + title = context.getString(R.string.continue_watching), + items = + latestNextUpService.buildCombined( + resume, + nextUp, + ), + viewOptions = row.viewOptions, + ), + ) + } + + is HomeRowConfig.Genres -> { + val request = + GetGenresRequest( + parentId = row.parentId, + userId = userDto.id, + limit = limit, + ) + val items = + GetGenresRequestHandler + .execute(api, request) + .content.items + val genreIds = items.map { it.id } + val genreImages = + getGenreImageMap( + api = api, + imageUrlService = imageUrlService, + genres = genreIds, + parentId = row.parentId, + includeItemTypes = null, + cardWidthPx = null, + ) + val genres = + items.map { + BaseItem(it, false, genreImages[it.id]) + } + + val name = + _state.value.libraries + .firstOrNull { it.itemId == row.parentId } + ?.name + val title = + name?.let { context.getString(R.string.genres_in, it) } + ?: context.getString(R.string.genres) + listOf( + Success( + title, + genres, + viewOptions = row.viewOptions, + ), + ) + } + + is HomeRowConfig.RecentlyAdded -> { + val name = + _state.value.libraries + .firstOrNull { it.itemId == row.parentId } + ?.name + val title = + name?.let { context.getString(R.string.recently_added_in, it) } + ?: context.getString(R.string.recently_added) + val request = + GetLatestMediaRequest( + fields = SlimItemFields, + imageTypeLimit = 1, + parentId = row.parentId, + groupItems = true, + limit = limit, + isPlayed = null, // Server will handle user's preference + ) + val latest = + api.userLibraryApi + .getLatestMedia(request) + .content + .map { BaseItem.from(it, api, true) } + .let { + Success( + title, + it, + row.viewOptions, + ) + } + listOf(latest) + } + + is HomeRowConfig.RecentlyReleased -> { + val name = + _state.value.libraries + .firstOrNull { it.itemId == row.parentId } + ?.name + val title = + name?.let { + context.getString(R.string.recently_released_in, it) + } ?: context.getString(R.string.recently_released) + val request = + GetItemsRequest( + parentId = row.parentId, + limit = limit, + sortBy = listOf(ItemSortBy.PREMIERE_DATE), + sortOrder = listOf(SortOrder.DESCENDING), + fields = DefaultItemFields, + recursive = true, + ) + GetItemsRequestHandler + .execute(api, request) + .content.items + .map { BaseItem.from(it, api, true) } + .let { + listOf( + Success( + title, + it, + row.viewOptions, + ), + ) + } + } + + is HomeRowConfig.Collection -> { + val collection by api.userLibraryApi.getItem(itemId = row.collectionId) + val request = + GetItemsRequest( + parentId = row.collectionId, + limit = limit, + fields = DefaultItemFields, + recursive = true, + ) + GetItemsRequestHandler + .execute(api, request) + .content.items + .map { BaseItem.from(it, api, true) } + .let { + listOf( + Success( + collection.name ?: "", + it, + row.viewOptions, + ), + ) + } + } + } + private fun List.move( direction: MoveDirection, index: Int,