mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-16 23:12:12 +00:00
fix: patch remaining areas generating duplicate keys
This commit is contained in:
parent
0a663560d8
commit
8a58fabfdd
11 changed files with 66 additions and 26 deletions
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.nuvio.app.core.ui
|
||||||
|
|
||||||
|
internal data class DuplicateSafeLazyEntry<T>(
|
||||||
|
val value: T,
|
||||||
|
val lazyKey: Any,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun <T> List<T>.withDuplicateSafeLazyKeys(key: (T) -> Any): List<DuplicateSafeLazyEntry<T>> {
|
||||||
|
val keyCounts = groupingBy(key).eachCount()
|
||||||
|
val occurrences = mutableMapOf<Any, Int>()
|
||||||
|
|
||||||
|
return map { entry ->
|
||||||
|
val baseKey = key(entry)
|
||||||
|
val lazyKey = if (keyCounts[baseKey] == 1) {
|
||||||
|
baseKey
|
||||||
|
} else {
|
||||||
|
val occurrence = occurrences.getOrElse(baseKey) { 0 }
|
||||||
|
occurrences[baseKey] = occurrence + 1
|
||||||
|
"$baseKey#$occurrence"
|
||||||
|
}
|
||||||
|
DuplicateSafeLazyEntry(value = entry, lazyKey = lazyKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -82,10 +82,10 @@ fun <T> NuvioShelfSection(
|
||||||
) {
|
) {
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
items(
|
items(
|
||||||
items = entries,
|
items = entries.withDuplicateSafeLazyKeys(key),
|
||||||
key = key,
|
key = { entry -> entry.lazyKey },
|
||||||
) { entry ->
|
) { keyedEntry ->
|
||||||
itemContent(entry)
|
itemContent(keyedEntry.value)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
items(entries) { entry ->
|
items(entries) { entry ->
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ import com.nuvio.app.core.ui.NuvioBackButton
|
||||||
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
||||||
import com.nuvio.app.core.ui.posterCardClickable
|
import com.nuvio.app.core.ui.posterCardClickable
|
||||||
import com.nuvio.app.core.ui.nuvioSafeBottomPadding
|
import com.nuvio.app.core.ui.nuvioSafeBottomPadding
|
||||||
|
import com.nuvio.app.core.ui.withDuplicateSafeLazyKeys
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
import com.nuvio.app.features.home.PosterShape
|
import com.nuvio.app.features.home.PosterShape
|
||||||
import com.nuvio.app.features.home.stableKey
|
import com.nuvio.app.features.home.stableKey
|
||||||
|
|
@ -175,9 +176,10 @@ fun CatalogScreen(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
items(
|
items(
|
||||||
items = uiState.items,
|
items = uiState.items.withDuplicateSafeLazyKeys { item -> item.stableKey() },
|
||||||
key = { item -> item.stableKey() },
|
key = { item -> item.lazyKey },
|
||||||
) { item ->
|
) { keyedItem ->
|
||||||
|
val item = keyedItem.value
|
||||||
CatalogPosterTile(
|
CatalogPosterTile(
|
||||||
item = item,
|
item = item,
|
||||||
cornerRadiusDp = posterCardStyle.cornerRadiusDp,
|
cornerRadiusDp = posterCardStyle.cornerRadiusDp,
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import com.nuvio.app.core.ui.NuvioPosterCard
|
||||||
import com.nuvio.app.core.ui.NuvioPosterShape
|
import com.nuvio.app.core.ui.NuvioPosterShape
|
||||||
import com.nuvio.app.core.ui.NuvioScreenHeader
|
import com.nuvio.app.core.ui.NuvioScreenHeader
|
||||||
import com.nuvio.app.core.ui.nuvioSafeBottomPadding
|
import com.nuvio.app.core.ui.nuvioSafeBottomPadding
|
||||||
|
import com.nuvio.app.core.ui.withDuplicateSafeLazyKeys
|
||||||
import com.nuvio.app.features.home.HomeCatalogSection
|
import com.nuvio.app.features.home.HomeCatalogSection
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
import com.nuvio.app.features.home.PosterShape
|
import com.nuvio.app.features.home.PosterShape
|
||||||
|
|
@ -275,9 +276,10 @@ private fun TabbedGridContent(
|
||||||
verticalArrangement = Arrangement.spacedBy(14.dp),
|
verticalArrangement = Arrangement.spacedBy(14.dp),
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = selectedTab.items,
|
items = selectedTab.items.withDuplicateSafeLazyKeys { item -> item.stableKey() },
|
||||||
key = { item -> item.stableKey() },
|
key = { item -> item.lazyKey },
|
||||||
) { item ->
|
) { keyedItem ->
|
||||||
|
val item = keyedItem.value
|
||||||
NuvioPosterCard(
|
NuvioPosterCard(
|
||||||
title = item.name,
|
title = item.name,
|
||||||
imageUrl = item.poster,
|
imageUrl = item.poster,
|
||||||
|
|
@ -326,9 +328,10 @@ private fun RowsContent(
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = sections,
|
items = sections.withDuplicateSafeLazyKeys { it.key },
|
||||||
key = { it.key },
|
key = { it.lazyKey },
|
||||||
) { section ->
|
) { keyedSection ->
|
||||||
|
val section = keyedSection.value
|
||||||
HomeCatalogRowSection(
|
HomeCatalogRowSection(
|
||||||
section = section,
|
section = section,
|
||||||
entries = section.items.take(18),
|
entries = section.items.take(18),
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ 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 androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.nuvio.app.core.ui.withDuplicateSafeLazyKeys
|
||||||
import com.nuvio.app.features.trakt.TraktCommentReview
|
import com.nuvio.app.features.trakt.TraktCommentReview
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import nuvio.composeapp.generated.resources.*
|
import nuvio.composeapp.generated.resources.*
|
||||||
|
|
@ -122,7 +123,11 @@ fun DetailCommentsSection(
|
||||||
state = listState,
|
state = listState,
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
items(comments, key = { it.id }) { review ->
|
items(
|
||||||
|
items = comments.withDuplicateSafeLazyKeys { it.id },
|
||||||
|
key = { it.lazyKey },
|
||||||
|
) { keyedReview ->
|
||||||
|
val review = keyedReview.value
|
||||||
CommentCard(
|
CommentCard(
|
||||||
review = review,
|
review = review,
|
||||||
onClick = { onCommentClick(review) },
|
onClick = { onCommentClick(review) },
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
|
@ -582,7 +583,10 @@ private fun EpisodeHorizontalRow(
|
||||||
contentPadding = PaddingValues(horizontal = rowMetrics.rowHorizontalPadding, vertical = rowMetrics.rowVerticalPadding),
|
contentPadding = PaddingValues(horizontal = rowMetrics.rowHorizontalPadding, vertical = rowMetrics.rowVerticalPadding),
|
||||||
horizontalArrangement = Arrangement.spacedBy(rowMetrics.itemSpacing),
|
horizontalArrangement = Arrangement.spacedBy(rowMetrics.itemSpacing),
|
||||||
) {
|
) {
|
||||||
items(episodes, key = { it.id }) { episode ->
|
itemsIndexed(
|
||||||
|
items = episodes,
|
||||||
|
key = { index, episode -> "${episode.season}:${episode.episode}:${episode.id}#$index" },
|
||||||
|
) { _, episode ->
|
||||||
val episodeVideoId = buildPlaybackVideoId(
|
val episodeVideoId = buildPlaybackVideoId(
|
||||||
parentMetaId = parentMetaId,
|
parentMetaId = parentMetaId,
|
||||||
seasonNumber = episode.season,
|
seasonNumber = episode.season,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ExpandMore
|
import androidx.compose.material.icons.filled.ExpandMore
|
||||||
|
|
@ -158,10 +158,10 @@ fun DetailTrailersSection(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.spacedBy(sizing.cardSpacing),
|
horizontalArrangement = Arrangement.spacedBy(sizing.cardSpacing),
|
||||||
) {
|
) {
|
||||||
items(
|
itemsIndexed(
|
||||||
items = selectedTrailers,
|
items = selectedTrailers,
|
||||||
key = { trailer -> "${trailer.type}-${trailer.id}-${trailer.seasonNumber ?: 0}" },
|
key = { index, trailer -> "${trailer.type}-${trailer.id}-${trailer.seasonNumber ?: 0}#$index" },
|
||||||
) { trailer ->
|
) { _, trailer ->
|
||||||
TrailerCard(
|
TrailerCard(
|
||||||
trailer = trailer,
|
trailer = trailer,
|
||||||
cardWidth = sizing.cardWidth,
|
cardWidth = sizing.cardWidth,
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,10 @@ private fun EpisodesListSubView(
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
contentPadding = androidx.compose.foundation.layout.PaddingValues(bottom = 16.dp),
|
contentPadding = androidx.compose.foundation.layout.PaddingValues(bottom = 16.dp),
|
||||||
) {
|
) {
|
||||||
items(seasonEpisodes, key = { "${it.season}:${it.episode}:${it.id}" }) { episode ->
|
itemsIndexed(
|
||||||
|
items = seasonEpisodes,
|
||||||
|
key = { index, episode -> "${episode.season}:${episode.episode}:${episode.id}#$index" },
|
||||||
|
) { _, episode ->
|
||||||
val isCurrent = episode.season == currentSeason && episode.episode == currentEpisode
|
val isCurrent = episode.season == currentSeason && episode.episode == currentEpisode
|
||||||
EpisodeRow(
|
EpisodeRow(
|
||||||
episode = episode,
|
episode = episode,
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ import com.nuvio.app.core.ui.NuvioInputField
|
||||||
import com.nuvio.app.core.ui.NuvioScreen
|
import com.nuvio.app.core.ui.NuvioScreen
|
||||||
import com.nuvio.app.core.ui.NuvioNetworkOfflineCard
|
import com.nuvio.app.core.ui.NuvioNetworkOfflineCard
|
||||||
import com.nuvio.app.core.ui.NuvioScreenHeader
|
import com.nuvio.app.core.ui.NuvioScreenHeader
|
||||||
|
import com.nuvio.app.core.ui.withDuplicateSafeLazyKeys
|
||||||
import com.nuvio.app.features.addons.AddonRepository
|
import com.nuvio.app.features.addons.AddonRepository
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
import com.nuvio.app.features.home.components.HomeCatalogRowSection
|
import com.nuvio.app.features.home.components.HomeCatalogRowSection
|
||||||
|
|
@ -303,9 +304,10 @@ fun SearchScreen(
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
items(
|
items(
|
||||||
items = uiState.sections,
|
items = uiState.sections.withDuplicateSafeLazyKeys { section -> section.key },
|
||||||
key = { section -> section.key },
|
key = { section -> section.lazyKey },
|
||||||
) { section ->
|
) { keyedSection ->
|
||||||
|
val section = keyedSection.value
|
||||||
HomeCatalogRowSection(
|
HomeCatalogRowSection(
|
||||||
section = section,
|
section = section,
|
||||||
modifier = Modifier.padding(bottom = 12.dp),
|
modifier = Modifier.padding(bottom = 12.dp),
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
CURRENT_PROJECT_VERSION=48
|
CURRENT_PROJECT_VERSION=48
|
||||||
MARKETING_VERSION=0.1.12
|
MARKETING_VERSION=0.1.0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
shouldAutocreateTestPlan = "YES">
|
shouldAutocreateTestPlan = "YES">
|
||||||
<Testables>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue