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 03c662b7..b195c28d 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 @@ -136,6 +136,18 @@ sealed interface HomeRowConfig { override fun updateViewOptions(viewOptions: HomeRowViewOptions): TvPrograms = this.copy(viewOptions = viewOptions) } + /** + * Fetch suggestions from [com.github.damontecres.wholphin.services.SuggestionService] for the given parent ID + */ + @Serializable + @SerialName("Suggestions") + data class Suggestions( + val parentId: UUID, + override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(), + ) : HomeRowConfig { + override fun updateViewOptions(viewOptions: HomeRowViewOptions): Suggestions = this.copy(viewOptions = viewOptions) + } + /** * Fetch by parent ID such as a library, collection, or playlist with optional simple sorting */ diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt index 6cc0a197..24951110 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt @@ -23,6 +23,7 @@ import com.github.damontecres.wholphin.util.supportedHomeCollectionTypes import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.update import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json @@ -64,6 +65,7 @@ class HomeSettingsService private val navDrawerItemRepository: NavDrawerItemRepository, private val latestNextUpService: LatestNextUpService, private val imageUrlService: ImageUrlService, + private val suggestionService: SuggestionService, ) { @OptIn(ExperimentalSerializationApi::class) val jsonParser = @@ -504,6 +506,18 @@ class HomeSettingsService config, ) } + + is HomeRowConfig.Suggestions -> { + val name = + api.userLibraryApi + .getItem(itemId = config.parentId) + .content.name ?: "" + HomeRowConfigDisplay( + id = id, + title = context.getString(R.string.suggestions_for, name), + config, + ) + } } /** @@ -829,6 +843,39 @@ class HomeSettingsService ) } } + + is HomeRowConfig.Suggestions -> { + val library = + api.userLibraryApi + .getItem(itemId = row.parentId) + .content + val title = context.getString(R.string.suggestions_for, library.name ?: "") + val itemKind = SuggestionsWorker.getTypeForCollection(library.collectionType) + val suggestions = + itemKind?.let { + suggestionService + .getSuggestionsFlow(row.parentId, itemKind) + .firstOrNull() + } + if (suggestions != null && suggestions is SuggestionsResource.Success) { + Success( + title, + suggestions.items, + row.viewOptions, + ) + } else if (suggestions is SuggestionsResource.Empty) { + Success( + title, + listOf(), + row.viewOptions, + ) + } else { + HomeRowLoadingState.Error( + title, + message = "Unsupported type ${library.collectionType}", + ) + } + } } companion object { diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/SuggestionsWorker.kt b/app/src/main/java/com/github/damontecres/wholphin/services/SuggestionsWorker.kt index 70943f83..5222929e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/SuggestionsWorker.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/SuggestionsWorker.kt @@ -82,11 +82,8 @@ class SuggestionsWorker views .mapNotNull { view -> val itemKind = - when (view.collectionType) { - CollectionType.MOVIES -> BaseItemKind.MOVIE - CollectionType.TVSHOWS -> BaseItemKind.SERIES - else -> return@mapNotNull null - } + getTypeForCollection(view.collectionType) + ?: return@mapNotNull null async(Dispatchers.IO) { runCatching { Timber.v("Fetching suggestions for view %s", view.id) @@ -226,5 +223,12 @@ class SuggestionsWorker const val PARAM_USER_ID = "userId" const val PARAM_SERVER_ID = "serverId" private const val FRESH_CONTENT_RATIO = 0.4 + + fun getTypeForCollection(collectionType: CollectionType?): BaseItemKind? = + when (collectionType) { + CollectionType.MOVIES -> BaseItemKind.MOVIE + CollectionType.TVSHOWS -> BaseItemKind.SERIES + else -> null + } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeLibraryRowTypeList.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeLibraryRowTypeList.kt index ea4ba9e2..c680e077 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeLibraryRowTypeList.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeLibraryRowTypeList.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.unit.dp import androidx.tv.material3.ListItem import androidx.tv.material3.Text import com.github.damontecres.wholphin.R +import com.github.damontecres.wholphin.services.SuggestionsWorker import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.tryRequestFocus @@ -30,6 +31,7 @@ fun HomeLibraryRowTypeList( modifier: Modifier, firstFocus: FocusRequester = remember { FocusRequester() }, ) { + val items = remember(library) { getSupportedRowTypes(library) } LaunchedEffect(Unit) { firstFocus.tryRequestFocus() } Column(modifier = modifier) { TitleText(stringResource(R.string.add_row_for, library.name)) @@ -41,7 +43,7 @@ fun HomeLibraryRowTypeList( .fillMaxHeight() .focusRestorer(firstFocus), ) { - itemsIndexed(LibraryRowType.entries) { index, rowType -> + itemsIndexed(items) { index, rowType -> ListItem( selected = false, headlineContent = { @@ -60,10 +62,20 @@ fun HomeLibraryRowTypeList( } } +fun getSupportedRowTypes(library: Library): List { + val itemKind = SuggestionsWorker.getTypeForCollection(library.collectionType) + return if (itemKind != null) { + LibraryRowType.entries + } else { + LibraryRowType.entries.toMutableList().apply { remove(LibraryRowType.SUGGESTIONS) } + } +} + enum class LibraryRowType( @param:StringRes val stringId: Int, ) { RECENTLY_ADDED(R.string.recently_added), RECENTLY_RELEASED(R.string.recently_released), + SUGGESTIONS(R.string.suggestions), GENRES(R.string.genres), } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt index e2fc85f2..6ebbbf44 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt @@ -13,7 +13,11 @@ import com.github.damontecres.wholphin.data.model.HomePageSettings import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowConfig.ContinueWatching import com.github.damontecres.wholphin.data.model.HomeRowConfig.ContinueWatchingCombined +import com.github.damontecres.wholphin.data.model.HomeRowConfig.Genres import com.github.damontecres.wholphin.data.model.HomeRowConfig.NextUp +import com.github.damontecres.wholphin.data.model.HomeRowConfig.RecentlyAdded +import com.github.damontecres.wholphin.data.model.HomeRowConfig.RecentlyReleased +import com.github.damontecres.wholphin.data.model.HomeRowConfig.Suggestions import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.services.BackdropService import com.github.damontecres.wholphin.services.HomePageResolvedSettings @@ -252,7 +256,7 @@ class HomeSettingsViewModel HomeRowConfigDisplay( id = id, title = title, - config = HomeRowConfig.RecentlyAdded(library.itemId), + config = RecentlyAdded(library.itemId), ) } @@ -267,7 +271,7 @@ class HomeSettingsViewModel HomeRowConfigDisplay( id = id, title = title, - config = HomeRowConfig.RecentlyReleased(library.itemId), + config = RecentlyReleased(library.itemId), ) } @@ -276,7 +280,17 @@ class HomeSettingsViewModel HomeRowConfigDisplay( id = id, title = title, - config = HomeRowConfig.Genres(library.itemId), + config = Genres(library.itemId), + ) + } + + LibraryRowType.SUGGESTIONS -> { + val title = + library.name.let { context.getString(R.string.suggestions_for, it) } + HomeRowConfigDisplay( + id = id, + title = title, + config = Suggestions(library.itemId), ) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd5ceed1..f4509878 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -500,6 +500,7 @@ Overwrite settings on server? Overwrite local settings? For episodes + Suggestions for %1$s Disabled