Only show the latest media on the HomePage

This commit is contained in:
2026-01-17 22:21:44 +01:00
parent 3bd8d423d2
commit 71080198c4
4 changed files with 101 additions and 28 deletions

View File

@@ -26,19 +26,21 @@ class HomePageViewModel @Inject constructor(
private val jellyfinApiClient: JellyfinApiClient
) : ViewModel() {
init {
loadHomePageData()
}
private val _continueWatching = MutableStateFlow<List<ContinueWatchingItem>>(emptyList())
val continueWatching = _continueWatching.asStateFlow()
private val _libraries = MutableStateFlow<List<LibraryItem>>(emptyList())
val libraries = _libraries.asStateFlow()
private val _libraryContent = MutableStateFlow<Map<UUID, List<PosterItem>>>(emptyMap())
val libraryContent = _libraryContent.asStateFlow()
private val _libraryItems = MutableStateFlow<Map<UUID, List<PosterItem>>>(emptyMap())
val libraryItems = _libraryItems.asStateFlow()
private val _latestLibraryContent = MutableStateFlow<Map<UUID, List<PosterItem>>>(emptyMap())
val latestLibraryContent = _latestLibraryContent.asStateFlow()
init {
loadHomePageData()
}
fun loadContinueWatching() {
viewModelScope.launch {
@@ -68,34 +70,84 @@ class HomePageViewModel @Inject constructor(
fun loadLibraries() {
viewModelScope.launch {
val libraries: List<BaseItemDto> = jellyfinApiClient.getLibraries()
val mappedLibraries = libraries.map {
LibraryItem(
name = it.name!!,
id = it.id
)
loadLibrariesInternal()
}
}
private suspend fun loadLibrariesInternal() {
val libraries: List<BaseItemDto> = jellyfinApiClient.getLibraries()
val mappedLibraries = libraries.map {
LibraryItem(
name = it.name!!,
id = it.id
)
}
_libraries.value = mappedLibraries
}
fun loadAllLibraryItems() {
viewModelScope.launch {
if (_libraries.value.isEmpty()) {
loadLibrariesInternal()
}
_libraries.value = mappedLibraries
mappedLibraries.forEach { library ->
loadLibrary(library.id)
_libraries.value.forEach { library ->
loadLibraryItems(library.id)
}
}
}
fun loadLibrary(libraryId: UUID) {
if (_libraryContent.value.containsKey(libraryId)) return
private fun loadLibraryItems(libraryId: UUID) {
viewModelScope.launch {
val libraryItems = jellyfinApiClient.getLibrary(libraryId)
val posterItems = libraryItems.map {
val libraryItems: List<BaseItemDto> = jellyfinApiClient.getLibrary(libraryId)
val libraryPosterItems = libraryItems.map {
PosterItem(
id = it.id,
title = it.name ?: "Unknown",
colors = listOf(Color.Blue, Color.Cyan),
isLatest = false
title = it.name ?: "Unknown"
)
}
_libraryContent.update { currentMap ->
currentMap + (libraryId to posterItems)
_libraryItems.update { currentMap ->
currentMap + (libraryId to libraryPosterItems)
}
}
}
fun loadAllShownLibraryItems() {
viewModelScope.launch {
if (_libraries.value.isEmpty()) {
loadLibrariesInternal()
}
_libraries.value.forEach { library ->
loadLatestLibraryItems(library.id)
}
}
}
fun loadLatestLibraryItems(libraryId: UUID) {
if (_libraryItems.value.containsKey(libraryId)) return
val libraryItems = _libraryItems.value[libraryId]
viewModelScope.launch {
val latestLibraryItems = jellyfinApiClient.getLatestFromLibrary(libraryId)
val latestLibraryPosterItem = latestLibraryItems.mapNotNull {
when (it.type) {
BaseItemKind.MOVIE -> PosterItem(
id = it.id,
title = it.name ?: "Unknown"
)
BaseItemKind.EPISODE -> PosterItem(
id = it.seriesId!!,
title = it.seriesName ?: "Unknown"
)
BaseItemKind.SEASON -> PosterItem(
id = it.seriesId!!,
title = it.seriesName ?: "Unknown"
)
else -> null
}
}
_latestLibraryContent.update { currentMap ->
currentMap + (libraryId to latestLibraryPosterItem)
}
}
}
@@ -103,6 +155,8 @@ class HomePageViewModel @Inject constructor(
fun loadHomePageData() {
loadContinueWatching()
loadLibraries()
loadAllLibraryItems()
loadAllShownLibraryItems()
}
fun logout() {

View File

@@ -23,7 +23,7 @@ fun HomeContent(
) {
val libraries by viewModel.libraries.collectAsState()
val libraryContent by viewModel.libraryContent.collectAsState()
val libraryContent by viewModel.latestLibraryContent.collectAsState()
LazyColumn(
modifier = modifier

View File

@@ -19,9 +19,7 @@ data class LibraryItem(
data class PosterItem(
val id: UUID,
val title: String,
val isLatest: Boolean,
val colors: List<Color>
val title: String
)
data class HomeNavItem(

View File

@@ -10,6 +10,7 @@ import org.jellyfin.sdk.api.client.extensions.authenticateUserByName
import org.jellyfin.sdk.api.client.extensions.itemsApi
import org.jellyfin.sdk.api.client.extensions.libraryApi
import org.jellyfin.sdk.api.client.extensions.userApi
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
import org.jellyfin.sdk.createJellyfin
import org.jellyfin.sdk.model.ClientInfo
import org.jellyfin.sdk.model.api.BaseItemDto
@@ -115,4 +116,24 @@ class JellyfinApiClient @Inject constructor(
return response.content.items
}
/**
* Fetches the latest media items from a specified library including Movie, Episode, Season.
*
* @param libraryId The UUID of the library to fetch from
* @return A list of [BaseItemDto] representing the latest media items that includes Movie, Episode, Season, or an empty list if not configured
*/
suspend fun getLatestFromLibrary(libraryId: UUID): List<BaseItemDto> {
if (!ensureConfigured()) {
return emptyList()
}
val response = api.userLibraryApi.getLatestMedia(
userId = getUserId(),
parentId = libraryId,
includeItemTypes = listOf(BaseItemKind.MOVIE, BaseItemKind.EPISODE, BaseItemKind.SEASON),
limit = 10
)
Log.d("getLatestFromLibrary response: {}", response.content.toString())
return response.content
}
}