feat(home): Refactor HomeCatalogRowSection and HomeContinueWatchingSection for dynamic padding and layout adjustments

This commit is contained in:
tapframe 2026-04-01 19:23:00 +05:30
parent fc5a078f73
commit ae95c9d004
4 changed files with 134 additions and 70 deletions

View file

@ -1,8 +1,10 @@
package com.nuvio.app.features.home.components
import androidx.compose.foundation.layout.BoxWithConstraints
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
@ -20,24 +22,27 @@ fun HomeCatalogRowSection(
onPosterClick: ((MetaPreview) -> Unit)? = null,
onPosterLongClick: ((MetaPreview) -> Unit)? = null,
) {
NuvioShelfSection(
title = section.title,
entries = entries,
modifier = modifier,
headerHorizontalPadding = 16.dp,
rowContentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 16.dp),
onViewAllClick = onViewAllClick,
viewAllPillSize = NuvioViewAllPillSize.Compact,
key = { item -> item.stableKey() },
) { item ->
HomePosterCard(
item = item,
isWatched = WatchingState.isPosterWatched(
watchedKeys = watchedKeys,
BoxWithConstraints(modifier = modifier.fillMaxWidth()) {
val sectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value)
NuvioShelfSection(
title = section.title,
entries = entries,
modifier = Modifier.fillMaxWidth(),
headerHorizontalPadding = sectionPadding,
rowContentPadding = PaddingValues(horizontal = sectionPadding),
onViewAllClick = onViewAllClick,
viewAllPillSize = NuvioViewAllPillSize.Compact,
key = { item -> item.stableKey() },
) { item ->
HomePosterCard(
item = item,
),
onClick = onPosterClick?.let { { it(item) } },
onLongClick = onPosterLongClick?.let { { it(item) } },
)
isWatched = WatchingState.isPosterWatched(
watchedKeys = watchedKeys,
item = item,
),
onClick = onPosterClick?.let { { it(item) } },
onLongClick = onPosterLongClick?.let { { it(item) } },
)
}
}
}

View file

