mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
feat: add unwatched episode count indicators to PosterItems and enhance media item data structure
This commit is contained in:
@@ -106,7 +106,8 @@ class JellyfinApiClient @Inject constructor(
|
|||||||
ItemFields.CHILD_COUNT,
|
ItemFields.CHILD_COUNT,
|
||||||
ItemFields.PARENT_ID,
|
ItemFields.PARENT_ID,
|
||||||
ItemFields.DATE_LAST_REFRESHED,
|
ItemFields.DATE_LAST_REFRESHED,
|
||||||
ItemFields.OVERVIEW
|
ItemFields.OVERVIEW,
|
||||||
|
ItemFields.SEASON_USER_DATA
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun getLibraryContent(libraryId: UUID): List<BaseItemDto> {
|
suspend fun getLibraryContent(libraryId: UUID): List<BaseItemDto> {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package hu.bbara.purefin.common.ui
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@@ -11,6 +12,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
@@ -23,6 +25,8 @@ import androidx.compose.ui.unit.sp
|
|||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
import hu.bbara.purefin.app.home.ui.PosterItem
|
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||||
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
|
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
|
||||||
|
import hu.bbara.purefin.common.ui.components.UnwatchedEpisodeIndicator
|
||||||
|
import hu.bbara.purefin.common.ui.components.WatchStateIndicator
|
||||||
import org.jellyfin.sdk.model.UUID
|
import org.jellyfin.sdk.model.UUID
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
|
|
||||||
@@ -62,17 +66,39 @@ fun PosterCard(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(posterWidth)
|
.width(posterWidth)
|
||||||
) {
|
) {
|
||||||
PurefinAsyncImage(
|
Box() {
|
||||||
model = imageRequest,
|
PurefinAsyncImage(
|
||||||
contentDescription = null,
|
model = imageRequest,
|
||||||
modifier = Modifier
|
contentDescription = null,
|
||||||
.aspectRatio(2f / 3f)
|
modifier = Modifier
|
||||||
.clip(RoundedCornerShape(14.dp))
|
.aspectRatio(2f / 3f)
|
||||||
.border(1.dp, scheme.outlineVariant.copy(alpha = 0.3f), RoundedCornerShape(14.dp))
|
.clip(RoundedCornerShape(14.dp))
|
||||||
.background(scheme.surfaceVariant)
|
.border(1.dp, scheme.outlineVariant.copy(alpha = 0.3f), RoundedCornerShape(14.dp))
|
||||||
.clickable(onClick = { openItem(item) }),
|
.background(scheme.surfaceVariant)
|
||||||
contentScale = ContentScale.Crop
|
.clickable(onClick = { openItem(item) }),
|
||||||
)
|
contentScale = ContentScale.Crop
|
||||||
|
)
|
||||||
|
when (item.type) {
|
||||||
|
BaseItemKind.MOVIE -> WatchStateIndicator(
|
||||||
|
modifier = Modifier.align(Alignment.TopEnd)
|
||||||
|
.padding(8.dp),
|
||||||
|
watched = item.movie!!.watched,
|
||||||
|
started = (item.movie.progress ?: 0.0) > 0
|
||||||
|
)
|
||||||
|
BaseItemKind.EPISODE -> WatchStateIndicator(
|
||||||
|
modifier = Modifier.align(Alignment.TopEnd)
|
||||||
|
.padding(8.dp),
|
||||||
|
watched = item.episode!!.watched,
|
||||||
|
started = (item.episode.progress ?: 0.0) > 0
|
||||||
|
)
|
||||||
|
BaseItemKind.SERIES -> UnwatchedEpisodeIndicator(
|
||||||
|
modifier = Modifier.align(Alignment.TopEnd)
|
||||||
|
.padding(8.dp),
|
||||||
|
unwatchedCount = item.series!!.unwatchedEpisodeCount
|
||||||
|
)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
Text(
|
Text(
|
||||||
text = item.title,
|
text = item.title,
|
||||||
color = scheme.onBackground,
|
color = scheme.onBackground,
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package hu.bbara.purefin.common.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UnwatchedEpisodeIndicator(
|
||||||
|
unwatchedCount: Int,
|
||||||
|
foregroundColor: Color = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
backgroundColor: Color = MaterialTheme.colorScheme.primary,
|
||||||
|
size: Int = 24,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
if (unwatchedCount == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = modifier
|
||||||
|
.border(1.dp, backgroundColor.copy(alpha = 0.8f), CircleShape)
|
||||||
|
.background(backgroundColor.copy(alpha = 0.8f), CircleShape)
|
||||||
|
.size(size.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = unwatchedCount.toString(),
|
||||||
|
color = foregroundColor.copy(alpha = 0.8f),
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -364,6 +364,7 @@ class InMemoryMediaRepository @Inject constructor(
|
|||||||
itemId = this.id,
|
itemId = this.id,
|
||||||
type = ImageType.PRIMARY
|
type = ImageType.PRIMARY
|
||||||
),
|
),
|
||||||
|
unwatchedEpisodeCount = this.userData!!.unplayedItemCount!!,
|
||||||
seasonCount = this.childCount!!,
|
seasonCount = this.childCount!!,
|
||||||
seasons = emptyList(),
|
seasons = emptyList(),
|
||||||
cast = emptyList()
|
cast = emptyList()
|
||||||
@@ -376,6 +377,7 @@ class InMemoryMediaRepository @Inject constructor(
|
|||||||
seriesId = this.seriesId!!,
|
seriesId = this.seriesId!!,
|
||||||
name = this.name ?: "Unknown",
|
name = this.name ?: "Unknown",
|
||||||
index = this.indexNumber!!,
|
index = this.indexNumber!!,
|
||||||
|
unwatchedEpisodeCount = this.userData!!.unplayedItemCount!!,
|
||||||
episodeCount = this.childCount!!,
|
episodeCount = this.childCount!!,
|
||||||
episodes = emptyList()
|
episodes = emptyList()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ class RoomMediaLocalDataSource @Inject constructor(
|
|||||||
synopsis = synopsis,
|
synopsis = synopsis,
|
||||||
year = year,
|
year = year,
|
||||||
heroImageUrl = heroImageUrl,
|
heroImageUrl = heroImageUrl,
|
||||||
|
unwatchedEpisodeCount = unwatchedEpisodeCount,
|
||||||
seasonCount = seasonCount
|
seasonCount = seasonCount
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -169,6 +170,7 @@ class RoomMediaLocalDataSource @Inject constructor(
|
|||||||
seriesId = seriesId,
|
seriesId = seriesId,
|
||||||
name = name,
|
name = name,
|
||||||
index = index,
|
index = index,
|
||||||
|
unwatchedEpisodeCount = unwatchedEpisodeCount,
|
||||||
episodeCount = episodeCount
|
episodeCount = episodeCount
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -212,6 +214,7 @@ class RoomMediaLocalDataSource @Inject constructor(
|
|||||||
synopsis = synopsis,
|
synopsis = synopsis,
|
||||||
year = year,
|
year = year,
|
||||||
heroImageUrl = heroImageUrl,
|
heroImageUrl = heroImageUrl,
|
||||||
|
unwatchedEpisodeCount = unwatchedEpisodeCount,
|
||||||
seasonCount = seasonCount,
|
seasonCount = seasonCount,
|
||||||
seasons = seasons,
|
seasons = seasons,
|
||||||
cast = cast
|
cast = cast
|
||||||
@@ -222,6 +225,7 @@ class RoomMediaLocalDataSource @Inject constructor(
|
|||||||
seriesId = seriesId,
|
seriesId = seriesId,
|
||||||
name = name,
|
name = name,
|
||||||
index = index,
|
index = index,
|
||||||
|
unwatchedEpisodeCount = unwatchedEpisodeCount,
|
||||||
episodeCount = episodeCount,
|
episodeCount = episodeCount,
|
||||||
episodes = episodes
|
episodes = episodes
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,5 +23,6 @@ data class SeasonEntity(
|
|||||||
val seriesId: UUID,
|
val seriesId: UUID,
|
||||||
val name: String,
|
val name: String,
|
||||||
val index: Int,
|
val index: Int,
|
||||||
|
val unwatchedEpisodeCount: Int,
|
||||||
val episodeCount: Int
|
val episodeCount: Int
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,5 +12,6 @@ data class SeriesEntity(
|
|||||||
val synopsis: String,
|
val synopsis: String,
|
||||||
val year: String,
|
val year: String,
|
||||||
val heroImageUrl: String,
|
val heroImageUrl: String,
|
||||||
|
val unwatchedEpisodeCount: Int,
|
||||||
val seasonCount: Int
|
val seasonCount: Int
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ data class Season(
|
|||||||
val seriesId: UUID,
|
val seriesId: UUID,
|
||||||
val name: String,
|
val name: String,
|
||||||
val index: Int,
|
val index: Int,
|
||||||
|
val unwatchedEpisodeCount: Int,
|
||||||
val episodeCount: Int,
|
val episodeCount: Int,
|
||||||
val episodes: List<Episode>
|
val episodes: List<Episode>
|
||||||
)
|
) {
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ data class Series(
|
|||||||
val synopsis: String,
|
val synopsis: String,
|
||||||
val year: String,
|
val year: String,
|
||||||
val heroImageUrl: String,
|
val heroImageUrl: String,
|
||||||
|
val unwatchedEpisodeCount: Int,
|
||||||
val seasonCount: Int,
|
val seasonCount: Int,
|
||||||
val seasons: List<Season>,
|
val seasons: List<Season>,
|
||||||
val cast: List<CastMember>
|
val cast: List<CastMember>
|
||||||
)
|
) {
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user