mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 08:01:20 +02:00
Add option for suggestions row for supported library types
This commit is contained in:
parent
2d77249099
commit
b31c0044fc
6 changed files with 99 additions and 9 deletions
|
|
@ -136,6 +136,18 @@ sealed interface HomeRowConfig {
|
||||||
override fun updateViewOptions(viewOptions: HomeRowViewOptions): TvPrograms = this.copy(viewOptions = viewOptions)
|
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
|
* Fetch by parent ID such as a library, collection, or playlist with optional simple sorting
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import com.github.damontecres.wholphin.util.supportedHomeCollectionTypes
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
@ -64,6 +65,7 @@ class HomeSettingsService
|
||||||
private val navDrawerItemRepository: NavDrawerItemRepository,
|
private val navDrawerItemRepository: NavDrawerItemRepository,
|
||||||
private val latestNextUpService: LatestNextUpService,
|
private val latestNextUpService: LatestNextUpService,
|
||||||
private val imageUrlService: ImageUrlService,
|
private val imageUrlService: ImageUrlService,
|
||||||
|
private val suggestionService: SuggestionService,
|
||||||
) {
|
) {
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
val jsonParser =
|
val jsonParser =
|
||||||
|
|
@ -504,6 +506,18 @@ class HomeSettingsService
|
||||||
config,
|
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 {
|
companion object {
|
||||||
|
|
|
||||||
|
|
@ -82,11 +82,8 @@ class SuggestionsWorker
|
||||||
views
|
views
|
||||||
.mapNotNull { view ->
|
.mapNotNull { view ->
|
||||||
val itemKind =
|
val itemKind =
|
||||||
when (view.collectionType) {
|
getTypeForCollection(view.collectionType)
|
||||||
CollectionType.MOVIES -> BaseItemKind.MOVIE
|
?: return@mapNotNull null
|
||||||
CollectionType.TVSHOWS -> BaseItemKind.SERIES
|
|
||||||
else -> return@mapNotNull null
|
|
||||||
}
|
|
||||||
async(Dispatchers.IO) {
|
async(Dispatchers.IO) {
|
||||||
runCatching {
|
runCatching {
|
||||||
Timber.v("Fetching suggestions for view %s", view.id)
|
Timber.v("Fetching suggestions for view %s", view.id)
|
||||||
|
|
@ -226,5 +223,12 @@ class SuggestionsWorker
|
||||||
const val PARAM_USER_ID = "userId"
|
const val PARAM_USER_ID = "userId"
|
||||||
const val PARAM_SERVER_ID = "serverId"
|
const val PARAM_SERVER_ID = "serverId"
|
||||||
private const val FRESH_CONTENT_RATIO = 0.4
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.tv.material3.ListItem
|
import androidx.tv.material3.ListItem
|
||||||
import androidx.tv.material3.Text
|
import androidx.tv.material3.Text
|
||||||
import com.github.damontecres.wholphin.R
|
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.ifElse
|
||||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
|
|
||||||
|
|
@ -30,6 +31,7 @@ fun HomeLibraryRowTypeList(
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
firstFocus: FocusRequester = remember { FocusRequester() },
|
firstFocus: FocusRequester = remember { FocusRequester() },
|
||||||
) {
|
) {
|
||||||
|
val items = remember(library) { getSupportedRowTypes(library) }
|
||||||
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
TitleText(stringResource(R.string.add_row_for, library.name))
|
TitleText(stringResource(R.string.add_row_for, library.name))
|
||||||
|
|
@ -41,7 +43,7 @@ fun HomeLibraryRowTypeList(
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
.focusRestorer(firstFocus),
|
.focusRestorer(firstFocus),
|
||||||
) {
|
) {
|
||||||
itemsIndexed(LibraryRowType.entries) { index, rowType ->
|
itemsIndexed(items) { index, rowType ->
|
||||||
ListItem(
|
ListItem(
|
||||||
selected = false,
|
selected = false,
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
|
|
@ -60,10 +62,20 @@ fun HomeLibraryRowTypeList(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getSupportedRowTypes(library: Library): List<LibraryRowType> {
|
||||||
|
val itemKind = SuggestionsWorker.getTypeForCollection(library.collectionType)
|
||||||
|
return if (itemKind != null) {
|
||||||
|
LibraryRowType.entries
|
||||||
|
} else {
|
||||||
|
LibraryRowType.entries.toMutableList().apply { remove(LibraryRowType.SUGGESTIONS) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class LibraryRowType(
|
enum class LibraryRowType(
|
||||||
@param:StringRes val stringId: Int,
|
@param:StringRes val stringId: Int,
|
||||||
) {
|
) {
|
||||||
RECENTLY_ADDED(R.string.recently_added),
|
RECENTLY_ADDED(R.string.recently_added),
|
||||||
RECENTLY_RELEASED(R.string.recently_released),
|
RECENTLY_RELEASED(R.string.recently_released),
|
||||||
|
SUGGESTIONS(R.string.suggestions),
|
||||||
GENRES(R.string.genres),
|
GENRES(R.string.genres),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
import com.github.damontecres.wholphin.data.model.HomeRowConfig.ContinueWatching
|
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.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.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.data.model.HomeRowViewOptions
|
||||||
import com.github.damontecres.wholphin.services.BackdropService
|
import com.github.damontecres.wholphin.services.BackdropService
|
||||||
import com.github.damontecres.wholphin.services.HomePageResolvedSettings
|
import com.github.damontecres.wholphin.services.HomePageResolvedSettings
|
||||||
|
|
@ -252,7 +256,7 @@ class HomeSettingsViewModel
|
||||||
HomeRowConfigDisplay(
|
HomeRowConfigDisplay(
|
||||||
id = id,
|
id = id,
|
||||||
title = title,
|
title = title,
|
||||||
config = HomeRowConfig.RecentlyAdded(library.itemId),
|
config = RecentlyAdded(library.itemId),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,7 +271,7 @@ class HomeSettingsViewModel
|
||||||
HomeRowConfigDisplay(
|
HomeRowConfigDisplay(
|
||||||
id = id,
|
id = id,
|
||||||
title = title,
|
title = title,
|
||||||
config = HomeRowConfig.RecentlyReleased(library.itemId),
|
config = RecentlyReleased(library.itemId),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,7 +280,17 @@ class HomeSettingsViewModel
|
||||||
HomeRowConfigDisplay(
|
HomeRowConfigDisplay(
|
||||||
id = id,
|
id = id,
|
||||||
title = title,
|
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),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -500,6 +500,7 @@
|
||||||
<string name="overwrite_server_settings">Overwrite settings on server?</string>
|
<string name="overwrite_server_settings">Overwrite settings on server?</string>
|
||||||
<string name="overwrite_local_settings">Overwrite local settings?</string>
|
<string name="overwrite_local_settings">Overwrite local settings?</string>
|
||||||
<string name="for_episodes">For episodes</string>
|
<string name="for_episodes">For episodes</string>
|
||||||
|
<string name="suggestions_for">Suggestions for %1$s</string>
|
||||||
|
|
||||||
<string-array name="theme_song_volume">
|
<string-array name="theme_song_volume">
|
||||||
<item>Disabled</item>
|
<item>Disabled</item>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue