refactor: Use MediaUiModel instead of SuggestedItem

This commit is contained in:
2026-04-20 19:51:13 +02:00
parent 18e352eb1e
commit a9b0f771f8
6 changed files with 38 additions and 125 deletions

View File

@@ -14,7 +14,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import hu.bbara.purefin.core.ui.model.MediaUiModel import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.feature.browse.home.LibraryItem import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.feature.browse.home.SuggestedItem
import hu.bbara.purefin.ui.screen.AppBottomBar import hu.bbara.purefin.ui.screen.AppBottomBar
import hu.bbara.purefin.ui.screen.home.components.HomeContent import hu.bbara.purefin.ui.screen.home.components.HomeContent
import hu.bbara.purefin.ui.screen.home.components.HomeTopBar import hu.bbara.purefin.ui.screen.home.components.HomeTopBar
@@ -26,7 +25,7 @@ import java.util.UUID
fun HomeScreen( fun HomeScreen(
libraries: List<LibraryItem>, libraries: List<LibraryItem>,
libraryContent: Map<UUID, List<MediaUiModel>>, libraryContent: Map<UUID, List<MediaUiModel>>,
suggestions: List<SuggestedItem>, suggestions: List<MediaUiModel>,
continueWatching: List<MediaUiModel>, continueWatching: List<MediaUiModel>,
nextUp: List<MediaUiModel>, nextUp: List<MediaUiModel>,
isRefreshing: Boolean, isRefreshing: Boolean,

View File

@@ -1,6 +1,5 @@
package hu.bbara.purefin.ui.screen.home.components package hu.bbara.purefin.ui.screen.home.components
import android.util.Log
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@@ -22,10 +21,11 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.core.model.MediaKind import hu.bbara.purefin.core.ui.model.EpisodeUiModel
import hu.bbara.purefin.core.ui.model.MediaUiModel import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.core.ui.model.MovieUiModel
import hu.bbara.purefin.core.ui.model.SeriesUiModel
import hu.bbara.purefin.feature.browse.home.LibraryItem import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.feature.browse.home.SuggestedItem
import hu.bbara.purefin.ui.screen.home.components.continuewatching.ContinueWatchingSection import hu.bbara.purefin.ui.screen.home.components.continuewatching.ContinueWatchingSection
import hu.bbara.purefin.ui.screen.home.components.featured.SuggestionsSection import hu.bbara.purefin.ui.screen.home.components.featured.SuggestionsSection
import hu.bbara.purefin.ui.screen.home.components.library.LibraryPosterSection import hu.bbara.purefin.ui.screen.home.components.library.LibraryPosterSection
@@ -37,7 +37,7 @@ import java.util.UUID
fun HomeContent( fun HomeContent(
libraries: List<LibraryItem>, libraries: List<LibraryItem>,
libraryContent: Map<UUID, List<MediaUiModel>>, libraryContent: Map<UUID, List<MediaUiModel>>,
suggestions: List<SuggestedItem>, suggestions: List<MediaUiModel>,
continueWatching: List<MediaUiModel>, continueWatching: List<MediaUiModel>,
nextUp: List<MediaUiModel>, nextUp: List<MediaUiModel>,
isRefreshing: Boolean, isRefreshing: Boolean,
@@ -102,13 +102,10 @@ fun HomeContent(
SuggestionsSection( SuggestionsSection(
items = suggestions, items = suggestions,
onItemOpen = { item -> onItemOpen = { item ->
when (item.type) { when (item) {
MediaKind.MOVIE -> onMovieSelected(item.id) is MovieUiModel -> onMovieSelected(item.id)
MediaKind.SERIES -> onSeriesSelected(item.id) is SeriesUiModel -> onSeriesSelected(item.id)
MediaKind.EPISODE -> onEpisodeSelected(item.id, item.id, item.id) is EpisodeUiModel -> onEpisodeSelected(item.id, item.id, item.id)
else -> {
Log.e("HomeContent", "Unsupported item type: ${item.type}")
}
} }
} }
) )

View File

@@ -24,13 +24,13 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.ui.common.bar.MediaProgressBar import hu.bbara.purefin.ui.common.bar.MediaProgressBar
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import hu.bbara.purefin.feature.browse.home.SuggestedItem
@Composable @Composable
internal fun SuggestionCard( internal fun SuggestionCard(
item: SuggestedItem, item: MediaUiModel,
onClick: () -> Unit, onClick: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
@@ -51,8 +51,8 @@ internal fun SuggestionCard(
.aspectRatio(16f / 11f) .aspectRatio(16f / 11f)
) { ) {
PurefinAsyncImage( PurefinAsyncImage(
model = item.imageUrl, model = item.primaryImageUrl,
contentDescription = item.title, contentDescription = item.primaryText,
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )
@@ -77,23 +77,20 @@ internal fun SuggestionCard(
) { ) {
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
Text( Text(
text = item.title, text = item.primaryText,
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
color = Color.White, color = Color.White,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
maxLines = 2, maxLines = 2,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
if (item.metadata.isNotEmpty()) {
Text( Text(
text = item.metadata.joinToString(""), text = item.secondaryText,
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = Color.White.copy(alpha = 0.88f), color = Color.White.copy(alpha = 0.88f),
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
}
if (description.isNotBlank()) {
Text( Text(
text = description, text = description,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
@@ -104,7 +101,6 @@ internal fun SuggestionCard(
) )
} }
} }
}
if (item.progress != null && item.progress!! > 0f) { if (item.progress != null && item.progress!! > 0f) {
MediaProgressBar( MediaProgressBar(
progress = item.progress!!.coerceIn(0f, 1f), progress = item.progress!!.coerceIn(0f, 1f),

View File

@@ -22,12 +22,12 @@ import androidx.compose.runtime.LaunchedEffect
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.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.feature.browse.home.SuggestedItem import hu.bbara.purefin.core.ui.model.MediaUiModel
@Composable @Composable
fun SuggestionsSection( fun SuggestionsSection(
items: List<SuggestedItem>, items: List<MediaUiModel>,
onItemOpen: (SuggestedItem) -> Unit, onItemOpen: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
if (items.isEmpty()) return if (items.isEmpty()) return

View File

@@ -7,17 +7,17 @@ import hu.bbara.purefin.core.data.HomeRepository
import hu.bbara.purefin.core.data.MediaCatalogReader import hu.bbara.purefin.core.data.MediaCatalogReader
import hu.bbara.purefin.core.data.session.UserSessionRepository import hu.bbara.purefin.core.data.session.UserSessionRepository
import hu.bbara.purefin.core.download.MediaDownloadController import hu.bbara.purefin.core.download.MediaDownloadController
import hu.bbara.purefin.core.ui.model.EpisodeUiModel
import hu.bbara.purefin.core.model.LibraryKind import hu.bbara.purefin.core.model.LibraryKind
import hu.bbara.purefin.core.model.Media import hu.bbara.purefin.core.model.Media
import hu.bbara.purefin.core.ui.model.MovieUiModel
import hu.bbara.purefin.core.ui.model.SeriesUiModel
import hu.bbara.purefin.core.navigation.EpisodeDto import hu.bbara.purefin.core.navigation.EpisodeDto
import hu.bbara.purefin.core.navigation.LibraryDto import hu.bbara.purefin.core.navigation.LibraryDto
import hu.bbara.purefin.core.navigation.MovieDto import hu.bbara.purefin.core.navigation.MovieDto
import hu.bbara.purefin.core.navigation.NavigationManager import hu.bbara.purefin.core.navigation.NavigationManager
import hu.bbara.purefin.core.navigation.Route import hu.bbara.purefin.core.navigation.Route
import hu.bbara.purefin.core.navigation.SeriesDto import hu.bbara.purefin.core.navigation.SeriesDto
import hu.bbara.purefin.core.ui.model.EpisodeUiModel
import hu.bbara.purefin.core.ui.model.MovieUiModel
import hu.bbara.purefin.core.ui.model.SeriesUiModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -72,13 +72,13 @@ class AppViewModel @Inject constructor(
list.mapNotNull { media -> list.mapNotNull { media ->
when (media) { when (media) {
is Media.MovieMedia -> moviesMap[media.movieId]?.let { is Media.MovieMedia -> moviesMap[media.movieId]?.let {
SuggestedMovie(movie = it) MovieUiModel(movie = it)
} }
is Media.SeriesMedia -> seriesMap[media.seriesId]?.let { is Media.SeriesMedia -> seriesMap[media.seriesId]?.let {
SuggestedSeries(series = it) SeriesUiModel(series = it)
} }
is Media.EpisodeMedia -> episodesMap[media.episodeId]?.let { is Media.EpisodeMedia -> episodesMap[media.episodeId]?.let {
SuggestedEpisode(episode = it) EpisodeUiModel(episode = it)
} }
else -> null else -> null
} }

View File

@@ -9,85 +9,6 @@ import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.core.model.Series import hu.bbara.purefin.core.model.Series
import java.util.UUID import java.util.UUID
sealed interface SuggestedItem {
val id: UUID
val badge: String
val title: String
val supportingText: String
val description: String
val metadata: List<String>
val imageUrl: String
val ctaLabel: String
val progress: Float?
val type: MediaKind
}
data class SuggestedEpisode (
val episode: Episode,
override val badge: String = "",
override val supportingText: String = listOf("Episode ${episode.index}", episode.runtime)
.filter { it.isNotBlank() }
.joinToString(""),
override val metadata: List<String> =
listOf(episode.releaseDate, episode.runtime, episode.rating, episode.format)
.filter { it.isNotBlank() },
override val ctaLabel: String = "Open",
override val progress: Float? = episode.progress?.toFloat(),
override val type: MediaKind = MediaKind.EPISODE,
override val id: UUID = episode.id,
override val title: String = episode.title,
override val description: String = episode.synopsis,
override val imageUrl: String = ImageUrlBuilder.finishImageUrl(
prefixImageUrl = episode.imageUrlPrefix,
artworkKind = ArtworkKind.PRIMARY
)
) : SuggestedItem
data class SuggestedSeries (
val series: Series,
override val badge: String = "",
override val supportingText: String =
if (series.unwatchedEpisodeCount > 0) {
"${series.unwatchedEpisodeCount} unwatched episodes"
} else {
"${series.seasonCount} seasons"
},
override val metadata: List<String> =
listOf(series.year, "${series.seasonCount} seasons").filter { it.isNotBlank() },
override val ctaLabel: String = "Open",
override val progress: Float? = null,
override val type: MediaKind = MediaKind.SERIES,
override val id: UUID = series.id,
override val title: String = series.name,
override val description: String = series.synopsis,
override val imageUrl: String = ImageUrlBuilder.finishImageUrl(
prefixImageUrl = series.imageUrlPrefix,
artworkKind = ArtworkKind.PRIMARY
)
) : SuggestedItem
data class SuggestedMovie (
val movie: Movie,
override val badge: String = "",
override val supportingText: String = listOf(movie.year, movie.runtime)
.filter { it.isNotBlank() }
.joinToString(""),
override val metadata: List<String> =
listOf(movie.year, movie.runtime, movie.rating, movie.format)
.filter { it.isNotBlank() },
override val ctaLabel: String = "Open",
override val progress: Float? = movie.progress?.toFloat(),
override val type: MediaKind = MediaKind.MOVIE,
override val id: UUID = movie.id,
override val title: String = movie.title,
override val description: String = movie.synopsis,
override val imageUrl: String = ImageUrlBuilder.finishImageUrl(
prefixImageUrl = movie.imageUrlPrefix,
artworkKind = ArtworkKind.PRIMARY
)
) : SuggestedItem
sealed interface FocusableItem { sealed interface FocusableItem {
val imageUrl: String val imageUrl: String
val primaryText: String val primaryText: String