@ -56,12 +56,13 @@ fun HomeContinueWatchingSection(
BoxWithConstraints(modifier = modifier.fillMaxWidth()) {
val layout = rememberContinueWatchingLayout(maxWidth.value)
val sectionPadding = homeSectionHorizontalPaddingForWidth(maxWidth.value)
NuvioShelfSection(
title = "Continue Watching",
entries = items,
modifier = Modifier.fillMaxWidth(),
headerHorizontalPadding = layout.sectionPadding,
rowContentPadding = PaddingValues(horizontal = layout.sectionPadding),
headerHorizontalPadding = sectionPadding,
rowContentPadding = PaddingValues(horizontal = sectionPadding),
itemSpacing = layout.itemGap,
key = { item -> item.videoId },
) { item ->
@ -460,7 +461,6 @@ private fun UpNextBadge(
}
private data class ContinueWatchingLayout(
val sectionPadding: Dp,
val itemGap: Dp,
val wideCardWidth: Dp,
val wideCardHeight: Dp,
@ -482,7 +482,6 @@ private data class ContinueWatchingLayout(
private fun rememberContinueWatchingLayout(maxWidthDp: Float): ContinueWatchingLayout =
when {
maxWidthDp >= 1440f -> ContinueWatchingLayout(
sectionPadding = 32.dp,
itemGap = 20.dp,
wideCardWidth = 400.dp,
wideCardHeight = 160.dp,
@ -501,7 +500,6 @@ private fun rememberContinueWatchingLayout(maxWidthDp: Float): ContinueWatchingL
posterBadgeTextSize = 12.sp,
)
maxWidthDp >= 1024f -> ContinueWatchingLayout(
sectionPadding = 28.dp,
itemGap = 18.dp,
wideCardWidth = 350.dp,
wideCardHeight = 140.dp,
@ -520,7 +518,6 @@ private fun rememberContinueWatchingLayout(maxWidthDp: Float): ContinueWatchingL
posterBadgeTextSize = 10.sp,
)
maxWidthDp >= 768f -> ContinueWatchingLayout(
sectionPadding = 24.dp,
itemGap = 16.dp,
wideCardWidth = 320.dp,
wideCardHeight = 130.dp,
@ -539,7 +536,6 @@ private fun rememberContinueWatchingLayout(maxWidthDp: Float): ContinueWatchingL
posterBadgeTextSize = 10.sp,
)
else -> ContinueWatchingLayout(
sectionPadding = 16.dp,
itemGap = 16.dp,
wideCardWidth = 280.dp,
wideCardHeight = 120.dp,

View file

@ -0,0 +1,12 @@
package com.nuvio.app.features.home.components
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
internal fun homeSectionHorizontalPaddingForWidth(maxWidthDp: Float): Dp =
when {
maxWidthDp >= 1440f -> 32.dp
maxWidthDp >= 1024f -> 28.dp
maxWidthDp >= 768f -> 24.dp
else -> 16.dp
}

View file

@ -10,6 +10,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -22,6 +23,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
@ -89,7 +91,7 @@ fun ProfileSelectionScreen(
val statusBarTop = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
Box(
BoxWithConstraints(
modifier = modifier
.fillMaxSize()
.background(
@ -103,14 +105,23 @@ fun ProfileSelectionScreen(
)
.padding(top = statusBarTop),
) {
val isTabletLayout = maxWidth >= 768.dp
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.then(
if (isTabletLayout) {
Modifier
} else {
Modifier.verticalScroll(rememberScrollState())
},
)
.padding(horizontal = 24.dp),
verticalArrangement = if (isTabletLayout) Arrangement.Center else Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Spacer(modifier = Modifier.height(60.dp))
Spacer(modifier = Modifier.height(if (isTabletLayout) 0.dp else 60.dp))
Text(
text = "Who's watching?",
@ -126,52 +137,92 @@ fun ProfileSelectionScreen(
},
)
Spacer(modifier = Modifier.height(48.dp))
Spacer(modifier = Modifier.height(if (isTabletLayout) 28.dp else 48.dp))
val profiles = profileState.profiles
val items = profiles.size + if (profiles.size < 4) 1 else 0
Column(
verticalArrangement = Arrangement.spacedBy(20.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth(),
) {
var index = 0
while (index < items) {
if (isTabletLayout) {
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(20.dp, Alignment.CenterHorizontally),
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.horizontalScroll(rememberScrollState())
.padding(horizontal = 4.dp),
horizontalArrangement = Arrangement.spacedBy(20.dp),
) {
for (col in 0..1) {
if (index < items) {
val currentIndex = index
if (currentIndex < profiles.size) {
val profile = profiles[currentIndex]
ProfileAvatarCard(
profile = profile,
isEditMode = isEditMode,
animDelay = currentIndex * 80,
onClick = {
if (isEditMode) {
onEditProfile(profile)
} else if (profile.pinEnabled) {
pinDialogProfile = profile
} else {
ProfileRepository.selectProfile(profile.profileIndex)
onProfileSelected(profile)
}
},
)
} else {
AddProfileCard(
animDelay = currentIndex * 80,
onClick = onAddProfile,
)
}
index++
for (currentIndex in 0 until items) {
if (currentIndex < profiles.size) {
val profile = profiles[currentIndex]
ProfileAvatarCard(
profile = profile,
isEditMode = isEditMode,
animDelay = currentIndex * 80,
onClick = {
if (isEditMode) {
onEditProfile(profile)
} else if (profile.pinEnabled) {
pinDialogProfile = profile
} else {
ProfileRepository.selectProfile(profile.profileIndex)
onProfileSelected(profile)
}
},
)
} else {
if (profiles.isNotEmpty()) {
Spacer(modifier = Modifier.width(150.dp))
AddProfileCard(
animDelay = currentIndex * 80,
onClick = onAddProfile,
)
}
}
}
}
} else {
Column(
verticalArrangement = Arrangement.spacedBy(20.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth(),
) {
var index = 0
while (index < items) {
Row(
horizontalArrangement = Arrangement.spacedBy(20.dp, Alignment.CenterHorizontally),
modifier = Modifier.fillMaxWidth(),
) {
for (col in 0..1) {
if (index < items) {
val currentIndex = index
if (currentIndex < profiles.size) {
val profile = profiles[currentIndex]
ProfileAvatarCard(
profile = profile,
isEditMode = isEditMode,
animDelay = currentIndex * 80,
onClick = {
if (isEditMode) {
onEditProfile(profile)
} else if (profile.pinEnabled) {
pinDialogProfile = profile
} else {
ProfileRepository.selectProfile(profile.profileIndex)
onProfileSelected(profile)
}
},
)
} else {
AddProfileCard(
animDelay = currentIndex * 80,
onClick = onAddProfile,
)
}
index++
} else {
if (profiles.isNotEmpty()) {
Spacer(modifier = Modifier.width(150.dp))
}
}
}
}
@ -179,7 +230,7 @@ fun ProfileSelectionScreen(
}
}
Spacer(modifier = Modifier.height(48.dp))
Spacer(modifier = Modifier.height(if (isTabletLayout) 28.dp else 48.dp))
Box(
modifier = Modifier
@ -207,7 +258,7 @@ fun ProfileSelectionScreen(
)
}
Spacer(modifier = Modifier.height(32.dp))
Spacer(modifier = Modifier.height(if (isTabletLayout) 0.dp else 32.dp))
}
}