diff --git a/app/src/main/java/hu/bbara/purefin/PurefinActivity.kt b/app/src/main/java/hu/bbara/purefin/PurefinActivity.kt index c750d898..a1c536d2 100644 --- a/app/src/main/java/hu/bbara/purefin/PurefinActivity.kt +++ b/app/src/main/java/hu/bbara/purefin/PurefinActivity.kt @@ -41,8 +41,10 @@ import dagger.hilt.android.AndroidEntryPoint import hu.bbara.purefin.data.SessionBootstrapper import hu.bbara.purefin.jellyfin.JellyfinAuthInterceptor import hu.bbara.purefin.data.UserSessionRepository +import hu.bbara.purefin.navigation.LocalHomeMediaSharedBoundsKey import hu.bbara.purefin.navigation.LocalNavigationBackStack import hu.bbara.purefin.navigation.LocalNavigationManager +import hu.bbara.purefin.navigation.LocalSetHomeMediaSharedBoundsKey import hu.bbara.purefin.navigation.LocalSharedTransitionScope import hu.bbara.purefin.navigation.NavigationCommand import hu.bbara.purefin.navigation.NavigationManager @@ -158,6 +160,7 @@ class PurefinActivity : ComponentActivity() { if (isLoggedIn) { @Suppress("UNCHECKED_CAST") val backStack = rememberNavBackStack(Route.Home) as NavBackStack + var homeMediaSharedBoundsKey by remember { mutableStateOf(null) } val appEntryProvider = entryProvider { entryBuilders.forEach { builder -> builder() } @@ -180,7 +183,11 @@ class PurefinActivity : ComponentActivity() { CompositionLocalProvider( LocalNavigationManager provides navigationManager, LocalNavigationBackStack provides backStack.toList(), - LocalSharedTransitionScope provides this + LocalSharedTransitionScope provides this, + LocalHomeMediaSharedBoundsKey provides homeMediaSharedBoundsKey, + LocalSetHomeMediaSharedBoundsKey provides { key -> + homeMediaSharedBoundsKey = key + } ) { NavDisplay( backStack = backStack, diff --git a/app/src/main/java/hu/bbara/purefin/navigation/NavigationLocals.kt b/app/src/main/java/hu/bbara/purefin/navigation/NavigationLocals.kt index 5dede312..c1514958 100644 --- a/app/src/main/java/hu/bbara/purefin/navigation/NavigationLocals.kt +++ b/app/src/main/java/hu/bbara/purefin/navigation/NavigationLocals.kt @@ -18,4 +18,8 @@ val LocalSharedTransitionScope = compositionLocalOf { nu val LocalNavSharedAnimatedVisibilityScope = compositionLocalOf { null } +val LocalHomeMediaSharedBoundsKey = compositionLocalOf { null } + +val LocalSetHomeMediaSharedBoundsKey = staticCompositionLocalOf<(String) -> Unit> { {} } + const val HOME_SEARCH_SHARED_BOUNDS_KEY = "home_search_shared_bounds" diff --git a/app/src/main/java/hu/bbara/purefin/navigation/RouteEntryBuilder.kt b/app/src/main/java/hu/bbara/purefin/navigation/RouteEntryBuilder.kt index f494092d..0a8ba57e 100644 --- a/app/src/main/java/hu/bbara/purefin/navigation/RouteEntryBuilder.kt +++ b/app/src/main/java/hu/bbara/purefin/navigation/RouteEntryBuilder.kt @@ -27,13 +27,25 @@ fun EntryProviderScope.appRouteEntryBuilder() { } } entry { - MovieScreen(movie = it.item) + CompositionLocalProvider( + LocalNavSharedAnimatedVisibilityScope provides LocalNavAnimatedContentScope.current + ) { + MovieScreen(movie = it.item) + } } entry { - SeriesScreen(series = it.item) + CompositionLocalProvider( + LocalNavSharedAnimatedVisibilityScope provides LocalNavAnimatedContentScope.current + ) { + SeriesScreen(series = it.item) + } } entry { - EpisodeScreen(episode = it.item) + CompositionLocalProvider( + LocalNavSharedAnimatedVisibilityScope provides LocalNavAnimatedContentScope.current + ) { + EpisodeScreen(episode = it.item) + } } entry { LibraryScreen(library = it.library) diff --git a/app/src/main/java/hu/bbara/purefin/ui/common/media/HomeMediaSharedBounds.kt b/app/src/main/java/hu/bbara/purefin/ui/common/media/HomeMediaSharedBounds.kt new file mode 100644 index 00000000..aca6ce3b --- /dev/null +++ b/app/src/main/java/hu/bbara/purefin/ui/common/media/HomeMediaSharedBounds.kt @@ -0,0 +1,75 @@ +package hu.bbara.purefin.ui.common.media + +import androidx.compose.animation.ExperimentalSharedTransitionApi +import androidx.compose.animation.SharedTransitionScope +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import hu.bbara.purefin.navigation.LocalHomeMediaSharedBoundsKey +import hu.bbara.purefin.navigation.LocalNavSharedAnimatedVisibilityScope +import hu.bbara.purefin.navigation.LocalSetHomeMediaSharedBoundsKey +import hu.bbara.purefin.navigation.LocalSharedTransitionScope +import java.util.UUID + +fun homeMediaSharedBoundsKey(origin: String, mediaId: UUID): String = + "home_media_${origin}_$mediaId" + +@OptIn(ExperimentalSharedTransitionApi::class) +@Composable +fun Modifier.homeMediaSharedBoundsSource(sharedBoundsKey: String): Modifier { + val selectedKey = LocalHomeMediaSharedBoundsKey.current + return homeMediaSharedBounds(sharedBoundsKey.takeIf { it == selectedKey }) +} + +@Composable +fun Modifier.homeMediaSharedBoundsDestination(): Modifier = + homeMediaSharedBounds(LocalHomeMediaSharedBoundsKey.current) + +@OptIn(ExperimentalSharedTransitionApi::class) +@Composable +fun isHomeMediaSharedBoundsTransitionActive(): Boolean { + val sharedBoundsKey = LocalHomeMediaSharedBoundsKey.current + val sharedTransitionScope = LocalSharedTransitionScope.current + return sharedBoundsKey != null && sharedTransitionScope?.isTransitionActive == true +} + +@Composable +fun rememberHomeMediaSharedBoundsClick( + sharedBoundsKey: String, + onClick: () -> Unit +): () -> Unit { + val selectSharedBoundsKey = LocalSetHomeMediaSharedBoundsKey.current + return remember(sharedBoundsKey, onClick, selectSharedBoundsKey) { + { + selectSharedBoundsKey(sharedBoundsKey) + onClick() + } + } +} + +@OptIn(ExperimentalSharedTransitionApi::class) +@Composable +private fun Modifier.homeMediaSharedBounds(sharedBoundsKey: String?): Modifier { + val sharedTransitionScope = LocalSharedTransitionScope.current + val animatedVisibilityScope = LocalNavSharedAnimatedVisibilityScope.current + + if ( + sharedBoundsKey == null || + sharedTransitionScope == null || + animatedVisibilityScope == null + ) { + return this + } + + return with(sharedTransitionScope) { + this@homeMediaSharedBounds.sharedBounds( + sharedContentState = rememberSharedContentState(key = sharedBoundsKey), + animatedVisibilityScope = animatedVisibilityScope, + enter = fadeIn(), + exit = fadeOut(), + resizeMode = SharedTransitionScope.ResizeMode.scaleToBounds() + ) + } +} diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/episode/EpisodeScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/episode/EpisodeScreen.kt index eae0e9be..be05f2f6 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/episode/EpisodeScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/episode/EpisodeScreen.kt @@ -34,6 +34,8 @@ import androidx.hilt.navigation.compose.hiltViewModel import hu.bbara.purefin.ui.screen.waiting.PurefinWaitingScreen import hu.bbara.purefin.ui.common.media.MediaHero import hu.bbara.purefin.ui.common.media.MediaMetadataFlowRow +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsDestination +import hu.bbara.purefin.ui.common.media.isHomeMediaSharedBoundsTransitionActive import hu.bbara.purefin.download.DownloadState import hu.bbara.purefin.image.ImageUrlBuilder import hu.bbara.purefin.navigation.EpisodeDto @@ -117,17 +119,20 @@ private fun EpisodeScreenInternal( onDownloadClick: () -> Unit, modifier: Modifier = Modifier, ) { + val isHomeMediaTransitionActive = isHomeMediaSharedBoundsTransitionActive() Scaffold( modifier = modifier, containerColor = MaterialTheme.colorScheme.background, topBar = { - EpisodeTopBar( - shortcut = topBarShortcut, - onBack = onBack, - onSeriesClick = onSeriesClick, - modifier = Modifier - ) + if (!isHomeMediaTransitionActive) { + EpisodeTopBar( + shortcut = topBarShortcut, + onBack = onBack, + onSeriesClick = onSeriesClick, + modifier = Modifier + ) + } } ) { innerPadding -> Column( @@ -136,15 +141,17 @@ private fun EpisodeScreenInternal( .verticalScroll(rememberScrollState()) ) { EpisodeHeroSection(episode = episode) - EpisodeDetails( - episode = episode, - downloadState = downloadState, - onDownloadClick = onDownloadClick, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(bottom = innerPadding.calculateBottomPadding()) - ) + if (!isHomeMediaTransitionActive) { + EpisodeDetails( + episode = episode, + downloadState = downloadState, + onDownloadClick = onDownloadClick, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .padding(bottom = innerPadding.calculateBottomPadding()) + ) + } } } } @@ -160,6 +167,7 @@ private fun EpisodeHeroSection( Box( modifier = modifier + .homeMediaSharedBoundsDestination() .fillMaxWidth() .height(sectionHeight) ) { diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/continuewatching/ContinueWatchingCard.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/continuewatching/ContinueWatchingCard.kt index 3f0681ea..9dcf6890 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/continuewatching/ContinueWatchingCard.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/continuewatching/ContinueWatchingCard.kt @@ -26,17 +26,23 @@ import androidx.compose.ui.unit.dp import hu.bbara.purefin.ui.model.MediaUiModel import hu.bbara.purefin.ui.common.bar.MediaProgressBar import hu.bbara.purefin.ui.common.image.PurefinAsyncImage +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsSource +import hu.bbara.purefin.ui.common.media.rememberHomeMediaSharedBoundsClick @Composable internal fun ContinueWatchingCard( item: MediaUiModel, + sharedBoundsKey: String, onMediaSelected: (MediaUiModel) -> Unit, modifier: Modifier = Modifier ) { val scheme = MaterialTheme.colorScheme + val onClick = rememberHomeMediaSharedBoundsClick(sharedBoundsKey) { + onMediaSelected(item) + } Card( - onClick = { onMediaSelected(item) }, + onClick = onClick, shape = RoundedCornerShape(26.dp), colors = CardDefaults.cardColors(containerColor = scheme.surfaceContainer), modifier = modifier.width(280.dp) @@ -44,6 +50,7 @@ internal fun ContinueWatchingCard( Column(modifier = Modifier.fillMaxWidth()) { Box( modifier = Modifier + .homeMediaSharedBoundsSource(sharedBoundsKey) .fillMaxWidth() .aspectRatio(16f / 9f) .background(scheme.surfaceContainer) diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/continuewatching/ContinueWatchingSection.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/continuewatching/ContinueWatchingSection.kt index 23b27ff9..0798b67c 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/continuewatching/ContinueWatchingSection.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/continuewatching/ContinueWatchingSection.kt @@ -7,13 +7,14 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import hu.bbara.purefin.ui.common.header.SectionHeader +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsKey import hu.bbara.purefin.ui.model.MediaUiModel @Composable @@ -42,9 +43,10 @@ fun ContinueWatchingSection( modifier = Modifier.fillMaxWidth(), state = listState ) { - items(items = items, key = { item -> item.id }) { item -> + itemsIndexed(items = items, key = { _, item -> item.id }) { index, item -> ContinueWatchingCard( item = item, + sharedBoundsKey = homeMediaSharedBoundsKey("continue-$index", item.id), onMediaSelected = onMediaSelected ) } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/featured/SuggestionCard.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/featured/SuggestionCard.kt index 8367535f..df25f05b 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/featured/SuggestionCard.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/featured/SuggestionCard.kt @@ -26,18 +26,25 @@ import androidx.compose.ui.unit.dp import hu.bbara.purefin.ui.model.MediaUiModel import hu.bbara.purefin.ui.common.bar.MediaProgressBar import hu.bbara.purefin.ui.common.image.PurefinAsyncImage +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsSource +import hu.bbara.purefin.ui.common.media.rememberHomeMediaSharedBoundsClick @Composable internal fun SuggestionCard( item: MediaUiModel, + sharedBoundsKey: String, onClick: () -> Unit, modifier: Modifier = Modifier ) { val scheme = MaterialTheme.colorScheme val description = item.description.trim() + val onCardClick = rememberHomeMediaSharedBoundsClick( + sharedBoundsKey = sharedBoundsKey, + onClick = onClick + ) ElevatedCard( - onClick = onClick, + onClick = onCardClick, colors = CardDefaults.elevatedCardColors(containerColor = scheme.surfaceContainerLow), elevation = CardDefaults.elevatedCardElevation(defaultElevation = 1.dp), shape = RoundedCornerShape(30.dp), @@ -45,6 +52,7 @@ internal fun SuggestionCard( ) { Box( modifier = Modifier + .homeMediaSharedBoundsSource(sharedBoundsKey) .fillMaxWidth() .aspectRatio(16f / 11f) ) { diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/featured/SuggestionsSection.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/featured/SuggestionsSection.kt index 63239263..c62b5239 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/featured/SuggestionsSection.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/featured/SuggestionsSection.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsKey import hu.bbara.purefin.ui.model.MediaUiModel @Composable @@ -49,9 +50,11 @@ fun SuggestionsSection( pageSpacing = 16.dp, modifier = Modifier.fillMaxWidth() ) { page -> + val item = items[page] SuggestionCard( - item = items[page], - onClick = { onItemOpen(items[page]) } + item = item, + sharedBoundsKey = homeMediaSharedBoundsKey("suggestion-$page", item.id), + onClick = { onItemOpen(item) } ) } if (items.size > 1) { diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/library/HomeBrowseCard.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/library/HomeBrowseCard.kt index 53bbe157..bd431b88 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/library/HomeBrowseCard.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/library/HomeBrowseCard.kt @@ -25,6 +25,8 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import hu.bbara.purefin.ui.common.badge.WatchStateBadge import hu.bbara.purefin.ui.common.image.PurefinAsyncImage +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsSource +import hu.bbara.purefin.ui.common.media.rememberHomeMediaSharedBoundsClick import hu.bbara.purefin.ui.model.EpisodeUiModel import hu.bbara.purefin.ui.model.MediaUiModel import hu.bbara.purefin.ui.model.MovieUiModel @@ -32,13 +34,17 @@ import hu.bbara.purefin.ui.model.MovieUiModel @Composable internal fun HomeBrowseCard( uiModel: MediaUiModel, + sharedBoundsKey: String, onMediaSelected: (MediaUiModel) -> Unit, modifier: Modifier = Modifier ) { val scheme = MaterialTheme.colorScheme + val onClick = rememberHomeMediaSharedBoundsClick(sharedBoundsKey) { + onMediaSelected(uiModel) + } Card( - onClick = { onMediaSelected(uiModel) }, + onClick = onClick, shape = RoundedCornerShape(12.dp), colors = CardDefaults.cardColors(containerColor = scheme.surfaceContainer), modifier = modifier.width(188.dp) @@ -46,6 +52,7 @@ internal fun HomeBrowseCard( Column(modifier = Modifier.fillMaxWidth()) { Box( modifier = Modifier + .homeMediaSharedBoundsSource(sharedBoundsKey) .fillMaxWidth() .aspectRatio(16f / 10f) .clip(RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp)) diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/library/LibraryPosterSection.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/library/LibraryPosterSection.kt index e8725287..520b2d49 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/library/LibraryPosterSection.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/library/LibraryPosterSection.kt @@ -7,13 +7,14 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import hu.bbara.purefin.ui.common.header.SectionHeader +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsKey import hu.bbara.purefin.ui.model.LibraryUiModel import hu.bbara.purefin.ui.model.MediaUiModel @@ -49,9 +50,13 @@ fun LibraryPosterSection( modifier = Modifier.fillMaxWidth(), state = listState ) { - items(items = items, key = { item -> item.id }) { item -> + itemsIndexed(items = items, key = { _, item -> item.id }) { index, item -> HomeBrowseCard( uiModel = item, + sharedBoundsKey = homeMediaSharedBoundsKey( + origin = "library-${library.id}-$index", + mediaId = item.id + ), onMediaSelected = onMediaSelected ) } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/nextup/NextUpCard.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/nextup/NextUpCard.kt index e89816cb..70ecb22b 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/nextup/NextUpCard.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/nextup/NextUpCard.kt @@ -24,17 +24,23 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import hu.bbara.purefin.ui.model.MediaUiModel import hu.bbara.purefin.ui.common.image.PurefinAsyncImage +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsSource +import hu.bbara.purefin.ui.common.media.rememberHomeMediaSharedBoundsClick @Composable internal fun NextUpCard( uiModel: MediaUiModel, + sharedBoundsKey: String, onMediaSelected: (MediaUiModel) -> Unit, modifier: Modifier = Modifier ) { val scheme = MaterialTheme.colorScheme + val onClick = rememberHomeMediaSharedBoundsClick(sharedBoundsKey) { + onMediaSelected(uiModel) + } Card( - onClick = { onMediaSelected(uiModel) }, + onClick = onClick, shape = RoundedCornerShape(24.dp), colors = CardDefaults.cardColors(containerColor = scheme.surfaceContainer), modifier = modifier.width(256.dp) @@ -42,6 +48,7 @@ internal fun NextUpCard( Column(modifier = Modifier.fillMaxWidth()) { Box( modifier = Modifier + .homeMediaSharedBoundsSource(sharedBoundsKey) .fillMaxWidth() .aspectRatio(16f / 10f) .background(scheme.surface) diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/nextup/NextUpSection.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/nextup/NextUpSection.kt index 117d7c3e..dce69d1e 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/nextup/NextUpSection.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/nextup/NextUpSection.kt @@ -7,13 +7,14 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import hu.bbara.purefin.ui.common.header.SectionHeader +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsKey import hu.bbara.purefin.ui.model.MediaUiModel @Composable @@ -42,9 +43,10 @@ fun NextUpSection( modifier = Modifier.fillMaxWidth(), state = listState ) { - items(items = items, key = { item -> item.id }) { item -> + itemsIndexed(items = items, key = { _, item -> item.id }) { index, item -> NextUpCard( uiModel = item, + sharedBoundsKey = homeMediaSharedBoundsKey("next-up-$index", item.id), onMediaSelected = onMediaSelected ) } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/movie/MovieScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/movie/MovieScreen.kt index 472bdb9f..d1842ec2 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/movie/MovieScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/movie/MovieScreen.kt @@ -39,6 +39,8 @@ import hu.bbara.purefin.model.Movie import hu.bbara.purefin.navigation.MovieDto import hu.bbara.purefin.ui.common.media.MediaHero import hu.bbara.purefin.ui.common.media.MediaMetadataFlowRow +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsDestination +import hu.bbara.purefin.ui.common.media.isHomeMediaSharedBoundsTransitionActive import hu.bbara.purefin.ui.screen.movie.components.MovieDetails import hu.bbara.purefin.ui.screen.movie.components.MovieTopBar import hu.bbara.purefin.ui.screen.waiting.PurefinWaitingScreen @@ -94,14 +96,18 @@ private fun MovieScreenInternal( onBack: () -> Unit, modifier: Modifier = Modifier, ) { + val isHomeMediaTransitionActive = isHomeMediaSharedBoundsTransitionActive() + Scaffold( modifier = modifier, containerColor = MaterialTheme.colorScheme.background, topBar = { - MovieTopBar( - onBack = onBack, - modifier = Modifier - ) + if (!isHomeMediaTransitionActive) { + MovieTopBar( + onBack = onBack, + modifier = Modifier + ) + } } ) { innerPadding -> Column( @@ -110,15 +116,17 @@ private fun MovieScreenInternal( .verticalScroll(rememberScrollState()) ) { MediaHeroSection(movie = movie) - MovieDetails( - movie = movie, - downloadState = downloadState, - onDownloadClick = onDownloadClick, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(bottom = innerPadding.calculateBottomPadding()) - ) + if (!isHomeMediaTransitionActive) { + MovieDetails( + movie = movie, + downloadState = downloadState, + onDownloadClick = onDownloadClick, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .padding(bottom = innerPadding.calculateBottomPadding()) + ) + } } } } @@ -134,6 +142,7 @@ fun MediaHeroSection( Box ( modifier = modifier + .homeMediaSharedBoundsDestination() .height(sectionHeight) ) { MediaHero( diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/series/SeriesScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/series/SeriesScreen.kt index 0188bdc1..a047e869 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/series/SeriesScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/series/SeriesScreen.kt @@ -41,6 +41,8 @@ import hu.bbara.purefin.model.Series import hu.bbara.purefin.navigation.SeriesDto import hu.bbara.purefin.ui.common.media.MediaHero import hu.bbara.purefin.ui.common.media.MediaSynopsis +import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsDestination +import hu.bbara.purefin.ui.common.media.isHomeMediaSharedBoundsTransitionActive import hu.bbara.purefin.ui.screen.series.components.CastRow import hu.bbara.purefin.ui.screen.series.components.EpisodeCarousel import hu.bbara.purefin.ui.screen.series.components.SeasonTabs @@ -103,6 +105,7 @@ private fun SeriesScreenInternal( modifier: Modifier = Modifier, ) { val scheme = MaterialTheme.colorScheme + val isHomeMediaTransitionActive = isHomeMediaSharedBoundsTransitionActive() fun getDefaultSeason() : Season { for (season in series.seasons) { @@ -131,10 +134,12 @@ private fun SeriesScreenInternal( modifier = modifier, containerColor = MaterialTheme.colorScheme.background, topBar = { - SeriesTopBar( - onBack = onBack, - modifier = Modifier - ) + if (!isHomeMediaTransitionActive) { + SeriesTopBar( + onBack = onBack, + modifier = Modifier + ) + } } ) { innerPadding -> Column( @@ -143,48 +148,50 @@ private fun SeriesScreenInternal( .verticalScroll(rememberScrollState()) ) { SeriesHeroSection(series = series) - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(bottom = innerPadding.calculateBottomPadding()) - ) { - SeriesActionButtons( - nextUpEpisode = nextUpEpisode, - seriesDownloadState = seriesDownloadState, - selectedSeason = selectedSeason, - seasonDownloadState = seasonDownloadState, - onDownloadOptionSelected = { option -> - onDownloadOptionSelected(option, selectedSeason) - } - ) - Spacer(modifier = Modifier.height(24.dp)) - MediaSynopsis( - synopsis = series.synopsis, - bodyColor = scheme.onSurface, - bodyFontSize = 13.sp, - bodyLineHeight = null, - titleSpacing = 8.dp - ) - Spacer(modifier = Modifier.height(24.dp)) - SeasonTabs( - seasons = series.seasons, - selectedSeason = selectedSeason, - onSelect = { selectedSeasonId = it.id } - ) - EpisodeCarousel( - episodes = selectedSeason.episodes, - ) - Spacer(modifier = Modifier.height(16.dp)) - if(series.cast.isNotEmpty()) { - Text( - text = "Cast", - color = scheme.onBackground, - fontSize = 18.sp, - fontWeight = FontWeight.Bold + if (!isHomeMediaTransitionActive) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .padding(bottom = innerPadding.calculateBottomPadding()) + ) { + SeriesActionButtons( + nextUpEpisode = nextUpEpisode, + seriesDownloadState = seriesDownloadState, + selectedSeason = selectedSeason, + seasonDownloadState = seasonDownloadState, + onDownloadOptionSelected = { option -> + onDownloadOptionSelected(option, selectedSeason) + } ) - Spacer(modifier = Modifier.height(12.dp)) - CastRow(cast = series.cast) + Spacer(modifier = Modifier.height(24.dp)) + MediaSynopsis( + synopsis = series.synopsis, + bodyColor = scheme.onSurface, + bodyFontSize = 13.sp, + bodyLineHeight = null, + titleSpacing = 8.dp + ) + Spacer(modifier = Modifier.height(24.dp)) + SeasonTabs( + seasons = series.seasons, + selectedSeason = selectedSeason, + onSelect = { selectedSeasonId = it.id } + ) + EpisodeCarousel( + episodes = selectedSeason.episodes, + ) + Spacer(modifier = Modifier.height(16.dp)) + if(series.cast.isNotEmpty()) { + Text( + text = "Cast", + color = scheme.onBackground, + fontSize = 18.sp, + fontWeight = FontWeight.Bold + ) + Spacer(modifier = Modifier.height(12.dp)) + CastRow(cast = series.cast) + } } } } @@ -202,6 +209,7 @@ private fun SeriesHeroSection( Box( modifier = modifier + .homeMediaSharedBoundsDestination() .fillMaxWidth() .height(sectionHeight) ) {