From 0bf968a42b05332111fb13d4141ecd2f724609ef Mon Sep 17 00:00:00 2001 From: Barnabas Balogh Date: Sat, 6 Jun 2026 10:38:40 +0000 Subject: [PATCH] feat(ui): make top bars scroll aware --- .../ui/common/media/MediaDetailScaffold.kt | 15 ++-- .../ui/screen/episode/EpisodeScreen.kt | 5 +- .../episode/components/EpisodeComponents.kt | 7 +- .../purefin/ui/screen/home/HomeScreen.kt | 12 +++- .../screen/home/components/DefaultTopBar.kt | 70 +++++++++---------- .../ui/screen/home/components/HomeTopBar.kt | 5 ++ .../home/components/search/SearchScreen.kt | 15 +++- .../ui/screen/libraries/LibrariesScreen.kt | 11 ++- .../libraries/components/LibrariesTopBar.kt | 5 ++ .../ui/screen/library/LibraryScreen.kt | 12 +++- .../library/components/LibraryTopBar.kt | 5 ++ .../purefin/ui/screen/movie/MovieScreen.kt | 9 ++- .../movie/components/MovieComponents.kt | 7 +- .../purefin/ui/screen/series/SeriesScreen.kt | 9 ++- .../series/components/SeriesComponents.kt | 8 ++- .../ui/screen/settings/SettingsScreen.kt | 20 +++++- 16 files changed, 157 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/hu/bbara/purefin/ui/common/media/MediaDetailScaffold.kt b/app/src/main/java/hu/bbara/purefin/ui/common/media/MediaDetailScaffold.kt index 70bca9c9..24d3df7c 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/common/media/MediaDetailScaffold.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/common/media/MediaDetailScaffold.kt @@ -11,17 +11,22 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import hu.bbara.purefin.ui.common.image.PurefinAsyncImage +@OptIn(ExperimentalMaterial3Api::class) @Composable fun MediaDetailScaffold( imageUrl: String, @@ -29,19 +34,22 @@ fun MediaDetailScaffold( imageHeight: Dp = 320.dp, contentOverlap: Dp = 24.dp, contentSpacing: Dp = 16.dp, - topBar: @Composable () -> Unit = {}, + topBar: @Composable (scrollBehavior: TopAppBarScrollBehavior) -> Unit = {}, heroContent: @Composable ColumnScope.(Modifier) -> Unit, content: @Composable ColumnScope.(Modifier) -> Unit ) { val scheme = MaterialTheme.colorScheme val isHomeMediaTransitionActive = isHomeMediaSharedBoundsTransitionActive() + val topBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() Scaffold( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize() + .nestedScroll(topBarScrollBehavior.nestedScrollConnection), containerColor = scheme.background, topBar = { if (!isHomeMediaTransitionActive) { - topBar() + topBar(topBarScrollBehavior) } } ) { innerPadding -> @@ -86,4 +94,3 @@ fun MediaDetailScaffold( } } } - 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 cd39a2c6..08d9b8cd 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 @@ -1,5 +1,6 @@ package hu.bbara.purefin.ui.screen.episode +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -77,6 +78,7 @@ fun EpisodeScreen( ) } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun EpisodeScreenInternal( episode: Episode, @@ -89,10 +91,11 @@ private fun EpisodeScreenInternal( MediaDetailScaffold( imageUrl = ImageUrlBuilder.finishImageUrl(episode.imageUrlPrefix, ArtworkKind.PRIMARY), modifier = modifier, - topBar = { + topBar = { scrollBehavior -> EpisodeTopBar( shortcut = topBarShortcut, onBack = onBack, + scrollBehavior = scrollBehavior ) }, heroContent = { _modifier -> diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/episode/components/EpisodeComponents.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/episode/components/EpisodeComponents.kt index 4cd1af22..5643c503 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/episode/components/EpisodeComponents.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/episode/components/EpisodeComponents.kt @@ -12,9 +12,11 @@ import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.Cast import androidx.compose.material.icons.outlined.MoreVert import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -47,10 +49,12 @@ internal sealed interface EpisodeTopBarShortcut { } } +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun EpisodeTopBar( shortcut: EpisodeTopBarShortcut?, onBack: () -> Unit, + scrollBehavior: TopAppBarScrollBehavior? = null, ) { DefaultTopBar( leftActions = { @@ -93,7 +97,8 @@ internal fun EpisodeTopBar( contentDescription = "More", onClick = { }) }, - withIcon = false + withIcon = false, + scrollBehavior = scrollBehavior ) } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/HomeScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/HomeScreen.kt index 19ddf546..f1192025 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/HomeScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/HomeScreen.kt @@ -2,19 +2,23 @@ package hu.bbara.purefin.ui.screen.home import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import hu.bbara.purefin.core.model.LibraryUiModel import hu.bbara.purefin.core.model.MediaUiModel import hu.bbara.purefin.ui.screen.AppBottomBar import hu.bbara.purefin.ui.screen.home.components.HomeContent import hu.bbara.purefin.ui.screen.home.components.HomeTopBar +import hu.bbara.purefin.ui.screen.home.components.rememberDefaultTopBarScrollBehavior import java.util.UUID +@OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeScreen( libraries: List, @@ -39,9 +43,12 @@ fun HomeScreen( onTabSelected: (Int) -> Unit, modifier: Modifier = Modifier ) { + val topBarScrollBehavior = rememberDefaultTopBarScrollBehavior() + Scaffold( modifier = modifier - .fillMaxSize(), + .fillMaxSize() + .nestedScroll(topBarScrollBehavior.nestedScrollConnection), containerColor = MaterialTheme.colorScheme.background, contentColor = MaterialTheme.colorScheme.onBackground, topBar = { @@ -51,7 +58,8 @@ fun HomeScreen( onCheckForUpdates = onCheckForUpdates, isCheckingForUpdates = isCheckingForUpdates, onSettingsClick = onSettingsClick, - onLogoutClick = onLogoutClick + onLogoutClick = onLogoutClick, + scrollBehavior = topBarScrollBehavior ) }, snackbarHost = { SnackbarHost(snackbarHostState) }, diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/DefaultTopBar.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/DefaultTopBar.kt index ae7a770d..68abdf64 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/DefaultTopBar.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/DefaultTopBar.kt @@ -7,19 +7,19 @@ import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Search +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonColors import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -32,58 +32,58 @@ import hu.bbara.purefin.navigation.LocalNavSharedAnimatedVisibilityScope import hu.bbara.purefin.navigation.LocalSharedTransitionScope import hu.bbara.purefin.ui.common.image.PurefinLogo +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun rememberDefaultTopBarScrollBehavior(): TopAppBarScrollBehavior = + TopAppBarDefaults.pinnedScrollBehavior() + +@OptIn(ExperimentalMaterial3Api::class) @Composable fun DefaultTopBar( leftActions: (@Composable RowScope.() -> Unit)? = null, rightActions: (@Composable RowScope.() -> Unit)? = null, - withIcon: Boolean = true + withIcon: Boolean = true, + scrollBehavior: TopAppBarScrollBehavior? = null ) { val scheme = MaterialTheme.colorScheme - Surface( - color = Color.Transparent, - contentColor = scheme.onSurface, - modifier = Modifier.fillMaxWidth() - ) { - Row( - modifier = Modifier - .statusBarsPadding() - .height(84.dp) - .padding(horizontal = 16.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { + TopAppBar( + title = { + if (withIcon) { + PurefinLogo( + modifier = Modifier.size(56.dp), + ) + } + }, + navigationIcon = { if (leftActions != null) { Row( + modifier = Modifier.padding(start = 8.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp), content = leftActions ) } - if (withIcon) { - Row( - modifier = Modifier, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = when { - leftActions == null && rightActions != null -> Arrangement.Start - leftActions != null && rightActions == null -> Arrangement.Center - else -> Arrangement.Center - } - ) { - PurefinLogo( - modifier = Modifier.size(56.dp), - ) - } - } + }, + actions = { if (rightActions != null) { Row( + modifier = Modifier.padding(end = 8.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp), content = rightActions ) } - } - } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Transparent, + scrolledContainerColor = scheme.background, + navigationIconContentColor = scheme.onSurface, + titleContentColor = scheme.onSurface, + actionIconContentColor = scheme.onSurface + ), + scrollBehavior = scrollBehavior + ) } @Composable diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/HomeTopBar.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/HomeTopBar.kt index 0bb71527..ad2890c1 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/HomeTopBar.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/HomeTopBar.kt @@ -4,13 +4,16 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Person import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +@OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeTopBar( onSearchClick: () -> Unit, @@ -19,10 +22,12 @@ fun HomeTopBar( isCheckingForUpdates: Boolean, onSettingsClick: () -> Unit, onLogoutClick: () -> Unit, + scrollBehavior: TopAppBarScrollBehavior? = null, ) { var isProfileMenuExpanded by remember { mutableStateOf(false) } DefaultTopBar( + scrollBehavior = scrollBehavior, rightActions = { DefaultTopBarSearchButton(onClick = onSearchClick) DefaultTopBarIconButton( diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/search/SearchScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/search/SearchScreen.kt index 4076953c..f8451d05 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/search/SearchScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/components/search/SearchScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.Search import androidx.compose.material.icons.outlined.Tune import androidx.compose.material3.AlertDialog +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilterChip import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -38,6 +39,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -46,6 +48,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.font.FontWeight @@ -64,6 +67,7 @@ import hu.bbara.purefin.navigation.LocalNavSharedAnimatedVisibilityScope import hu.bbara.purefin.navigation.LocalSharedTransitionScope import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar import hu.bbara.purefin.ui.screen.home.components.DefaultTopBarIconButton +import hu.bbara.purefin.ui.screen.home.components.rememberDefaultTopBarScrollBehavior import hu.bbara.purefin.ui.theme.AppTheme import java.util.UUID @@ -126,7 +130,7 @@ fun SearchScreen( ) } -@OptIn(ExperimentalLayoutApi::class) +@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class) @Composable private fun SearchScreenContent( query: String, @@ -142,13 +146,17 @@ private fun SearchScreenContent( modifier: Modifier = Modifier ) { val scheme = MaterialTheme.colorScheme + val topBarScrollBehavior = rememberDefaultTopBarScrollBehavior() + Scaffold( topBar = { SearchHeader( - onBack = onBack + onBack = onBack, + scrollBehavior = topBarScrollBehavior ) }, modifier = modifier .fillMaxSize() .testTag(SearchScreenTag) + .nestedScroll(topBarScrollBehavior.nestedScrollConnection) .background(scheme.background) ) { innerPadding -> Column( @@ -216,10 +224,13 @@ private fun SearchResults( } @Composable +@OptIn(ExperimentalMaterial3Api::class) private fun SearchHeader( onBack: () -> Unit, + scrollBehavior: TopAppBarScrollBehavior? = null, ) { DefaultTopBar( + scrollBehavior = scrollBehavior, leftActions = { DefaultTopBarIconButton( imageVector = Icons.Outlined.ArrowBack, diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/LibrariesScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/LibrariesScreen.kt index 69bac55f..06ab4195 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/LibrariesScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/LibrariesScreen.kt @@ -2,15 +2,19 @@ package hu.bbara.purefin.ui.screen.libraries import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import hu.bbara.purefin.core.model.LibraryUiModel import hu.bbara.purefin.ui.screen.AppBottomBar +import hu.bbara.purefin.ui.screen.home.components.rememberDefaultTopBarScrollBehavior import hu.bbara.purefin.ui.screen.libraries.components.LibrariesContent import hu.bbara.purefin.ui.screen.libraries.components.LibrariesTopBar +@OptIn(ExperimentalMaterial3Api::class) @Composable fun LibrariesScreen( items: List, @@ -21,13 +25,18 @@ fun LibrariesScreen( onTabSelected: (Int) -> Unit, modifier: Modifier = Modifier ) { + val topBarScrollBehavior = rememberDefaultTopBarScrollBehavior() + Scaffold( - modifier = modifier.fillMaxSize(), + modifier = modifier + .fillMaxSize() + .nestedScroll(topBarScrollBehavior.nestedScrollConnection), containerColor = MaterialTheme.colorScheme.background, contentColor = MaterialTheme.colorScheme.onBackground, topBar = { LibrariesTopBar( onSearchClick = onSearchClick, + scrollBehavior = topBarScrollBehavior ) }, bottomBar = { diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibrariesTopBar.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibrariesTopBar.kt index 1ef6d5bd..82fcbe97 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibrariesTopBar.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/components/LibrariesTopBar.kt @@ -1,14 +1,19 @@ package hu.bbara.purefin.ui.screen.libraries.components +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar import hu.bbara.purefin.ui.screen.home.components.DefaultTopBarSearchButton +@OptIn(ExperimentalMaterial3Api::class) @Composable fun LibrariesTopBar( onSearchClick: () -> Unit, + scrollBehavior: TopAppBarScrollBehavior? = null, ) { DefaultTopBar( + scrollBehavior = scrollBehavior, rightActions = { DefaultTopBarSearchButton(onClick = onSearchClick) } 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 298080cd..e766e77a 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 @@ -10,6 +10,7 @@ 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.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable @@ -17,6 +18,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel @@ -28,8 +30,10 @@ import hu.bbara.purefin.core.model.SeriesUiModel import hu.bbara.purefin.core.navigation.LibraryDto import hu.bbara.purefin.ui.common.badge.WatchStateBadge import hu.bbara.purefin.ui.common.card.MediaImageCard +import hu.bbara.purefin.ui.screen.home.components.rememberDefaultTopBarScrollBehavior import hu.bbara.purefin.ui.screen.library.components.LibraryTopBar +@OptIn(ExperimentalMaterial3Api::class) @Composable fun LibraryScreen( library: LibraryDto, @@ -41,14 +45,18 @@ fun LibraryScreen( } val libraryItems = viewModel.contents.collectAsStateWithLifecycle() + val topBarScrollBehavior = rememberDefaultTopBarScrollBehavior() Scaffold( - modifier = modifier.testTag(LibraryScreenTag), + modifier = modifier + .testTag(LibraryScreenTag) + .nestedScroll(topBarScrollBehavior.nestedScrollConnection), containerColor = MaterialTheme.colorScheme.background, contentColor = MaterialTheme.colorScheme.onBackground, topBar = { LibraryTopBar( - onBack = { viewModel.onBack() } + onBack = { viewModel.onBack() }, + scrollBehavior = topBarScrollBehavior ) } ) { innerPadding -> diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/library/components/LibraryTopBar.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/library/components/LibraryTopBar.kt index 398928bc..492e6757 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/library/components/LibraryTopBar.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/library/components/LibraryTopBar.kt @@ -3,15 +3,20 @@ package hu.bbara.purefin.ui.screen.library.components import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.outlined.FilterAlt +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar import hu.bbara.purefin.ui.screen.home.components.DefaultTopBarIconButton +@OptIn(ExperimentalMaterial3Api::class) @Composable fun LibraryTopBar( onBack: () -> Unit, + scrollBehavior: TopAppBarScrollBehavior? = null, ) { DefaultTopBar( + scrollBehavior = scrollBehavior, leftActions = { DefaultTopBarIconButton( imageVector = Icons.AutoMirrored.Outlined.ArrowBack, 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 c18e5d49..ea5f8f62 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 @@ -1,5 +1,6 @@ package hu.bbara.purefin.ui.screen.movie +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -63,6 +64,7 @@ fun MovieScreen( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun MovieScreenInternal( movie: Movie, @@ -74,8 +76,11 @@ private fun MovieScreenInternal( MediaDetailScaffold( imageUrl = ImageUrlBuilder.finishImageUrl(movie.imageUrlPrefix, ArtworkKind.PRIMARY), modifier = modifier, - topBar = { - MovieTopBar(onBack = onBack) + topBar = { scrollBehavior -> + MovieTopBar( + onBack = onBack, + scrollBehavior = scrollBehavior + ) }, heroContent = { _modifier -> MovieHeroContent( diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/movie/components/MovieComponents.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/movie/components/MovieComponents.kt index e5e16537..072ff393 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/movie/components/MovieComponents.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/movie/components/MovieComponents.kt @@ -11,8 +11,10 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.Cast import androidx.compose.material.icons.outlined.MoreVert +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -34,9 +36,11 @@ import hu.bbara.purefin.ui.common.media.mediaPlayButtonText import hu.bbara.purefin.ui.common.media.mediaPlaybackProgress import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun MovieTopBar( onBack: () -> Unit, + scrollBehavior: TopAppBarScrollBehavior? = null, ) { DefaultTopBar( leftActions = { @@ -53,7 +57,8 @@ internal fun MovieTopBar( contentDescription = "More", onClick = { }) }, - withIcon = false + withIcon = false, + scrollBehavior = scrollBehavior ) } 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 ebabe8e8..2398ea0e 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 @@ -2,6 +2,7 @@ package hu.bbara.purefin.ui.screen.series import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -112,6 +113,7 @@ fun SeriesScreen( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun SeriesScreenInternal( series: Series, @@ -148,8 +150,11 @@ private fun SeriesScreenInternal( MediaDetailScaffold( imageUrl = ImageUrlBuilder.finishImageUrl(series.imageUrlPrefix, ArtworkKind.PRIMARY), modifier = modifier, - topBar = { - SeriesTopBar(onBack = onBack) + topBar = { scrollBehavior -> + SeriesTopBar( + onBack = onBack, + scrollBehavior = scrollBehavior + ) }, heroContent = { _modifier -> SeriesHeroContent( diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/series/components/SeriesComponents.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/series/components/SeriesComponents.kt index 4378727e..37c9d82c 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/series/components/SeriesComponents.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/series/components/SeriesComponents.kt @@ -35,6 +35,7 @@ import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -77,10 +78,12 @@ import hu.bbara.purefin.ui.common.media.mediaPlayButtonText import hu.bbara.purefin.ui.common.media.mediaPlaybackProgress import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun SeriesTopBar( onBack: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + scrollBehavior: TopAppBarScrollBehavior? = null ) { DefaultTopBar( leftActions = { @@ -95,7 +98,8 @@ internal fun SeriesTopBar( GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = { }) } }, - withIcon = false + withIcon = false, + scrollBehavior = scrollBehavior ) } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/settings/SettingsScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/settings/SettingsScreen.kt index a38582f1..ee4e92f7 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/settings/SettingsScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/settings/SettingsScreen.kt @@ -13,16 +13,19 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -36,6 +39,7 @@ import hu.bbara.purefin.core.settings.StringSetting import hu.bbara.purefin.core.settings.VoidSetting import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar import hu.bbara.purefin.ui.screen.home.components.DefaultTopBarIconButton +import hu.bbara.purefin.ui.screen.home.components.rememberDefaultTopBarScrollBehavior import hu.bbara.purefin.ui.screen.settings.components.BooleanSettingItem import hu.bbara.purefin.ui.screen.settings.components.DropdownSettingItem import hu.bbara.purefin.ui.screen.settings.components.RangeSettingItem @@ -43,6 +47,7 @@ import hu.bbara.purefin.ui.screen.settings.components.ReadOnlySettingItem import hu.bbara.purefin.ui.screen.settings.components.StringSettingItem import hu.bbara.purefin.ui.screen.settings.components.VoidSettingItem +@OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsScreen( viewModel: SettingsViewModel = hiltViewModel(), @@ -50,6 +55,7 @@ fun SettingsScreen( ) { val settingGroups by viewModel.settingGroups.collectAsStateWithLifecycle() val snackbarHostState = remember { SnackbarHostState() } + val topBarScrollBehavior = rememberDefaultTopBarScrollBehavior() LaunchedEffect(viewModel) { viewModel.snackbarMessages.collect { message -> @@ -58,12 +64,17 @@ fun SettingsScreen( } Scaffold( - modifier = modifier.fillMaxSize(), + modifier = modifier + .fillMaxSize() + .nestedScroll(topBarScrollBehavior.nestedScrollConnection), containerColor = MaterialTheme.colorScheme.background, contentColor = MaterialTheme.colorScheme.onBackground, snackbarHost = { SnackbarHost(snackbarHostState) }, topBar = { - SettingsTopBar(onBack = viewModel::onBack) + SettingsTopBar( + onBack = viewModel::onBack, + scrollBehavior = topBarScrollBehavior + ) } ) { innerPadding -> LazyColumn( @@ -224,11 +235,14 @@ private fun DropdownSettingOptionItem( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun SettingsTopBar( - onBack: () -> Unit + onBack: () -> Unit, + scrollBehavior: TopAppBarScrollBehavior? = null ) { DefaultTopBar( + scrollBehavior = scrollBehavior, leftActions = { DefaultTopBarIconButton( imageVector = Icons.AutoMirrored.Outlined.ArrowBack,