From 5a377fc428bd17ca4e1791be9d5a044ef584cc0c Mon Sep 17 00:00:00 2001 From: Barnabas Balogh Date: Fri, 17 Apr 2026 18:02:22 +0200 Subject: [PATCH] Add keys to lazy Compose entries --- .../purefin/ui/screen/episode/TvEpisodeScreen.kt | 8 ++++---- .../ui/screen/home/components/TvHomeContent.kt | 12 ++++++------ .../purefin/ui/screen/library/TvLibraryScreen.kt | 2 +- .../bbara/purefin/ui/screen/movie/TvMovieScreen.kt | 8 ++++---- .../bbara/purefin/ui/screen/series/TvSeriesScreen.kt | 10 +++++----- .../screen/series/components/TvSeriesComponents.kt | 2 +- .../screen/download/components/DownloadsContent.kt | 6 +++--- .../bbara/purefin/ui/screen/library/LibraryScreen.kt | 2 +- .../ui/screen/player/components/PlayerQueuePanel.kt | 2 +- .../ui/screen/series/components/SeriesComponents.kt | 2 +- .../purefin/ui/common/media/MediaDetailComponents.kt | 5 ++++- 11 files changed, 31 insertions(+), 28 deletions(-) diff --git a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/episode/TvEpisodeScreen.kt b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/episode/TvEpisodeScreen.kt index f31be60a..143f376c 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/episode/TvEpisodeScreen.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/episode/TvEpisodeScreen.kt @@ -86,7 +86,7 @@ internal fun TvEpisodeScreenContent( resetScrollKey = episode.id, modifier = modifier ) { - item { + item(key = "episode-hero") { TvMediaDetailBodyBox( backgroundImageUrl = ImageUrlBuilder.finishImageUrl(episode.imageUrlPrefix, ArtworkKind.PRIMARY), modifier = it @@ -101,7 +101,7 @@ internal fun TvEpisodeScreenContent( Spacer(modifier = Modifier.height(12.dp)) } } - item { + item(key = "episode-overview") { Column(modifier = it.fillMaxWidth()) { Spacer(modifier = Modifier.height(16.dp)) MediaDetailOverviewSection( @@ -111,7 +111,7 @@ internal fun TvEpisodeScreenContent( Spacer(modifier = Modifier.height(20.dp)) } } - item { + item(key = "episode-playback") { Column(modifier = it.fillMaxWidth()) { MediaDetailPlaybackSection( audioTrack = "ENG", @@ -122,7 +122,7 @@ internal fun TvEpisodeScreenContent( } } if (episode.cast.isNotEmpty()) { - item { + item(key = "episode-cast") { Column(modifier = it.fillMaxWidth()) { MediaDetailSectionTitle(text = "Cast") Spacer(modifier = Modifier.height(14.dp)) diff --git a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/home/components/TvHomeContent.kt b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/home/components/TvHomeContent.kt index 89e96a76..b1a57467 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/home/components/TvHomeContent.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/home/components/TvHomeContent.kt @@ -84,11 +84,11 @@ fun TvHomeContent( .testTag(TvHomeContentViewportTag), contentPadding = contentPadding ) { - item { + item(key = "tv-home-top-spacer") { Spacer(modifier = Modifier.height(8.dp)) } if (hasContinueWatching) { - item { + item(key = "tv-home-continue-watching") { TvContinueWatchingSection( items = continueWatching, onFocusedItem = onMediaFocused, @@ -102,13 +102,13 @@ fun TvHomeContent( } if (hasContinueWatching && (hasNextUp || hasLibraries)) { - item { + item(key = "tv-home-post-continue-gap") { Spacer(modifier = Modifier.height(20.dp)) } } if (hasNextUp) { - item { + item(key = "tv-home-next-up") { TvNextUpSection( items = nextUp, onFocusedItem = onMediaFocused, @@ -121,7 +121,7 @@ fun TvHomeContent( } if (hasLibraries && (hasContinueWatching || hasNextUp)) { - item { + item(key = "tv-home-post-next-up-gap") { Spacer(modifier = Modifier.height(20.dp)) } } @@ -156,7 +156,7 @@ fun TvHomeContent( } if (hasVisibleContent) { - item { + item(key = "tv-home-trailing-space") { Spacer(modifier = Modifier.height(TvHomeBringIntoViewTrailingSpace)) } } diff --git a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/library/TvLibraryScreen.kt b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/library/TvLibraryScreen.kt index 490bbf10..73bb12ac 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/library/TvLibraryScreen.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/library/TvLibraryScreen.kt @@ -105,7 +105,7 @@ fun TvLibraryContent( verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.background(MaterialTheme.colorScheme.background) ) { - items(libraryItems) { item -> + items(libraryItems, key = { item -> item.id }) { item -> PosterCard( item = item, onMovieSelected = onMovieSelected, diff --git a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/movie/TvMovieScreen.kt b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/movie/TvMovieScreen.kt index 22d96cdb..6a17334a 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/movie/TvMovieScreen.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/movie/TvMovieScreen.kt @@ -64,7 +64,7 @@ internal fun TvMovieScreenContent( resetScrollKey = movie.id, modifier = modifier ) { - item { + item(key = "movie-hero") { TvMediaDetailBodyBox( backgroundImageUrl = tvMediaDetailBackgroundImageUrl(movie.imageUrlPrefix), modifier = it @@ -78,7 +78,7 @@ internal fun TvMovieScreenContent( Spacer(modifier = Modifier.height(12.dp)) } } - item { + item(key = "movie-overview") { Column(modifier = it.fillMaxWidth()) { Spacer(modifier = Modifier.height(16.dp)) MediaDetailOverviewSection( @@ -88,7 +88,7 @@ internal fun TvMovieScreenContent( Spacer(modifier = Modifier.height(20.dp)) } } - item { + item(key = "movie-playback") { Column(modifier = it.fillMaxWidth()) { MediaDetailPlaybackSection( audioTrack = movie.audioTrack, @@ -99,7 +99,7 @@ internal fun TvMovieScreenContent( } } if (movie.cast.isNotEmpty()) { - item { + item(key = "movie-cast") { Column(modifier = it.fillMaxWidth()) { MediaDetailSectionTitle(text = "Cast") Spacer(modifier = Modifier.height(14.dp)) diff --git a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/series/TvSeriesScreen.kt b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/series/TvSeriesScreen.kt index 39f29db9..61570f73 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/series/TvSeriesScreen.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/series/TvSeriesScreen.kt @@ -81,7 +81,7 @@ internal fun TvSeriesScreenContent( resetScrollKey = series.id, modifier = modifier ) { - item { + item(key = "series-hero") { TvMediaDetailBodyBox( backgroundImageUrl = tvMediaDetailBackgroundImageUrl(series.imageUrlPrefix), modifier = it @@ -97,7 +97,7 @@ internal fun TvSeriesScreenContent( Spacer(modifier = Modifier.height(12.dp)) } } - item { + item(key = "series-overview") { Column(modifier = it.fillMaxWidth()) { Spacer(modifier = Modifier.height(16.dp)) MediaDetailOverviewSection( @@ -107,7 +107,7 @@ internal fun TvSeriesScreenContent( Spacer(modifier = Modifier.height(24.dp)) } } - item { + item(key = "series-season-tabs") { TvSeasonTabs( seasons = series.seasons, selectedSeason = selectedSeason, @@ -117,7 +117,7 @@ internal fun TvSeriesScreenContent( modifier = it ) } - item { + item(key = "series-episodes") { Spacer(modifier = Modifier.height(20.dp)) TvEpisodeCarousel( episodes = selectedSeason.episodes, @@ -125,7 +125,7 @@ internal fun TvSeriesScreenContent( ) } if (series.cast.isNotEmpty()) { - item { + item(key = "series-cast") { Column(modifier = it) { Spacer(modifier = Modifier.height(20.dp)) MediaDetailSectionTitle(text = "Cast") diff --git a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/series/components/TvSeriesComponents.kt b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/series/components/TvSeriesComponents.kt index b8c37acc..2be31b49 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/ui/screen/series/components/TvSeriesComponents.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/ui/screen/series/components/TvSeriesComponents.kt @@ -171,7 +171,7 @@ internal fun TvEpisodeCarousel(episodes: List, modifier: Modifier = Mod modifier = modifier, horizontalArrangement = Arrangement.spacedBy(16.dp) ) { - items(episodes) { episode -> + items(episodes, key = { episode -> episode.id }) { episode -> TvEpisodeCard(episode = episode) } } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/download/components/DownloadsContent.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/download/components/DownloadsContent.kt index eddd0f79..9e1e27a5 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/download/components/DownloadsContent.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/download/components/DownloadsContent.kt @@ -65,7 +65,7 @@ fun DownloadsContent( modifier = modifier.background(MaterialTheme.colorScheme.background) ) { if (activeDownloads.value.isNotEmpty()) { - item(span = { GridItemSpan(maxLineSpan) }) { + item(key = "downloading-header", span = { GridItemSpan(maxLineSpan) }) { Text( text = "Downloading", style = MaterialTheme.typography.titleSmall, @@ -84,7 +84,7 @@ fun DownloadsContent( ) } if (downloads.value.isNotEmpty()) { - item(span = { GridItemSpan(maxLineSpan) }) { + item(key = "downloaded-header", span = { GridItemSpan(maxLineSpan) }) { Text( text = "Downloaded", style = MaterialTheme.typography.titleSmall, @@ -95,7 +95,7 @@ fun DownloadsContent( } } } - items(downloads.value) { item -> + items(downloads.value, key = { item -> item.id }) { item -> PosterCard( item = item, onMovieSelected = viewModel::onMovieSelected, diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/library/LibraryScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/library/LibraryScreen.kt index b686d826..0b2d9bad 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/library/LibraryScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/library/LibraryScreen.kt @@ -83,7 +83,7 @@ internal fun LibraryPosterGrid( verticalArrangement = Arrangement.spacedBy(16.dp), modifier = modifier.background(MaterialTheme.colorScheme.background) ) { - items(libraryItems) { item -> + items(libraryItems, key = { item -> item.id }) { item -> PosterCard( item = item, onMovieSelected = viewModel::onMovieSelected, diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/player/components/PlayerQueuePanel.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/player/components/PlayerQueuePanel.kt index 86b05a23..51a23bab 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/player/components/PlayerQueuePanel.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/player/components/PlayerQueuePanel.kt @@ -80,7 +80,7 @@ fun PlayerQueuePanel( exit = fadeOut() ) { LazyColumn(verticalArrangement = Arrangement.spacedBy(10.dp)) { - items(uiState.queue) { item -> + items(uiState.queue, key = { item -> item.id }) { item -> QueueRow( title = item.title, subtitle = item.subtitle, diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/series/components/SeriesComponents.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/series/components/SeriesComponents.kt index 55fa69fd..feb71a53 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/series/components/SeriesComponents.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/series/components/SeriesComponents.kt @@ -304,7 +304,7 @@ internal fun EpisodeCarousel(episodes: List, modifier: Modifier = Modif modifier = modifier, horizontalArrangement = Arrangement.spacedBy(16.dp) ) { - items(episodes) { episode -> + items(episodes, key = { episode -> episode.id }) { episode -> EpisodeCard(episode = episode) } } diff --git a/core/ui/src/main/java/hu/bbara/purefin/ui/common/media/MediaDetailComponents.kt b/core/ui/src/main/java/hu/bbara/purefin/ui/common/media/MediaDetailComponents.kt index f9e75b84..deccbab0 100644 --- a/core/ui/src/main/java/hu/bbara/purefin/ui/common/media/MediaDetailComponents.kt +++ b/core/ui/src/main/java/hu/bbara/purefin/ui/common/media/MediaDetailComponents.kt @@ -79,7 +79,10 @@ fun MediaCastRow( contentPadding = PaddingValues(horizontal = 4.dp), horizontalArrangement = Arrangement.spacedBy(16.dp) ) { - items(cast) { member -> + items( + items = cast, + key = { member -> "${member.name}:${member.role}:${member.imageUrl.orEmpty()}" } + ) { member -> Column(modifier = Modifier.width(cardWidth)) { Box( modifier = Modifier