mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-22 01:32:08 +00:00
feat: adding watched markers to remaining places
This commit is contained in:
parent
507d842098
commit
c18916e6e3
8 changed files with 82 additions and 18 deletions
|
|
@ -6,6 +6,7 @@ import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
|
@ -32,6 +33,7 @@ import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
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.dp
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import com.nuvio.app.core.format.formatReleaseDateForDisplay
|
import com.nuvio.app.core.format.formatReleaseDateForDisplay
|
||||||
|
|
@ -151,6 +153,20 @@ fun NuvioAnimatedWatchedBadge(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BoxScope.NuvioPosterWatchedOverlay(
|
||||||
|
isWatched: Boolean,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
padding: Dp = 6.dp,
|
||||||
|
) {
|
||||||
|
NuvioAnimatedWatchedBadge(
|
||||||
|
isVisible = isWatched,
|
||||||
|
modifier = modifier
|
||||||
|
.align(Alignment.TopEnd)
|
||||||
|
.padding(padding),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun PosterSheetHeader(
|
private fun PosterSheetHeader(
|
||||||
item: MetaPreview,
|
item: MetaPreview,
|
||||||
|
|
|
||||||
|
|
@ -179,12 +179,7 @@ fun NuvioPosterCard(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NuvioAnimatedWatchedBadge(
|
NuvioPosterWatchedOverlay(isWatched = isWatched)
|
||||||
isVisible = isWatched,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.TopEnd)
|
|
||||||
.padding(6.dp),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (shouldShowTitleBelow) {
|
if (shouldShowTitleBelow) {
|
||||||
Text(
|
Text(
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import com.nuvio.app.core.ui.NuvioNetworkOfflineCard
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import com.nuvio.app.core.format.formatReleaseDateForDisplay
|
import com.nuvio.app.core.format.formatReleaseDateForDisplay
|
||||||
import com.nuvio.app.core.ui.NuvioBackButton
|
import com.nuvio.app.core.ui.NuvioBackButton
|
||||||
|
import com.nuvio.app.core.ui.NuvioPosterWatchedOverlay
|
||||||
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
|
||||||
|
|
@ -55,6 +56,8 @@ import com.nuvio.app.features.home.MetaPreview
|
||||||
import com.nuvio.app.features.home.HomeCatalogSettingsRepository
|
import com.nuvio.app.features.home.HomeCatalogSettingsRepository
|
||||||
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
|
||||||
|
import com.nuvio.app.features.watched.WatchedRepository
|
||||||
|
import com.nuvio.app.features.watching.application.WatchingState
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
@ -79,6 +82,10 @@ fun CatalogScreen(
|
||||||
val homeCatalogSettingsUiState by HomeCatalogSettingsRepository.uiState.collectAsStateWithLifecycle()
|
val homeCatalogSettingsUiState by HomeCatalogSettingsRepository.uiState.collectAsStateWithLifecycle()
|
||||||
val posterCardStyle = rememberPosterCardStyleUiState()
|
val posterCardStyle = rememberPosterCardStyleUiState()
|
||||||
val networkStatusUiState by NetworkStatusRepository.uiState.collectAsStateWithLifecycle()
|
val networkStatusUiState by NetworkStatusRepository.uiState.collectAsStateWithLifecycle()
|
||||||
|
val watchedUiState by remember {
|
||||||
|
WatchedRepository.ensureLoaded()
|
||||||
|
WatchedRepository.uiState
|
||||||
|
}.collectAsStateWithLifecycle()
|
||||||
val gridState = rememberLazyGridState()
|
val gridState = rememberLazyGridState()
|
||||||
var headerHeightPx by remember { mutableIntStateOf(0) }
|
var headerHeightPx by remember { mutableIntStateOf(0) }
|
||||||
var observedOfflineState by remember { mutableStateOf(false) }
|
var observedOfflineState by remember { mutableStateOf(false) }
|
||||||
|
|
@ -187,6 +194,10 @@ fun CatalogScreen(
|
||||||
item = item,
|
item = item,
|
||||||
cornerRadiusDp = posterCardStyle.cornerRadiusDp,
|
cornerRadiusDp = posterCardStyle.cornerRadiusDp,
|
||||||
hideLabels = posterCardStyle.hideLabelsEnabled,
|
hideLabels = posterCardStyle.hideLabelsEnabled,
|
||||||
|
isWatched = WatchingState.isPosterWatched(
|
||||||
|
watchedKeys = watchedUiState.watchedKeys,
|
||||||
|
item = item,
|
||||||
|
),
|
||||||
onClick = onPosterClick?.let { { it(item) } },
|
onClick = onPosterClick?.let { { it(item) } },
|
||||||
onLongClick = onPosterLongClick?.let { { it(item) } },
|
onLongClick = onPosterLongClick?.let { { it(item) } },
|
||||||
)
|
)
|
||||||
|
|
@ -258,6 +269,7 @@ private fun CatalogPosterTile(
|
||||||
item: MetaPreview,
|
item: MetaPreview,
|
||||||
cornerRadiusDp: Int,
|
cornerRadiusDp: Int,
|
||||||
hideLabels: Boolean,
|
hideLabels: Boolean,
|
||||||
|
isWatched: Boolean,
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null,
|
||||||
onLongClick: (() -> Unit)? = null,
|
onLongClick: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
|
|
@ -280,6 +292,7 @@ private fun CatalogPosterTile(
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
NuvioPosterWatchedOverlay(isWatched = isWatched)
|
||||||
}
|
}
|
||||||
if (!hideLabels) {
|
if (!hideLabels) {
|
||||||
Text(
|
Text(
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ import com.nuvio.app.features.home.PosterShape
|
||||||
import com.nuvio.app.features.home.canOpenCatalog
|
import com.nuvio.app.features.home.canOpenCatalog
|
||||||
import com.nuvio.app.features.home.stableKey
|
import com.nuvio.app.features.home.stableKey
|
||||||
import com.nuvio.app.features.home.components.HomeCatalogRowSection
|
import com.nuvio.app.features.home.components.HomeCatalogRowSection
|
||||||
|
import com.nuvio.app.features.watched.WatchedRepository
|
||||||
|
import com.nuvio.app.features.watching.application.WatchingState
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
@ -79,6 +81,10 @@ fun FolderDetailScreen(
|
||||||
onPosterClick: (MetaPreview) -> Unit,
|
onPosterClick: (MetaPreview) -> Unit,
|
||||||
) {
|
) {
|
||||||
val uiState by FolderDetailRepository.uiState.collectAsState()
|
val uiState by FolderDetailRepository.uiState.collectAsState()
|
||||||
|
val watchedUiState by remember {
|
||||||
|
WatchedRepository.ensureLoaded()
|
||||||
|
WatchedRepository.uiState
|
||||||
|
}.collectAsState()
|
||||||
val folder = uiState.folder
|
val folder = uiState.folder
|
||||||
val coverImageUrl = folder?.coverImageUrl?.takeIf { it.isNotBlank() }
|
val coverImageUrl = folder?.coverImageUrl?.takeIf { it.isNotBlank() }
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
|
|
@ -160,18 +166,21 @@ fun FolderDetailScreen(
|
||||||
when (uiState.viewMode) {
|
when (uiState.viewMode) {
|
||||||
FolderViewMode.TABBED_GRID -> TabbedGridContent(
|
FolderViewMode.TABBED_GRID -> TabbedGridContent(
|
||||||
uiState = uiState,
|
uiState = uiState,
|
||||||
|
watchedKeys = watchedUiState.watchedKeys,
|
||||||
modifier = Modifier.weight(1f).then(contentModifier),
|
modifier = Modifier.weight(1f).then(contentModifier),
|
||||||
onTabSelected = { FolderDetailRepository.selectTab(it) },
|
onTabSelected = { FolderDetailRepository.selectTab(it) },
|
||||||
onPosterClick = onPosterClick,
|
onPosterClick = onPosterClick,
|
||||||
)
|
)
|
||||||
FolderViewMode.ROWS -> RowsContent(
|
FolderViewMode.ROWS -> RowsContent(
|
||||||
uiState = uiState,
|
uiState = uiState,
|
||||||
|
watchedKeys = watchedUiState.watchedKeys,
|
||||||
modifier = Modifier.weight(1f).then(contentModifier),
|
modifier = Modifier.weight(1f).then(contentModifier),
|
||||||
onCatalogClick = onCatalogClick,
|
onCatalogClick = onCatalogClick,
|
||||||
onPosterClick = onPosterClick,
|
onPosterClick = onPosterClick,
|
||||||
)
|
)
|
||||||
FolderViewMode.FOLLOW_LAYOUT -> RowsContent(
|
FolderViewMode.FOLLOW_LAYOUT -> RowsContent(
|
||||||
uiState = uiState,
|
uiState = uiState,
|
||||||
|
watchedKeys = watchedUiState.watchedKeys,
|
||||||
modifier = Modifier.weight(1f).then(contentModifier),
|
modifier = Modifier.weight(1f).then(contentModifier),
|
||||||
onCatalogClick = onCatalogClick,
|
onCatalogClick = onCatalogClick,
|
||||||
onPosterClick = onPosterClick,
|
onPosterClick = onPosterClick,
|
||||||
|
|
@ -199,6 +208,7 @@ private fun FolderCoverImage(
|
||||||
@Composable
|
@Composable
|
||||||
private fun TabbedGridContent(
|
private fun TabbedGridContent(
|
||||||
uiState: FolderDetailUiState,
|
uiState: FolderDetailUiState,
|
||||||
|
watchedKeys: Set<String>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onTabSelected: (Int) -> Unit,
|
onTabSelected: (Int) -> Unit,
|
||||||
onPosterClick: (MetaPreview) -> Unit,
|
onPosterClick: (MetaPreview) -> Unit,
|
||||||
|
|
@ -285,6 +295,10 @@ private fun TabbedGridContent(
|
||||||
imageUrl = item.poster,
|
imageUrl = item.poster,
|
||||||
shape = NuvioPosterShape.Poster,
|
shape = NuvioPosterShape.Poster,
|
||||||
detailLine = item.releaseInfo,
|
detailLine = item.releaseInfo,
|
||||||
|
isWatched = WatchingState.isPosterWatched(
|
||||||
|
watchedKeys = watchedKeys,
|
||||||
|
item = item,
|
||||||
|
),
|
||||||
onClick = { onPosterClick(item) },
|
onClick = { onPosterClick(item) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -304,6 +318,7 @@ private fun TabbedGridContent(
|
||||||
@Composable
|
@Composable
|
||||||
private fun RowsContent(
|
private fun RowsContent(
|
||||||
uiState: FolderDetailUiState,
|
uiState: FolderDetailUiState,
|
||||||
|
watchedKeys: Set<String>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onCatalogClick: (HomeCatalogSection) -> Unit,
|
onCatalogClick: (HomeCatalogSection) -> Unit,
|
||||||
onPosterClick: (MetaPreview) -> Unit,
|
onPosterClick: (MetaPreview) -> Unit,
|
||||||
|
|
@ -340,6 +355,7 @@ private fun RowsContent(
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
},
|
},
|
||||||
|
watchedKeys = watchedKeys,
|
||||||
onPosterClick = { onPosterClick(it) },
|
onPosterClick = { onPosterClick(it) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.lerp
|
import androidx.compose.ui.unit.lerp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import coil3.compose.LocalPlatformContext
|
import coil3.compose.LocalPlatformContext
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
|
|
@ -63,6 +64,7 @@ import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
||||||
import com.nuvio.app.features.details.components.DetailPosterRailSection
|
import com.nuvio.app.features.details.components.DetailPosterRailSection
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
import com.nuvio.app.features.tmdb.TmdbMetadataService
|
import com.nuvio.app.features.tmdb.TmdbMetadataService
|
||||||
|
import com.nuvio.app.features.watched.WatchedRepository
|
||||||
import com.nuvio.app.features.watchprogress.CurrentDateProvider
|
import com.nuvio.app.features.watchprogress.CurrentDateProvider
|
||||||
import nuvio.composeapp.generated.resources.*
|
import nuvio.composeapp.generated.resources.*
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
|
|
@ -89,6 +91,10 @@ fun PersonDetailScreen(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
var uiState by remember(personId) { mutableStateOf<PersonDetailUiState>(PersonDetailUiState.Loading) }
|
var uiState by remember(personId) { mutableStateOf<PersonDetailUiState>(PersonDetailUiState.Loading) }
|
||||||
|
val watchedUiState by remember {
|
||||||
|
WatchedRepository.ensureLoaded()
|
||||||
|
WatchedRepository.uiState
|
||||||
|
}.collectAsStateWithLifecycle()
|
||||||
val resolvedAvatarTransitionKey = avatarTransitionKey ?: castAvatarSharedTransitionKey(personId)
|
val resolvedAvatarTransitionKey = avatarTransitionKey ?: castAvatarSharedTransitionKey(personId)
|
||||||
|
|
||||||
LaunchedEffect(personId) {
|
LaunchedEffect(personId) {
|
||||||
|
|
@ -127,6 +133,7 @@ fun PersonDetailScreen(
|
||||||
)
|
)
|
||||||
is PersonDetailUiState.Success -> PersonDetailContent(
|
is PersonDetailUiState.Success -> PersonDetailContent(
|
||||||
person = state.personDetail,
|
person = state.personDetail,
|
||||||
|
watchedKeys = watchedUiState.watchedKeys,
|
||||||
onOpenMeta = onOpenMeta,
|
onOpenMeta = onOpenMeta,
|
||||||
initialProfilePhoto = initialProfilePhoto,
|
initialProfilePhoto = initialProfilePhoto,
|
||||||
avatarTransitionKey = resolvedAvatarTransitionKey,
|
avatarTransitionKey = resolvedAvatarTransitionKey,
|
||||||
|
|
@ -156,6 +163,7 @@ fun PersonDetailScreen(
|
||||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
@OptIn(ExperimentalSharedTransitionApi::class)
|
||||||
private fun PersonDetailContent(
|
private fun PersonDetailContent(
|
||||||
person: PersonDetail,
|
person: PersonDetail,
|
||||||
|
watchedKeys: Set<String>,
|
||||||
onOpenMeta: (MetaPreview) -> Unit,
|
onOpenMeta: (MetaPreview) -> Unit,
|
||||||
initialProfilePhoto: String? = null,
|
initialProfilePhoto: String? = null,
|
||||||
avatarTransitionKey: String,
|
avatarTransitionKey: String,
|
||||||
|
|
@ -274,7 +282,7 @@ private fun PersonDetailContent(
|
||||||
DetailPosterRailSection(
|
DetailPosterRailSection(
|
||||||
title = stringResource(Res.string.person_popular),
|
title = stringResource(Res.string.person_popular),
|
||||||
items = popularCredits,
|
items = popularCredits,
|
||||||
watchedKeys = emptySet(),
|
watchedKeys = watchedKeys,
|
||||||
headerHorizontalPadding = 20.dp,
|
headerHorizontalPadding = 20.dp,
|
||||||
onPosterClick = onOpenMeta,
|
onPosterClick = onOpenMeta,
|
||||||
)
|
)
|
||||||
|
|
@ -285,7 +293,7 @@ private fun PersonDetailContent(
|
||||||
DetailPosterRailSection(
|
DetailPosterRailSection(
|
||||||
title = stringResource(Res.string.person_latest),
|
title = stringResource(Res.string.person_latest),
|
||||||
items = latestCredits,
|
items = latestCredits,
|
||||||
watchedKeys = emptySet(),
|
watchedKeys = watchedKeys,
|
||||||
headerHorizontalPadding = 20.dp,
|
headerHorizontalPadding = 20.dp,
|
||||||
onPosterClick = onOpenMeta,
|
onPosterClick = onOpenMeta,
|
||||||
)
|
)
|
||||||
|
|
@ -296,7 +304,7 @@ private fun PersonDetailContent(
|
||||||
DetailPosterRailSection(
|
DetailPosterRailSection(
|
||||||
title = stringResource(Res.string.person_upcoming),
|
title = stringResource(Res.string.person_upcoming),
|
||||||
items = upcomingCredits,
|
items = upcomingCredits,
|
||||||
watchedKeys = emptySet(),
|
watchedKeys = watchedKeys,
|
||||||
headerHorizontalPadding = 20.dp,
|
headerHorizontalPadding = 20.dp,
|
||||||
onPosterClick = onOpenMeta,
|
onPosterClick = onOpenMeta,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,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 androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import nuvio.composeapp.generated.resources.*
|
import nuvio.composeapp.generated.resources.*
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
@ -55,6 +56,7 @@ import com.nuvio.app.features.tmdb.TmdbEntityKind
|
||||||
import com.nuvio.app.features.tmdb.TmdbEntityMediaType
|
import com.nuvio.app.features.tmdb.TmdbEntityMediaType
|
||||||
import com.nuvio.app.features.tmdb.TmdbEntityRailType
|
import com.nuvio.app.features.tmdb.TmdbEntityRailType
|
||||||
import com.nuvio.app.features.tmdb.TmdbMetadataService
|
import com.nuvio.app.features.tmdb.TmdbMetadataService
|
||||||
|
import com.nuvio.app.features.watched.WatchedRepository
|
||||||
|
|
||||||
private sealed interface EntityBrowseUiState {
|
private sealed interface EntityBrowseUiState {
|
||||||
data object Loading : EntityBrowseUiState
|
data object Loading : EntityBrowseUiState
|
||||||
|
|
@ -75,6 +77,10 @@ fun TmdbEntityBrowseScreen(
|
||||||
var uiState by remember(entityKind, entityId) {
|
var uiState by remember(entityKind, entityId) {
|
||||||
mutableStateOf<EntityBrowseUiState>(EntityBrowseUiState.Loading)
|
mutableStateOf<EntityBrowseUiState>(EntityBrowseUiState.Loading)
|
||||||
}
|
}
|
||||||
|
val watchedUiState by remember {
|
||||||
|
WatchedRepository.ensureLoaded()
|
||||||
|
WatchedRepository.uiState
|
||||||
|
}.collectAsStateWithLifecycle()
|
||||||
val loadFailedMessage = stringResource(Res.string.details_browse_load_failed, entityName)
|
val loadFailedMessage = stringResource(Res.string.details_browse_load_failed, entityName)
|
||||||
|
|
||||||
LaunchedEffect(entityKind, entityId) {
|
LaunchedEffect(entityKind, entityId) {
|
||||||
|
|
@ -106,6 +112,7 @@ fun TmdbEntityBrowseScreen(
|
||||||
is EntityBrowseUiState.Success -> EntityBrowseContent(
|
is EntityBrowseUiState.Success -> EntityBrowseContent(
|
||||||
data = state.data,
|
data = state.data,
|
||||||
sourceType = sourceType,
|
sourceType = sourceType,
|
||||||
|
watchedKeys = watchedUiState.watchedKeys,
|
||||||
onOpenMeta = onOpenMeta,
|
onOpenMeta = onOpenMeta,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -131,6 +138,7 @@ fun TmdbEntityBrowseScreen(
|
||||||
private fun EntityBrowseContent(
|
private fun EntityBrowseContent(
|
||||||
data: TmdbEntityBrowseData,
|
data: TmdbEntityBrowseData,
|
||||||
sourceType: String,
|
sourceType: String,
|
||||||
|
watchedKeys: Set<String>,
|
||||||
onOpenMeta: (MetaPreview) -> Unit,
|
onOpenMeta: (MetaPreview) -> Unit,
|
||||||
) {
|
) {
|
||||||
val backgroundUrl = remember(data.rails, sourceType) {
|
val backgroundUrl = remember(data.rails, sourceType) {
|
||||||
|
|
@ -208,7 +216,7 @@ private fun EntityBrowseContent(
|
||||||
DetailPosterRailSection(
|
DetailPosterRailSection(
|
||||||
title = railTitle,
|
title = railTitle,
|
||||||
items = rail.items,
|
items = rail.items,
|
||||||
watchedKeys = emptySet(),
|
watchedKeys = watchedKeys,
|
||||||
headerHorizontalPadding = 20.dp,
|
headerHorizontalPadding = 20.dp,
|
||||||
onPosterClick = onOpenMeta,
|
onPosterClick = onOpenMeta,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ import com.nuvio.app.features.home.components.HomeEmptyStateCard
|
||||||
import com.nuvio.app.features.home.components.HomePosterCard
|
import com.nuvio.app.features.home.components.HomePosterCard
|
||||||
import com.nuvio.app.features.home.components.HomeSkeletonRow
|
import com.nuvio.app.features.home.components.HomeSkeletonRow
|
||||||
import com.nuvio.app.features.profiles.ProfileRepository
|
import com.nuvio.app.features.profiles.ProfileRepository
|
||||||
|
import com.nuvio.app.features.watched.WatchedRepository
|
||||||
|
import com.nuvio.app.features.watching.application.WatchingState
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.emptyFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -50,6 +52,10 @@ fun LibraryScreen(
|
||||||
LibraryRepository.ensureLoaded()
|
LibraryRepository.ensureLoaded()
|
||||||
LibraryRepository.uiState
|
LibraryRepository.uiState
|
||||||
}.collectAsStateWithLifecycle()
|
}.collectAsStateWithLifecycle()
|
||||||
|
val watchedUiState by remember {
|
||||||
|
WatchedRepository.ensureLoaded()
|
||||||
|
WatchedRepository.uiState
|
||||||
|
}.collectAsStateWithLifecycle()
|
||||||
val networkStatusUiState by NetworkStatusRepository.uiState.collectAsStateWithLifecycle()
|
val networkStatusUiState by NetworkStatusRepository.uiState.collectAsStateWithLifecycle()
|
||||||
var observedOfflineState by remember { mutableStateOf(false) }
|
var observedOfflineState by remember { mutableStateOf(false) }
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
@ -176,6 +182,7 @@ fun LibraryScreen(
|
||||||
else -> {
|
else -> {
|
||||||
librarySections(
|
librarySections(
|
||||||
sections = uiState.sections,
|
sections = uiState.sections,
|
||||||
|
watchedKeys = watchedUiState.watchedKeys,
|
||||||
onPosterClick = onPosterClick,
|
onPosterClick = onPosterClick,
|
||||||
onSectionViewAllClick = onSectionViewAllClick,
|
onSectionViewAllClick = onSectionViewAllClick,
|
||||||
onPosterLongClick = onPosterLongClick,
|
onPosterLongClick = onPosterLongClick,
|
||||||
|
|
@ -187,6 +194,7 @@ fun LibraryScreen(
|
||||||
|
|
||||||
private fun LazyListScope.librarySections(
|
private fun LazyListScope.librarySections(
|
||||||
sections: List<LibrarySection>,
|
sections: List<LibrarySection>,
|
||||||
|
watchedKeys: Set<String>,
|
||||||
onPosterClick: ((LibraryItem) -> Unit)?,
|
onPosterClick: ((LibraryItem) -> Unit)?,
|
||||||
onSectionViewAllClick: ((LibrarySection) -> Unit)?,
|
onSectionViewAllClick: ((LibrarySection) -> Unit)?,
|
||||||
onPosterLongClick: ((LibraryItem, LibrarySection) -> Unit)?,
|
onPosterLongClick: ((LibraryItem, LibrarySection) -> Unit)?,
|
||||||
|
|
@ -209,8 +217,13 @@ private fun LazyListScope.librarySections(
|
||||||
viewAllPillSize = NuvioViewAllPillSize.Compact,
|
viewAllPillSize = NuvioViewAllPillSize.Compact,
|
||||||
key = { item -> "${item.type}:${item.id}" },
|
key = { item -> "${item.type}:${item.id}" },
|
||||||
) { item ->
|
) { item ->
|
||||||
|
val posterItem = item.toMetaPreview()
|
||||||
HomePosterCard(
|
HomePosterCard(
|
||||||
item = item.toMetaPreview(),
|
item = posterItem,
|
||||||
|
isWatched = WatchingState.isPosterWatched(
|
||||||
|
watchedKeys = watchedKeys,
|
||||||
|
item = posterItem,
|
||||||
|
),
|
||||||
onClick = onPosterClick?.let { { it(item) } },
|
onClick = onPosterClick?.let { { it(item) } },
|
||||||
onLongClick = onPosterLongClick?.let { { it(item, section) } },
|
onLongClick = onPosterLongClick?.let { { it(item, section) } },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,12 @@ import coil3.compose.AsyncImage
|
||||||
import com.nuvio.app.core.network.NetworkCondition
|
import com.nuvio.app.core.network.NetworkCondition
|
||||||
import com.nuvio.app.core.format.formatReleaseDateForDisplay
|
import com.nuvio.app.core.format.formatReleaseDateForDisplay
|
||||||
import com.nuvio.app.core.ui.NuvioNetworkOfflineCard
|
import com.nuvio.app.core.ui.NuvioNetworkOfflineCard
|
||||||
import com.nuvio.app.core.ui.NuvioAnimatedWatchedBadge
|
|
||||||
import com.nuvio.app.core.ui.NuvioBottomSheetActionRow
|
import com.nuvio.app.core.ui.NuvioBottomSheetActionRow
|
||||||
import com.nuvio.app.core.ui.NuvioBottomSheetDivider
|
import com.nuvio.app.core.ui.NuvioBottomSheetDivider
|
||||||
import com.nuvio.app.core.ui.NuvioModalBottomSheet
|
import com.nuvio.app.core.ui.NuvioModalBottomSheet
|
||||||
import com.nuvio.app.core.ui.dismissNuvioBottomSheet
|
import com.nuvio.app.core.ui.dismissNuvioBottomSheet
|
||||||
import com.nuvio.app.core.ui.nuvioSafeBottomPadding
|
import com.nuvio.app.core.ui.nuvioSafeBottomPadding
|
||||||
|
import com.nuvio.app.core.ui.NuvioPosterWatchedOverlay
|
||||||
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.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
|
|
@ -404,12 +404,7 @@ private fun DiscoverPosterTile(
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
NuvioAnimatedWatchedBadge(
|
NuvioPosterWatchedOverlay(isWatched = isWatched)
|
||||||
isVisible = isWatched,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.TopEnd)
|
|
||||||
.padding(6.dp),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (!hideLabels) {
|
if (!hideLabels) {
|
||||||
Text(
|
Text(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue