From fbcba6fbfcacd3622fbeea688e9b3068685d95e1 Mon Sep 17 00:00:00 2001 From: Barnabas Balogh Date: Sat, 2 May 2026 20:28:54 +0200 Subject: [PATCH] feat(libraries): refactor LibraryListItem and LibraryScreen for improved click handling and layout --- .../libraries/components/LibrariesContent.kt | 5 +- .../libraries/components/LibraryListItem.kt | 59 +++++++--- .../ui/screen/library/LibraryScreen.kt | 107 +++++++++++++++++- 3 files changed, 147 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibrariesContent.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibrariesContent.kt index e680bb5f..480b2a36 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibrariesContent.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibrariesContent.kt @@ -1,6 +1,5 @@ package hu.bbara.purefin.ui.screen.libraries.components -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.lazy.grid.GridCells @@ -27,9 +26,7 @@ fun LibrariesContent( items(items, key = { it.id }) { item -> LibraryListItem( uiModel = item, - modifier = Modifier.clickable { - onLibrarySelected(item) - } + onClick = { onLibrarySelected(item) } ) } } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibraryListItem.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibraryListItem.kt index b8dfa0f6..0785bc6c 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibraryListItem.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibraryListItem.kt @@ -1,15 +1,25 @@ package hu.bbara.purefin.ui.screen.libraries.components +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip 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.ui.common.image.PurefinAsyncImage import hu.bbara.purefin.ui.model.LibraryUiModel @@ -17,21 +27,42 @@ import hu.bbara.purefin.ui.model.LibraryUiModel @Composable fun LibraryListItem( uiModel: LibraryUiModel, + onClick: () -> Unit, modifier: Modifier = Modifier ) { - Column(modifier = modifier.fillMaxWidth()) { - PurefinAsyncImage( - model = uiModel.posterUrl, - contentDescription = uiModel.name, - contentScale = ContentScale.Inside, - modifier = Modifier - .fillMaxWidth() - .height(200.dp) - .clip(RoundedCornerShape(24.dp)) - ) - Text( - text = uiModel.name, - style = MaterialTheme.typography.displaySmall - ) + val scheme = MaterialTheme.colorScheme + + Card( + onClick = onClick, + shape = RoundedCornerShape(12.dp), + colors = CardDefaults.cardColors(containerColor = scheme.surfaceContainer), + modifier = modifier.fillMaxWidth() + ) { + Column(modifier = Modifier.fillMaxWidth()) { + Box( + modifier = Modifier + .fillMaxWidth() + .aspectRatio(16f / 10f) + .clip(RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp)) + .background(scheme.surface) + ) { + PurefinAsyncImage( + model = uiModel.posterUrl, + contentDescription = uiModel.name, + contentScale = ContentScale.Crop, + modifier = Modifier.fillMaxSize() + ) + } + Spacer(modifier = Modifier.height(10.dp)) + Column(modifier = Modifier.padding(12.dp)) { + Text( + text = uiModel.name, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.SemiBold, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } } } 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 8c33cef5..f7462bca 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 @@ -2,24 +2,43 @@ package hu.bbara.purefin.ui.screen.library import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +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 androidx.hilt.navigation.compose.hiltViewModel import hu.bbara.purefin.feature.browse.library.LibraryViewModel import hu.bbara.purefin.navigation.LibraryDto -import hu.bbara.purefin.ui.common.card.PosterCard +import hu.bbara.purefin.ui.common.badge.WatchStateBadge +import hu.bbara.purefin.ui.common.image.PurefinAsyncImage +import hu.bbara.purefin.ui.model.EpisodeUiModel import hu.bbara.purefin.ui.model.MediaUiModel +import hu.bbara.purefin.ui.model.MovieUiModel +import hu.bbara.purefin.ui.model.SeriesUiModel import hu.bbara.purefin.ui.screen.library.components.LibraryTopBar @Composable @@ -35,13 +54,21 @@ fun LibraryScreen( val libraryItems = viewModel.contents.collectAsState() Scaffold( + modifier = modifier, + containerColor = MaterialTheme.colorScheme.background, + contentColor = MaterialTheme.colorScheme.onBackground, topBar = { LibraryTopBar( onBack = { viewModel.onBack() } ) } ) { innerPadding -> - Column(modifier = Modifier.padding(innerPadding)) { + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background) + .padding(innerPadding) + ) { LibraryPosterGrid(libraryItems = libraryItems.value) } } @@ -61,12 +88,80 @@ internal fun LibraryPosterGrid( modifier = modifier.background(MaterialTheme.colorScheme.background) ) { items(libraryItems, key = { item -> item.id }) { item -> - PosterCard( + LibraryMediaCard( item = item, - onMovieSelected = viewModel::onMovieSelected, - onSeriesSelected = viewModel::onSeriesSelected, - onEpisodeSelected = { _, _, _ -> } + onClick = { + when (item) { + is MovieUiModel -> viewModel.onMovieSelected(item.id) + is SeriesUiModel -> viewModel.onSeriesSelected(item.id) + is EpisodeUiModel -> Unit + } + } ) } } } + +@Composable +private fun LibraryMediaCard( + item: MediaUiModel, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + val scheme = MaterialTheme.colorScheme + + Card( + onClick = onClick, + shape = RoundedCornerShape(12.dp), + colors = CardDefaults.cardColors(containerColor = scheme.surfaceContainer), + modifier = modifier.fillMaxWidth() + ) { + Column(modifier = Modifier.fillMaxWidth()) { + Box( + modifier = Modifier + .fillMaxWidth() + .aspectRatio(16f / 10f) + .clip(RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp)) + .background(scheme.surface) + ) { + PurefinAsyncImage( + model = item.primaryImageUrl, + contentDescription = item.primaryText, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop + ) + when (item) { + is MovieUiModel, is EpisodeUiModel -> { + WatchStateBadge( + size = 28, + modifier = Modifier + .align(Alignment.TopEnd) + .padding(8.dp), + watched = item.watched, + started = (item.progress ?: 0f) > 0f + ) + } + else -> Unit + } + } + Spacer(modifier = Modifier.height(10.dp)) + Column(modifier = Modifier.padding(12.dp)) { + Text( + text = item.primaryText, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.SemiBold, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = item.secondaryText, + style = MaterialTheme.typography.bodySmall, + color = scheme.onSurfaceVariant, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } + } +}