Refactor media selection logic to use a unified onMediaSelected callback

Consolidates specific media selection callbacks (`onMovieSelected`, `onSeriesSelected`, `onEpisodeSelected`) into a single `onMediaSelected` handler that accepts a `MediaUiModel`. This simplifies the interface between the ViewModel and UI components across both mobile and TV screens, moving the type-checking logic into `AppViewModel`.
This commit is contained in:
2026-04-20 20:08:38 +02:00
parent a9b0f771f8
commit a39581682f
14 changed files with 54 additions and 129 deletions

View File

@@ -76,9 +76,7 @@ fun TvAppScreen(
libraryContent = latestLibraryContent,
continueWatching = continueWatching,
nextUp = nextUp,
onMovieSelected = viewModel::onMovieSelected,
onSeriesSelected = viewModel::onSeriesSelected,
onEpisodeSelected = viewModel::onEpisodeSelected,
onMediaSelected = viewModel::onMediaSelected,
modifier = Modifier.fillMaxSize()
)
}

View File

@@ -24,9 +24,7 @@ fun TvHomeScreen(
libraryContent: Map<UUID, List<MediaUiModel>>,
continueWatching: List<MediaUiModel>,
nextUp: List<MediaUiModel>,
onMovieSelected: (UUID) -> Unit,
onSeriesSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier,
) {
val scheme = MaterialTheme.colorScheme
@@ -53,9 +51,7 @@ fun TvHomeScreen(
onMediaFocused = {
focusedMediaUiModel.value = it
},
onMovieSelected = onMovieSelected,
onSeriesSelected = onSeriesSelected,
onEpisodeSelected = onEpisodeSelected,
onMediaSelected = onMediaSelected,
modifier = Modifier
.weight(1f)
.fillMaxWidth()

View File

@@ -37,9 +37,7 @@ fun TvHomeContent(
continueWatching: List<MediaUiModel>,
nextUp: List<MediaUiModel>,
onMediaFocused: (MediaUiModel) -> Unit,
onMovieSelected: (UUID) -> Unit,
onSeriesSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
contentPadding: PaddingValues = PaddingValues(bottom = 32.dp),
modifier: Modifier = Modifier,
) {
@@ -81,8 +79,7 @@ fun TvHomeContent(
TvContinueWatchingSection(
items = continueWatching,
onFocusedItem = onMediaFocused,
onMovieSelected = onMovieSelected,
onEpisodeSelected = onEpisodeSelected,
onMediaSelected = onMediaSelected,
firstItemFocusRequester = initialFocusRequester,
firstItemTestTag = TvHomeInitialFocusTag,
rowTestTag = TvHomeContinueWatchingRowTag
@@ -95,7 +92,7 @@ fun TvHomeContent(
TvNextUpSection(
items = nextUp,
onFocusedItem = onMediaFocused,
onEpisodeSelected = onEpisodeSelected,
onMediaSelected = onMediaSelected,
firstItemFocusRequester = initialFocusRequester.takeIf { !hasContinueWatching },
firstItemTestTag = TvHomeInitialFocusTag.takeIf { !hasContinueWatching },
rowTestTag = TvHomeNextUpRowTag
@@ -115,9 +112,7 @@ fun TvHomeContent(
!hasContinueWatching && !hasNextUp && library.id == firstLibraryWithItemsId
},
firstItemTestTag = tvHomeLibraryFirstItemTag(library.id),
onMovieSelected = onMovieSelected,
onSeriesSelected = onSeriesSelected,
onEpisodeSelected = onEpisodeSelected
onMediaSelected = onMediaSelected
)
}

View File

@@ -44,10 +44,9 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.core.ui.model.EpisodeUiModel
import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.ui.common.bar.MediaProgressBar
import hu.bbara.purefin.ui.common.card.PosterCard
import hu.bbara.purefin.ui.common.card.PosterCardContent
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import java.util.UUID
import kotlin.math.roundToInt
@@ -83,8 +82,7 @@ internal fun tvHomeLibraryFirstItemTag(libraryId: UUID): String =
fun TvContinueWatchingSection(
items: List<MediaUiModel>,
onFocusedItem: (MediaUiModel) -> Unit = {},
onMovieSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
firstItemFocusRequester: FocusRequester? = null,
firstItemTestTag: String? = null,
rowTestTag: String? = null,
@@ -120,13 +118,7 @@ fun TvContinueWatchingSection(
}
),
onFocusedItem = { onFocusedItem(item) },
onClick = {
when (item) {
//TODO fix this shit
is EpisodeUiModel -> onEpisodeSelected(item.seriesId, item.seasonId, item.id)
else -> Unit
}
}
onClick = { onMediaSelected(item) }
)
}
}
@@ -136,7 +128,7 @@ fun TvContinueWatchingSection(
fun TvNextUpSection(
items: List<MediaUiModel>,
onFocusedItem: (MediaUiModel) -> Unit = {},
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
firstItemFocusRequester: FocusRequester? = null,
firstItemTestTag: String? = null,
rowTestTag: String? = null,
@@ -171,12 +163,7 @@ fun TvNextUpSection(
}
),
onFocusedItem = { onFocusedItem(item) },
onClick = {
//TODO FIX
(item as? EpisodeUiModel)?.let { episode ->
onEpisodeSelected(episode.seriesId, episode.seasonId, episode.id)
}
}
onClick = { onMediaSelected(item) }
)
}
}
@@ -191,9 +178,7 @@ fun TvLibraryPosterSection(
firstItemTestTag: String? = null,
rowTestTag: String? = null,
modifier: Modifier = Modifier,
onMovieSelected: (UUID) -> Unit,
onSeriesSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
) {
TvSectionHeader(
title = title,
@@ -203,8 +188,9 @@ fun TvLibraryPosterSection(
rowTestTag = rowTestTag
) {
itemsIndexed(items = items, key = { _, item -> item.id }) { index, item ->
PosterCard(
item = item,
PosterCardContent(
model = item,
onClick = { onMediaSelected(item) },
posterWidth = TvHomePosterCardWidth,
contentScale = TvHomeMediaCardScale,
showSecondaryText = true,
@@ -225,10 +211,9 @@ fun TvLibraryPosterSection(
Modifier
}
),
onFocusedItem = onFocusedItem,
onMovieSelected = onMovieSelected,
onSeriesSelected = onSeriesSelected,
onEpisodeSelected = onEpisodeSelected
onFocused = { onFocusedItem(item) },
focusedScale = 1.07f,
focusedBorderWidth = 2.dp
)
}
}

View File

@@ -52,9 +52,7 @@ fun AppScreen(
nextUp = nextUp,
isRefreshing = isRefreshing,
onRefresh = viewModel::onRefresh,
onMovieSelected = viewModel::onMovieSelected,
onSeriesSelected = viewModel::onSeriesSelected,
onEpisodeSelected = viewModel::onEpisodeSelected,
onMediaSelected = viewModel::onMediaSelected,
onLibrarySelected = { library ->
viewModel.onLibrarySelected(
library.id,

View File

@@ -30,9 +30,7 @@ fun HomeScreen(
nextUp: List<MediaUiModel>,
isRefreshing: Boolean,
onRefresh: () -> Unit,
onMovieSelected: (UUID) -> Unit,
onSeriesSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
onLibrarySelected: (LibraryItem) -> Unit,
onProfileClick: () -> Unit,
onSettingsClick: () -> Unit,
@@ -72,9 +70,7 @@ fun HomeScreen(
nextUp = nextUp,
isRefreshing = isRefreshing,
onRefresh = onRefresh,
onMovieSelected = onMovieSelected,
onSeriesSelected = onSeriesSelected,
onEpisodeSelected = onEpisodeSelected,
onMediaSelected = onMediaSelected,
onLibrarySelected = onLibrarySelected,
onBrowseLibrariesClick = { onTabSelected(1) },
modifier = Modifier.padding(innerPadding)
@@ -85,11 +81,12 @@ fun HomeScreen(
onDismiss = { isSearchVisible = false },
onMovieSelected = {
isSearchVisible = false
onMovieSelected(it)
//TODO use MediaUiModel as well
//onMovieSelected(it)
},
onSeriesSelected = {
isSearchVisible = false
onSeriesSelected(it)
//onSeriesSelected(it)
},
modifier = Modifier
.fillMaxSize()

View File

@@ -21,10 +21,7 @@ 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.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.ui.screen.home.components.continuewatching.ContinueWatchingSection
import hu.bbara.purefin.ui.screen.home.components.featured.SuggestionsSection
@@ -42,9 +39,7 @@ fun HomeContent(
nextUp: List<MediaUiModel>,
isRefreshing: Boolean,
onRefresh: () -> Unit,
onMovieSelected: (UUID) -> Unit,
onSeriesSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
onLibrarySelected: (LibraryItem) -> Unit,
onBrowseLibrariesClick: () -> Unit,
modifier: Modifier = Modifier
@@ -101,13 +96,7 @@ fun HomeContent(
item(key = "featured") {
SuggestionsSection(
items = suggestions,
onItemOpen = { item ->
when (item) {
is MovieUiModel -> onMovieSelected(item.id)
is SeriesUiModel -> onSeriesSelected(item.id)
is EpisodeUiModel -> onEpisodeSelected(item.id, item.id, item.id)
}
}
onItemOpen = { item -> onMediaSelected(item) }
)
}
}
@@ -116,8 +105,7 @@ fun HomeContent(
item(key = "continue-watching") {
ContinueWatchingSection(
items = continueWatching,
onMovieSelected = onMovieSelected,
onEpisodeSelected = onEpisodeSelected
onMediaSelected = onMediaSelected
)
}
}
@@ -126,7 +114,7 @@ fun HomeContent(
item(key = "next-up") {
NextUpSection(
items = nextUp,
onEpisodeSelected = onEpisodeSelected
onMediaSelected = onMediaSelected
)
}
}
@@ -139,9 +127,7 @@ fun HomeContent(
library = library,
items = libraryContent[library.id].orEmpty(),
onLibrarySelected = onLibrarySelected,
onMovieSelected = onMovieSelected,
onSeriesSelected = onSeriesSelected,
onEpisodeSelected = onEpisodeSelected
onMediaSelected = onMediaSelected
)
}

View File

@@ -23,18 +23,14 @@ 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.EpisodeUiModel
import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.core.ui.model.MovieUiModel
import hu.bbara.purefin.ui.common.bar.MediaProgressBar
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import java.util.UUID
@Composable
internal fun ContinueWatchingCard(
item: MediaUiModel,
onMovieSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier
) {
val scheme = MaterialTheme.colorScheme
@@ -47,14 +43,7 @@ internal fun ContinueWatchingCard(
Column(
modifier = Modifier
.fillMaxWidth()
.clickable {
// TODO fix this shit as well
when (item) {
is MovieUiModel -> onMovieSelected(item.id)
is EpisodeUiModel -> onEpisodeSelected(item.seriesId, item.seasonId, item.id)
else -> Unit
}
}
.clickable { onMediaSelected(item) }
) {
Box(
modifier = Modifier

View File

@@ -11,13 +11,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.ui.common.header.SectionHeader
import java.util.UUID
@Composable
fun ContinueWatchingSection(
items: List<MediaUiModel>,
onMovieSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier
) {
if (items.isEmpty()) return
@@ -35,8 +33,7 @@ fun ContinueWatchingSection(
items(items = items, key = { item -> item.id }) { item ->
ContinueWatchingCard(
item = item,
onMovieSelected = onMovieSelected,
onEpisodeSelected = onEpisodeSelected
onMediaSelected = onMediaSelected
)
}
}

View File

@@ -26,17 +26,13 @@ import androidx.compose.ui.unit.dp
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.ui.common.badge.WatchStateBadge
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import java.util.UUID
@Composable
internal fun HomeBrowseCard(
uiModel: MediaUiModel,
onMovieSelected: (UUID) -> Unit,
onSeriesSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier
) {
val scheme = MaterialTheme.colorScheme
@@ -49,14 +45,7 @@ internal fun HomeBrowseCard(
Column(
modifier = Modifier
.fillMaxWidth()
.clickable {
//TODO fix this shit
when (uiModel) {
is MovieUiModel -> onMovieSelected(uiModel.id)
is SeriesUiModel -> onSeriesSelected(uiModel.id)
is EpisodeUiModel -> onEpisodeSelected(uiModel.seriesId, uiModel.seasonId, uiModel.id)
}
}
.clickable { onMediaSelected(uiModel) }
) {
Box(
modifier = Modifier

View File

@@ -12,16 +12,13 @@ import androidx.compose.ui.unit.dp
import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.ui.common.header.SectionHeader
import java.util.UUID
@Composable
fun LibraryPosterSection(
library: LibraryItem,
items: List<MediaUiModel>,
onLibrarySelected: (LibraryItem) -> Unit,
onMovieSelected: (UUID) -> Unit,
onSeriesSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier,
) {
if (items.isEmpty()) return
@@ -43,9 +40,7 @@ fun LibraryPosterSection(
items(items = items, key = { item -> item.id }) { item ->
HomeBrowseCard(
uiModel = item,
onMovieSelected = onMovieSelected,
onSeriesSelected = onSeriesSelected,
onEpisodeSelected = onEpisodeSelected
onMediaSelected = onMediaSelected
)
}
}

View File

@@ -22,15 +22,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.EpisodeUiModel
import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import java.util.UUID
@Composable
internal fun NextUpCard(
uiModel: MediaUiModel,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier
) {
val scheme = MaterialTheme.colorScheme
@@ -43,13 +41,7 @@ internal fun NextUpCard(
Column(
modifier = Modifier
.fillMaxWidth()
.clickable {
// TODO fix this shit
when (uiModel) {
is EpisodeUiModel -> onEpisodeSelected(uiModel.seriesId, uiModel.seasonId, uiModel.id)
else -> Unit
}
}
.clickable { onMediaSelected(uiModel) }
) {
Box(
modifier = Modifier

View File

@@ -11,12 +11,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import hu.bbara.purefin.core.ui.model.MediaUiModel
import hu.bbara.purefin.ui.common.header.SectionHeader
import java.util.UUID
@Composable
fun NextUpSection(
items: List<MediaUiModel>,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
onMediaSelected: (MediaUiModel) -> Unit,
modifier: Modifier = Modifier
) {
if (items.isEmpty()) return
@@ -34,7 +33,7 @@ fun NextUpSection(
items(items = items, key = { item -> item.id }) { item ->
NextUpCard(
uiModel = item,
onEpisodeSelected = onEpisodeSelected
onMediaSelected = onMediaSelected
)
}
}

View File

@@ -16,6 +16,7 @@ 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.MediaUiModel
import hu.bbara.purefin.core.ui.model.MovieUiModel
import hu.bbara.purefin.core.ui.model.SeriesUiModel
import kotlinx.coroutines.flow.MutableStateFlow
@@ -165,7 +166,15 @@ class AppViewModel @Inject constructor(
}
}
fun onMovieSelected(movieId: UUID) {
fun onMediaSelected(mediaUiModel : MediaUiModel) {
when (mediaUiModel) {
is MovieUiModel -> onMovieSelected(mediaUiModel.id)
is SeriesUiModel -> onSeriesSelected(mediaUiModel.id)
is EpisodeUiModel -> onEpisodeSelected(mediaUiModel.seriesId, mediaUiModel.seasonId, mediaUiModel.id)
}
}
private fun onMovieSelected(movieId: UUID) {
navigationManager.navigate(Route.MovieRoute(
MovieDto(
id = movieId,
@@ -173,7 +182,7 @@ class AppViewModel @Inject constructor(
))
}
fun onSeriesSelected(seriesId: UUID) {
private fun onSeriesSelected(seriesId: UUID) {
viewModelScope.launch {
navigationManager.navigate(Route.SeriesRoute(
SeriesDto(
@@ -183,7 +192,7 @@ class AppViewModel @Inject constructor(
}
}
fun onEpisodeSelected(seriesId: UUID, seasonId: UUID, episodeId: UUID) {
private fun onEpisodeSelected(seriesId: UUID, seasonId: UUID, episodeId: UUID) {
viewModelScope.launch {
navigationManager.navigate(Route.EpisodeRoute(
EpisodeDto(