From 4baa0504dd0d0bf3982cfcf5da316c01889c449c Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:59:58 +0530 Subject: [PATCH] refactor: improve HomeScreen and related components for better layout handling --- .../commonMain/kotlin/com/nuvio/app/App.kt | 117 ++++---- .../com/nuvio/app/features/home/HomeScreen.kt | 249 ++++++++++-------- .../home/components/HomeCatalogSection.kt | 73 +++-- .../components/HomeCollectionRowSection.kt | 50 +++- .../components/HomeContinueWatchingSection.kt | 91 +++++-- 5 files changed, 339 insertions(+), 241 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt index 77fc354a..58fb2fa8 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt @@ -1,7 +1,6 @@ package com.nuvio.app import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -12,7 +11,6 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -43,6 +41,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.saveable.rememberSaveableStateHolder import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.draw.alpha @@ -1427,53 +1426,54 @@ private fun AppTabHost( onFolderClick: ((collectionId: String, folderId: String) -> Unit)? = null, onInitialHomeContentRendered: () -> Unit = {}, ) { + val tabStateHolder = rememberSaveableStateHolder() + Box(modifier = modifier.fillMaxSize()) { - keepAliveTab( - selected = selectedTab == AppScreenTab.Home, - ) { - HomeScreen( - modifier = Modifier.fillMaxSize(), - onCatalogClick = onCatalogClick, - onPosterClick = onPosterClick, - onPosterLongClick = onPosterLongClick, - onContinueWatchingClick = onContinueWatchingClick, - onContinueWatchingLongPress = onContinueWatchingLongPress, - onFolderClick = onFolderClick, - onFirstCatalogRendered = onInitialHomeContentRendered, - ) - } - keepAliveTab( - selected = selectedTab == AppScreenTab.Search, - ) { - SearchScreen( - modifier = Modifier.fillMaxSize(), - onPosterClick = onPosterClick, - onPosterLongClick = onPosterLongClick, - ) - } - keepAliveTab( - selected = selectedTab == AppScreenTab.Library, - ) { - LibraryScreen( - modifier = Modifier.fillMaxSize(), - onPosterClick = onLibraryPosterClick, - onSectionViewAllClick = onLibrarySectionViewAllClick, - ) - } - keepAliveTab( - selected = selectedTab == AppScreenTab.Settings, - ) { - SettingsScreen( - modifier = Modifier.fillMaxSize(), - onSwitchProfile = onSwitchProfile, - onHomescreenClick = onHomescreenSettingsClick, - onMetaScreenClick = onMetaScreenSettingsClick, - onContinueWatchingClick = onContinueWatchingSettingsClick, - onAddonsClick = onAddonsSettingsClick, - onPluginsClick = onPluginsSettingsClick, - onAccountClick = onAccountSettingsClick, - onCollectionsClick = onCollectionsSettingsClick, - ) + tabStateHolder.SaveableStateProvider(selectedTab.name) { + when (selectedTab) { + AppScreenTab.Home -> { + HomeScreen( + modifier = Modifier.fillMaxSize(), + onCatalogClick = onCatalogClick, + onPosterClick = onPosterClick, + onPosterLongClick = onPosterLongClick, + onContinueWatchingClick = onContinueWatchingClick, + onContinueWatchingLongPress = onContinueWatchingLongPress, + onFolderClick = onFolderClick, + onFirstCatalogRendered = onInitialHomeContentRendered, + ) + } + + AppScreenTab.Search -> { + SearchScreen( + modifier = Modifier.fillMaxSize(), + onPosterClick = onPosterClick, + onPosterLongClick = onPosterLongClick, + ) + } + + AppScreenTab.Library -> { + LibraryScreen( + modifier = Modifier.fillMaxSize(), + onPosterClick = onLibraryPosterClick, + onSectionViewAllClick = onLibrarySectionViewAllClick, + ) + } + + AppScreenTab.Settings -> { + SettingsScreen( + modifier = Modifier.fillMaxSize(), + onSwitchProfile = onSwitchProfile, + onHomescreenClick = onHomescreenSettingsClick, + onMetaScreenClick = onMetaScreenSettingsClick, + onContinueWatchingClick = onContinueWatchingSettingsClick, + onAddonsClick = onAddonsSettingsClick, + onPluginsClick = onPluginsSettingsClick, + onAccountClick = onAccountSettingsClick, + onCollectionsClick = onCollectionsSettingsClick, + ) + } + } } } } @@ -1650,24 +1650,3 @@ private fun AppLaunchOverlay( } } } - -@Composable -private fun BoxScope.keepAliveTab( - selected: Boolean, - content: @Composable () -> Unit, -) { - val contentAlpha by animateFloatAsState( - targetValue = if (selected) 1f else 0f, - animationSpec = tween(durationMillis = 220), - label = "tab_content_alpha", - ) - - Box( - modifier = Modifier - .fillMaxSize() - .alpha(contentAlpha) - .zIndex(if (selected) 1f else 0f), - ) { - content() - } -} diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt index 5380ce8f..b82edfec 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt @@ -1,5 +1,7 @@ package com.nuvio.app.features.home +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -45,6 +47,8 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit +import com.nuvio.app.features.home.components.homeSectionHorizontalPaddingForWidth +import com.nuvio.app.features.home.components.rememberContinueWatchingLayout @Composable fun HomeScreen( @@ -286,127 +290,148 @@ fun HomeScreen( onFirstCatalogRendered?.invoke() } - NuvioScreen( - modifier = modifier, - horizontalPadding = 0.dp, - topPadding = if (showHeroSlot) 0.dp else null, - ) { - if (showHeroSlot) { - item { - when { - showHeroSkeleton -> HomeSkeletonHero( - modifier = Modifier, - ) + val visibleCollections = remember(collections) { + collections.filter { it.folders.isNotEmpty() } + } + val collectionsMap = remember(visibleCollections) { + visibleCollections.associateBy { "collection_${it.id}" } + } + val sectionsMap = remember(homeUiState.sections) { + homeUiState.sections.associateBy(HomeCatalogSection::key) + } + val enabledHomeItems = remember(homeSettingsUiState.items) { + homeSettingsUiState.items.filter { it.enabled } + } - homeUiState.heroItems.isNotEmpty() -> HomeHeroSection( - items = homeUiState.heroItems, - modifier = Modifier, - onItemClick = onPosterClick, - ) + BoxWithConstraints(modifier = modifier.fillMaxSize()) { + val homeSectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value) + val continueWatchingLayout = rememberContinueWatchingLayout(maxWidth.value) - else -> HomeHeroReservedSpace(modifier = Modifier) - } - } - } - - when { - addonsUiState.addons.none { it.manifest != null } -> { - if (continueWatchingPreferences.isVisible && continueWatchingItems.isNotEmpty()) { - item { - HomeContinueWatchingSection( - items = continueWatchingItems, - style = continueWatchingPreferences.style, - modifier = Modifier.padding(bottom = 12.dp), - onItemClick = onContinueWatchingClick, - onItemLongPress = onContinueWatchingLongPress, - ) - } - } + NuvioScreen( + modifier = Modifier.fillMaxSize(), + horizontalPadding = 0.dp, + topPadding = if (showHeroSlot) 0.dp else null, + ) { + if (showHeroSlot) { item { - HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), - title = "No active addons", - message = "Install and validate at least one addon before loading catalog rows on Home.", - ) - } - } - - homeUiState.isLoading && homeUiState.sections.isEmpty() -> { - if (continueWatchingPreferences.isVisible && continueWatchingItems.isNotEmpty()) { - item { - HomeContinueWatchingSection( - items = continueWatchingItems, - style = continueWatchingPreferences.style, - modifier = Modifier.padding(bottom = 12.dp), - onItemClick = onContinueWatchingClick, - onItemLongPress = onContinueWatchingLongPress, + when { + showHeroSkeleton -> HomeSkeletonHero( + modifier = Modifier, ) + + homeUiState.heroItems.isNotEmpty() -> HomeHeroSection( + items = homeUiState.heroItems, + modifier = Modifier, + onItemClick = onPosterClick, + ) + + else -> HomeHeroReservedSpace(modifier = Modifier) } } - items(3) { - HomeSkeletonRow(modifier = Modifier.padding(horizontal = 16.dp)) - } } - homeUiState.sections.isEmpty() && homeUiState.heroItems.isEmpty() && - (!continueWatchingPreferences.isVisible || continueWatchingItems.isEmpty()) -> { - item { - HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), - title = "No home rows available", - message = homeUiState.errorMessage - ?: "Installed addons do not currently expose board-compatible catalogs without required extras.", - ) - } - } - - else -> { - if (continueWatchingPreferences.isVisible && continueWatchingItems.isNotEmpty()) { - item { - HomeContinueWatchingSection( - items = continueWatchingItems, - style = continueWatchingPreferences.style, - modifier = Modifier.padding(bottom = 12.dp), - onItemClick = onContinueWatchingClick, - onItemLongPress = onContinueWatchingLongPress, - ) - } - } - - val collectionsMap = collections.filter { it.folders.isNotEmpty() } - .associateBy { "collection_${it.id}" } - val sectionsMap = homeUiState.sections.associateBy { it.key } - val orderedItems = homeSettingsUiState.items.filter { it.enabled } - - orderedItems.forEach { settingsItem -> - if (settingsItem.isCollection) { - val collection = collectionsMap[settingsItem.key] - if (collection != null) { - item(key = settingsItem.key) { - HomeCollectionRowSection( - collection = collection, - modifier = Modifier.padding(bottom = 12.dp), - onFolderClick = onFolderClick, - ) - } + when { + addonsUiState.addons.none { it.manifest != null } -> { + if (continueWatchingPreferences.isVisible && continueWatchingItems.isNotEmpty()) { + item { + HomeContinueWatchingSection( + items = continueWatchingItems, + style = continueWatchingPreferences.style, + modifier = Modifier.padding(bottom = 12.dp), + sectionPadding = homeSectionPadding, + layout = continueWatchingLayout, + onItemClick = onContinueWatchingClick, + onItemLongPress = onContinueWatchingLongPress, + ) } - } else { - val section = sectionsMap[settingsItem.key] - if (section != null && section.items.isNotEmpty()) { - item(key = settingsItem.key) { - HomeCatalogRowSection( - section = section, - entries = section.items.take(HOME_CATALOG_PREVIEW_LIMIT), - modifier = Modifier.padding(bottom = 12.dp), - onViewAllClick = if (section.canOpenCatalog(HOME_CATALOG_PREVIEW_LIMIT)) { - onCatalogClick?.let { { it(section) } } - } else { - null - }, - watchedKeys = watchedUiState.watchedKeys, - onPosterClick = onPosterClick, - onPosterLongClick = onPosterLongClick, - ) + } + item { + HomeEmptyStateCard( + modifier = Modifier.padding(horizontal = 16.dp), + title = "No active addons", + message = "Install and validate at least one addon before loading catalog rows on Home.", + ) + } + } + + homeUiState.isLoading && homeUiState.sections.isEmpty() -> { + if (continueWatchingPreferences.isVisible && continueWatchingItems.isNotEmpty()) { + item { + HomeContinueWatchingSection( + items = continueWatchingItems, + style = continueWatchingPreferences.style, + modifier = Modifier.padding(bottom = 12.dp), + sectionPadding = homeSectionPadding, + layout = continueWatchingLayout, + onItemClick = onContinueWatchingClick, + onItemLongPress = onContinueWatchingLongPress, + ) + } + } + items(3) { + HomeSkeletonRow(modifier = Modifier.padding(horizontal = 16.dp)) + } + } + + homeUiState.sections.isEmpty() && homeUiState.heroItems.isEmpty() && + (!continueWatchingPreferences.isVisible || continueWatchingItems.isEmpty()) -> { + item { + HomeEmptyStateCard( + modifier = Modifier.padding(horizontal = 16.dp), + title = "No home rows available", + message = homeUiState.errorMessage + ?: "Installed addons do not currently expose board-compatible catalogs without required extras.", + ) + } + } + + else -> { + if (continueWatchingPreferences.isVisible && continueWatchingItems.isNotEmpty()) { + item { + HomeContinueWatchingSection( + items = continueWatchingItems, + style = continueWatchingPreferences.style, + modifier = Modifier.padding(bottom = 12.dp), + sectionPadding = homeSectionPadding, + layout = continueWatchingLayout, + onItemClick = onContinueWatchingClick, + onItemLongPress = onContinueWatchingLongPress, + ) + } + } + + enabledHomeItems.forEach { settingsItem -> + if (settingsItem.isCollection) { + val collection = collectionsMap[settingsItem.key] + if (collection != null) { + item(key = settingsItem.key) { + HomeCollectionRowSection( + collection = collection, + modifier = Modifier.padding(bottom = 12.dp), + sectionPadding = homeSectionPadding, + onFolderClick = onFolderClick, + ) + } + } + } else { + val section = sectionsMap[settingsItem.key] + if (section != null && section.items.isNotEmpty()) { + item(key = settingsItem.key) { + HomeCatalogRowSection( + section = section, + entries = section.items.take(HOME_CATALOG_PREVIEW_LIMIT), + modifier = Modifier.padding(bottom = 12.dp), + sectionPadding = homeSectionPadding, + onViewAllClick = if (section.canOpenCatalog(HOME_CATALOG_PREVIEW_LIMIT)) { + onCatalogClick?.let { { it(section) } } + } else { + null + }, + watchedKeys = watchedUiState.watchedKeys, + onPosterClick = onPosterClick, + onPosterLongClick = onPosterLongClick, + ) + } } } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCatalogSection.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCatalogSection.kt index 5d25e1c4..d1b6be59 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCatalogSection.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCatalogSection.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp import com.nuvio.app.core.ui.NuvioShelfSection import com.nuvio.app.core.ui.NuvioViewAllPillSize import com.nuvio.app.features.home.HomeCatalogSection @@ -18,31 +19,67 @@ fun HomeCatalogRowSection( modifier: Modifier = Modifier, entries: List = section.items, watchedKeys: Set = emptySet(), + sectionPadding: Dp? = null, onViewAllClick: (() -> Unit)? = null, onPosterClick: ((MetaPreview) -> Unit)? = null, onPosterLongClick: ((MetaPreview) -> Unit)? = null, ) { - BoxWithConstraints(modifier = modifier.fillMaxWidth()) { - val sectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value) - NuvioShelfSection( - title = section.title, + if (sectionPadding != null) { + HomeCatalogRowSectionContent( + section = section, entries = entries, - modifier = Modifier.fillMaxWidth(), - headerHorizontalPadding = sectionPadding, - rowContentPadding = PaddingValues(horizontal = sectionPadding), + watchedKeys = watchedKeys, + modifier = modifier.fillMaxWidth(), + sectionPadding = sectionPadding, onViewAllClick = onViewAllClick, - viewAllPillSize = NuvioViewAllPillSize.Compact, - key = { item -> item.stableKey() }, - ) { item -> - HomePosterCard( - item = item, - isWatched = WatchingState.isPosterWatched( - watchedKeys = watchedKeys, - item = item, - ), - onClick = onPosterClick?.let { { it(item) } }, - onLongClick = onPosterLongClick?.let { { it(item) } }, + onPosterClick = onPosterClick, + onPosterLongClick = onPosterLongClick, + ) + } else { + BoxWithConstraints(modifier = modifier.fillMaxWidth()) { + HomeCatalogRowSectionContent( + section = section, + entries = entries, + watchedKeys = watchedKeys, + modifier = Modifier.fillMaxWidth(), + sectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value), + onViewAllClick = onViewAllClick, + onPosterClick = onPosterClick, + onPosterLongClick = onPosterLongClick, ) } } } + +@Composable +private fun HomeCatalogRowSectionContent( + section: HomeCatalogSection, + entries: List, + watchedKeys: Set, + modifier: Modifier, + sectionPadding: Dp, + onViewAllClick: (() -> Unit)?, + onPosterClick: ((MetaPreview) -> Unit)?, + onPosterLongClick: ((MetaPreview) -> Unit)?, +) { + NuvioShelfSection( + title = section.title, + entries = entries, + modifier = modifier, + headerHorizontalPadding = sectionPadding, + rowContentPadding = PaddingValues(horizontal = sectionPadding), + onViewAllClick = onViewAllClick, + viewAllPillSize = NuvioViewAllPillSize.Compact, + key = { item -> item.stableKey() }, + ) { item -> + HomePosterCard( + item = item, + isWatched = WatchingState.isPosterWatched( + watchedKeys = watchedKeys, + item = item, + ), + onClick = onPosterClick?.let { { it(item) } }, + onLongClick = onPosterLongClick?.let { { it(item) } }, + ) + } +} diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCollectionRowSection.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCollectionRowSection.kt index 6b9b2d01..4300d3bc 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCollectionRowSection.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCollectionRowSection.kt @@ -34,28 +34,52 @@ import com.nuvio.app.features.home.PosterShape fun HomeCollectionRowSection( collection: Collection, modifier: Modifier = Modifier, + sectionPadding: Dp? = null, onFolderClick: ((collectionId: String, folderId: String) -> Unit)? = null, ) { if (collection.folders.isEmpty()) return - BoxWithConstraints(modifier = modifier.fillMaxWidth()) { - val sectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value) - NuvioShelfSection( - title = collection.title, - entries = collection.folders, - modifier = Modifier.fillMaxWidth(), - headerHorizontalPadding = sectionPadding, - rowContentPadding = PaddingValues(horizontal = sectionPadding), - key = { folder -> "collection_${collection.id}_folder_${folder.id}" }, - ) { folder -> - CollectionFolderCard( - folder = folder, - onClick = onFolderClick?.let { { it(collection.id, folder.id) } }, + if (sectionPadding != null) { + HomeCollectionRowSectionContent( + collection = collection, + modifier = modifier.fillMaxWidth(), + sectionPadding = sectionPadding, + onFolderClick = onFolderClick, + ) + } else { + BoxWithConstraints(modifier = modifier.fillMaxWidth()) { + HomeCollectionRowSectionContent( + collection = collection, + modifier = Modifier.fillMaxWidth(), + sectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value), + onFolderClick = onFolderClick, ) } } } +@Composable +private fun HomeCollectionRowSectionContent( + collection: Collection, + modifier: Modifier, + sectionPadding: Dp, + onFolderClick: ((collectionId: String, folderId: String) -> Unit)?, +) { + NuvioShelfSection( + title = collection.title, + entries = collection.folders, + modifier = modifier, + headerHorizontalPadding = sectionPadding, + rowContentPadding = PaddingValues(horizontal = sectionPadding), + key = { folder -> "collection_${collection.id}_folder_${folder.id}" }, + ) { folder -> + CollectionFolderCard( + folder = folder, + onClick = onFolderClick?.let { { it(collection.id, folder.id) } }, + ) + } +} + @Composable private fun CollectionFolderCard( folder: CollectionFolder, diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeContinueWatchingSection.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeContinueWatchingSection.kt index 1fc81b81..8f25ea42 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeContinueWatchingSection.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeContinueWatchingSection.kt @@ -45,41 +45,74 @@ import com.nuvio.app.features.watchprogress.ContinueWatchingSectionStyle import kotlin.math.roundToInt @Composable -fun HomeContinueWatchingSection( +internal fun HomeContinueWatchingSection( items: List, style: ContinueWatchingSectionStyle, modifier: Modifier = Modifier, + sectionPadding: Dp? = null, + layout: ContinueWatchingLayout? = null, onItemClick: ((ContinueWatchingItem) -> Unit)? = null, onItemLongPress: ((ContinueWatchingItem) -> Unit)? = null, ) { if (items.isEmpty()) return - BoxWithConstraints(modifier = modifier.fillMaxWidth()) { - val layout = rememberContinueWatchingLayout(maxWidth.value) - val sectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value) - NuvioShelfSection( - title = "Continue Watching", - entries = items, - modifier = Modifier.fillMaxWidth(), - headerHorizontalPadding = sectionPadding, - rowContentPadding = PaddingValues(horizontal = sectionPadding), - itemSpacing = layout.itemGap, - key = { item -> item.videoId }, - ) { item -> - when (style) { - ContinueWatchingSectionStyle.Wide -> ContinueWatchingWideCard( - item = item, - layout = layout, - onClick = onItemClick?.let { { it(item) } }, - onLongClick = onItemLongPress?.let { { it(item) } }, - ) - ContinueWatchingSectionStyle.Poster -> ContinueWatchingPosterCard( - item = item, - layout = layout, - onClick = onItemClick?.let { { it(item) } }, - onLongClick = onItemLongPress?.let { { it(item) } }, - ) - } + if (sectionPadding != null && layout != null) { + HomeContinueWatchingSectionContent( + items = items, + style = style, + modifier = modifier.fillMaxWidth(), + sectionPadding = sectionPadding, + layout = layout, + onItemClick = onItemClick, + onItemLongPress = onItemLongPress, + ) + } else { + BoxWithConstraints(modifier = modifier.fillMaxWidth()) { + HomeContinueWatchingSectionContent( + items = items, + style = style, + modifier = Modifier.fillMaxWidth(), + sectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value), + layout = rememberContinueWatchingLayout(maxWidth.value), + onItemClick = onItemClick, + onItemLongPress = onItemLongPress, + ) + } + } +} + +@Composable +private fun HomeContinueWatchingSectionContent( + items: List, + style: ContinueWatchingSectionStyle, + modifier: Modifier, + sectionPadding: Dp, + layout: ContinueWatchingLayout, + onItemClick: ((ContinueWatchingItem) -> Unit)?, + onItemLongPress: ((ContinueWatchingItem) -> Unit)?, +) { + NuvioShelfSection( + title = "Continue Watching", + entries = items, + modifier = modifier, + headerHorizontalPadding = sectionPadding, + rowContentPadding = PaddingValues(horizontal = sectionPadding), + itemSpacing = layout.itemGap, + key = { item -> item.videoId }, + ) { item -> + when (style) { + ContinueWatchingSectionStyle.Wide -> ContinueWatchingWideCard( + item = item, + layout = layout, + onClick = onItemClick?.let { { it(item) } }, + onLongClick = onItemLongPress?.let { { it(item) } }, + ) + ContinueWatchingSectionStyle.Poster -> ContinueWatchingPosterCard( + item = item, + layout = layout, + onClick = onItemClick?.let { { it(item) } }, + onLongClick = onItemLongPress?.let { { it(item) } }, + ) } } } @@ -460,7 +493,7 @@ private fun UpNextBadge( } } -private data class ContinueWatchingLayout( +internal data class ContinueWatchingLayout( val itemGap: Dp, val wideCardWidth: Dp, val wideCardHeight: Dp, @@ -479,7 +512,7 @@ private data class ContinueWatchingLayout( val posterBadgeTextSize: androidx.compose.ui.unit.TextUnit, ) -private fun rememberContinueWatchingLayout(maxWidthDp: Float): ContinueWatchingLayout = +internal fun rememberContinueWatchingLayout(maxWidthDp: Float): ContinueWatchingLayout = when { maxWidthDp >= 1440f -> ContinueWatchingLayout( itemGap = 20.dp,