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 hu.bbara.purefin.core.ui.model.MediaUiModel
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.home.components.HomeContent
import hu.bbara.purefin.ui.screen.home.components.HomeTopBar
@@ -26,7 +25,7 @@ import java.util.UUID
fun HomeScreen(
libraries: List<LibraryItem>,
libraryContent: Map<UUID, List<MediaUiModel>>,
suggestions: List<SuggestedItem>,
suggestions: List<MediaUiModel>,
continueWatching: List<MediaUiModel>,
nextUp: List<MediaUiModel>,
isRefreshing: Boolean,

View File

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

View File

@@ -24,13 +24,13 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
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.image.PurefinAsyncImage
import hu.bbara.purefin.feature.browse.home.SuggestedItem
@Composable
internal fun SuggestionCard(
item: SuggestedItem,
item: MediaUiModel,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
@@ -51,8 +51,8 @@ internal fun SuggestionCard(
.aspectRatio(16f / 11f)
) {
PurefinAsyncImage(
model = item.imageUrl,
contentDescription = item.title,
model = item.primaryImageUrl,
contentDescription = item.primaryText,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
@@ -77,23 +77,20 @@ internal fun SuggestionCard(
) {
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
Text(
text = item.title,
text = item.primaryText,
style = MaterialTheme.typography.headlineMedium,
color = Color.White,
fontWeight = FontWeight.Bold,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
if (item.metadata.isNotEmpty()) {
Text(
text = item.metadata.joinToString(""),
text = item.secondaryText,
style = MaterialTheme.typography.labelLarge,
color = Color.White.copy(alpha = 0.88f),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
if (description.isNotBlank()) {
Text(
text = description,
style = MaterialTheme.typography.bodyMedium,
@@ -104,7 +101,6 @@ internal fun SuggestionCard(
)
}
}
}
if (item.progress != null && item.progress!! > 0f) {
MediaProgressBar(
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.draw.clip
import androidx.compose.ui.unit.dp
import hu.bbara.purefin.feature.browse.home.SuggestedItem
import hu.bbara.purefin.core.ui.model.MediaUiModel
@Composable
fun SuggestionsSection(
items: List<SuggestedItem>,
onItemOpen: (SuggestedItem) -> Unit,
items: List<MediaUiModel>,
onItemOpen: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier
) {
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.session.UserSessionRepository
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.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.LibraryDto
import hu.bbara.purefin.core.navigation.MovieDto
import hu.bbara.purefin.core.navigation.NavigationManager
import hu.bbara.purefin.core.navigation.Route
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.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -72,13 +72,13 @@ class AppViewModel @Inject constructor(
list.mapNotNull { media ->
when (media) {
is Media.MovieMedia -> moviesMap[media.movieId]?.let {
SuggestedMovie(movie = it)
MovieUiModel(movie = it)
}
is Media.SeriesMedia -> seriesMap[media.seriesId]?.let {
SuggestedSeries(series = it)
SeriesUiModel(series = it)
}
is Media.EpisodeMedia -> episodesMap[media.episodeId]?.let {
SuggestedEpisode(episode = it)
EpisodeUiModel(episode = it)
}
else -> null
}

View File

@@ -9,85 +9,6 @@ import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.core.model.Series
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 {
val imageUrl: String
val primaryText: String