Skip to content

Commit 296f80a

Browse files
authored
Merge pull request #1618 from theovilardo/fix/navbar-disappear-animation
Fix/navbar disappear animation
2 parents 89edd0b + 00da53e commit 296f80a

5 files changed

Lines changed: 85 additions & 31 deletions

File tree

app/src/main/java/com/theveloper/pixelplay/MainActivity.kt

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import androidx.compose.runtime.CompositionLocalProvider
6868
import androidx.compose.runtime.setValue
6969
import androidx.compose.ui.Alignment
7070
import androidx.compose.ui.Modifier
71+
import androidx.compose.ui.draw.clipToBounds
7172
import androidx.compose.ui.graphics.graphicsLayer
7273
import androidx.compose.ui.layout.onSizeChanged
7374
import androidx.compose.ui.platform.LocalDensity
@@ -634,6 +635,50 @@ class MainActivity : ComponentActivity() {
634635
} else {
635636
0.dp
636637
}
638+
val animatedBottomBarPadding by animateDpAsState(
639+
targetValue = if (navBarStyle == NavBarStyle.FULL_WIDTH) 0.dp else systemNavBarInset,
640+
animationSpec = tween(400),
641+
label = "BottomBarPadding"
642+
)
643+
val bottomBarPadding = animatedBottomBarPadding
644+
val navBarHeight = if (navBarStyle == NavBarStyle.DEFAULT) {
645+
NavBarContentHeight
646+
} else {
647+
NavBarContentHeightFullWidth + systemNavBarInset
648+
}
649+
val navBarOccupiedHeight by remember(navBarHeight, bottomBarPadding) {
650+
derivedStateOf { navBarHeight + bottomBarPadding }
651+
}
652+
val navBarVisibilityProgress by animateFloatAsState(
653+
targetValue = if (shouldHideNavigationBar) 0f else 1f,
654+
animationSpec = tween(
655+
durationMillis = 220,
656+
easing = LinearOutSlowInEasing
657+
),
658+
label = "NavBarVisibilityProgress"
659+
)
660+
val visibleNavBarOccupiedHeight by remember(navBarOccupiedHeight, navBarVisibilityProgress) {
661+
derivedStateOf { navBarOccupiedHeight * navBarVisibilityProgress }
662+
}
663+
val miniPlayerBottomMargin by remember(systemNavBarInset, visibleNavBarOccupiedHeight) {
664+
derivedStateOf {
665+
if (visibleNavBarOccupiedHeight > systemNavBarInset) {
666+
visibleNavBarOccupiedHeight
667+
} else {
668+
systemNavBarInset
669+
}
670+
}
671+
}
672+
val shouldRenderNavigationBar by remember(shouldHideNavigationBar, navBarVisibilityProgress) {
673+
derivedStateOf {
674+
!shouldHideNavigationBar || navBarVisibilityProgress > 0.01f
675+
}
676+
}
677+
val isNavBarEffectivelyHidden by remember(shouldHideNavigationBar, navBarVisibilityProgress) {
678+
derivedStateOf {
679+
shouldHideNavigationBar && navBarVisibilityProgress <= 0.01f
680+
}
681+
}
637682

638683
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
639684
val scope = rememberCoroutineScope()
@@ -689,7 +734,7 @@ class MainActivity : ComponentActivity() {
689734
Scaffold(
690735
modifier = Modifier.fillMaxSize(),
691736
bottomBar = {
692-
if (!shouldHideNavigationBar) {
737+
if (shouldRenderNavigationBar) {
693738
val playerContentExpansionFraction = playerViewModel.playerContentExpansionFraction.value
694739
val currentSongId by remember {
695740
playerViewModel.stablePlayerState
@@ -753,13 +798,6 @@ class MainActivity : ComponentActivity() {
753798
)
754799
}
755800

756-
val animatedBottomBarPadding by animateDpAsState(
757-
targetValue = if (navBarStyle == NavBarStyle.FULL_WIDTH) 0.dp else systemNavBarInset,
758-
animationSpec = tween(400),
759-
label = "BottomBarPadding"
760-
)
761-
val bottomBarPadding = animatedBottomBarPadding
762-
763801
var componentHeightPx by remember { mutableStateOf(0) }
764802
val density = LocalDensity.current
765803
val shadowOverflowPx = remember(navBarElevation, density) {
@@ -782,26 +820,24 @@ class MainActivity : ComponentActivity() {
782820
Box(
783821
modifier = Modifier
784822
.fillMaxWidth()
785-
.padding(bottom = bottomBarPadding)
786-
.onSizeChanged { componentHeightPx = it.height }
787-
.graphicsLayer {
788-
translationY = animatedTranslationY
789-
alpha = 1f
790-
}
823+
.height(visibleNavBarOccupiedHeight)
824+
.clipToBounds()
791825
) {
792-
val navHeight: Dp = if (navBarStyle == NavBarStyle.DEFAULT) {
793-
NavBarContentHeight
794-
} else {
795-
NavBarContentHeightFullWidth + systemNavBarInset
796-
}
797826
val onSearchIconDoubleTap = remember(playerViewModel) {
798827
{ playerViewModel.onSearchNavIconDoubleTapped() }
799828
}
800829

801830
Surface(
802831
modifier = Modifier
832+
.align(Alignment.BottomCenter)
803833
.fillMaxWidth()
804-
.height(navHeight)
834+
.padding(bottom = bottomBarPadding)
835+
.onSizeChanged { componentHeightPx = it.height }
836+
.graphicsLayer {
837+
translationY = animatedTranslationY
838+
alpha = 1f
839+
}
840+
.height(navBarHeight)
805841
.padding(horizontal = horizontalPadding),
806842
color = NavigationBarDefaults.containerColor,
807843
shape = actualShape,
@@ -841,7 +877,7 @@ class MainActivity : ComponentActivity() {
841877
val miniPlayerH = with(density) { MiniPlayerHeight.toPx() }
842878
val totalSheetHeightWhenContentCollapsedPx = if (showPlayerContentInitially && !shouldHideMiniPlayer) miniPlayerH else 0f
843879

844-
val bottomMargin = innerPadding.calculateBottomPadding()
880+
val bottomMargin = miniPlayerBottomMargin
845881

846882
val spacerPx = with(density) { MiniPlayerBottomSpacer.toPx() }
847883
val sheetCollapsedTargetY = screenHeightPx - totalSheetHeightWhenContentCollapsedPx - with(density){ bottomMargin.toPx() } - spacerPx
@@ -863,7 +899,7 @@ class MainActivity : ComponentActivity() {
863899
hideMiniPlayer = shouldHideMiniPlayer,
864900
containerHeight = containerHeight,
865901
navController = navController,
866-
isNavBarHidden = shouldHideNavigationBar
902+
isNavBarHidden = isNavBarEffectivelyHidden
867903
)
868904
} else {
869905
UnifiedPlayerSheet(
@@ -873,7 +909,7 @@ class MainActivity : ComponentActivity() {
873909
hideMiniPlayer = shouldHideMiniPlayer,
874910
containerHeight = containerHeight,
875911
navController = navController,
876-
isNavBarHidden = shouldHideNavigationBar
912+
isNavBarHidden = isNavBarEffectivelyHidden
877913
)
878914
}
879915

app/src/main/java/com/theveloper/pixelplay/presentation/components/UnifiedPlayerSheet.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@ import androidx.compose.runtime.key
6161
import androidx.compose.runtime.mutableStateOf
6262
import androidx.compose.runtime.remember
6363
import androidx.compose.runtime.rememberCoroutineScope
64+
import androidx.compose.runtime.rememberUpdatedState
6465
import androidx.compose.runtime.setValue
6566
import androidx.compose.runtime.staticCompositionLocalOf
67+
import androidx.compose.runtime.snapshotFlow
6668
import com.theveloper.pixelplay.ui.theme.LocalPixelPlayDarkTheme
6769
import androidx.compose.ui.Alignment
6870
import androidx.compose.ui.Modifier
@@ -296,8 +298,12 @@ fun UnifiedPlayerSheet(
296298
)
297299
}
298300

299-
LaunchedEffect(sheetCollapsedTargetY) {
300-
sheetMotionController.syncToExpansion(sheetCollapsedTargetY)
301+
val sheetCollapsedTargetYState = rememberUpdatedState(sheetCollapsedTargetY)
302+
LaunchedEffect(sheetMotionController) {
303+
snapshotFlow { sheetCollapsedTargetYState.value }
304+
.collect { collapsedTargetY ->
305+
sheetMotionController.syncToExpansion(collapsedTargetY)
306+
}
301307
}
302308

303309
var previousSheetState by remember { mutableStateOf(currentSheetContentState) }

app/src/main/java/com/theveloper/pixelplay/presentation/components/UnifiedPlayerSheetV2.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ import androidx.compose.runtime.getValue
3232
import androidx.compose.runtime.mutableStateOf
3333
import androidx.compose.runtime.remember
3434
import androidx.compose.runtime.rememberCoroutineScope
35+
import androidx.compose.runtime.rememberUpdatedState
3536
import androidx.compose.runtime.setValue
37+
import androidx.compose.runtime.snapshotFlow
3638
import androidx.compose.ui.Modifier
3739
import androidx.compose.ui.draw.clipToBounds
3840
import androidx.compose.ui.draw.shadow
@@ -267,8 +269,12 @@ fun UnifiedPlayerSheetV2(
267269
)
268270
}
269271

270-
LaunchedEffect(sheetCollapsedTargetY) {
271-
sheetMotionController.syncToExpansion(sheetCollapsedTargetY)
272+
val sheetCollapsedTargetYState = rememberUpdatedState(sheetCollapsedTargetY)
273+
LaunchedEffect(sheetMotionController) {
274+
snapshotFlow { sheetCollapsedTargetYState.value }
275+
.collect { collapsedTargetY ->
276+
sheetMotionController.syncToExpansion(collapsedTargetY)
277+
}
272278
}
273279

274280
var previousSheetState by remember { mutableStateOf(currentSheetContentState) }

app/src/main/java/com/theveloper/pixelplay/presentation/components/scoped/PlayerAlbumNavigationEffect.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package com.theveloper.pixelplay.presentation.components.scoped
22

33
import androidx.compose.runtime.Composable
44
import androidx.compose.runtime.LaunchedEffect
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.runtime.rememberUpdatedState
57
import androidx.navigation.NavHostController
68
import com.theveloper.pixelplay.presentation.navigation.Screen
79
import com.theveloper.pixelplay.presentation.navigation.navigateSafely
@@ -15,9 +17,10 @@ internal fun PlayerAlbumNavigationEffect(
1517
sheetMotionController: SheetMotionController,
1618
playerViewModel: PlayerViewModel
1719
) {
18-
LaunchedEffect(navController, sheetCollapsedTargetY) {
20+
val latestSheetCollapsedTargetY by rememberUpdatedState(sheetCollapsedTargetY)
21+
LaunchedEffect(navController) {
1922
playerViewModel.albumNavigationRequests.collectLatest { albumId ->
20-
sheetMotionController.snapCollapsed(sheetCollapsedTargetY)
23+
sheetMotionController.snapCollapsed(latestSheetCollapsedTargetY)
2124
playerViewModel.collapsePlayerSheet()
2225

2326
navController.navigateSafely(Screen.AlbumDetail.createRoute(albumId)) {

app/src/main/java/com/theveloper/pixelplay/presentation/components/scoped/PlayerArtistNavigationEffect.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import com.theveloper.pixelplay.presentation.navigation.navigateSafely
44

55
import androidx.compose.runtime.Composable
66
import androidx.compose.runtime.LaunchedEffect
7+
import androidx.compose.runtime.getValue
8+
import androidx.compose.runtime.rememberUpdatedState
79
import androidx.navigation.NavHostController
810
import com.theveloper.pixelplay.presentation.navigation.Screen
911
import com.theveloper.pixelplay.presentation.viewmodel.PlayerViewModel
@@ -16,9 +18,10 @@ internal fun PlayerArtistNavigationEffect(
1618
sheetMotionController: SheetMotionController,
1719
playerViewModel: PlayerViewModel
1820
) {
19-
LaunchedEffect(navController, sheetCollapsedTargetY) {
21+
val latestSheetCollapsedTargetY by rememberUpdatedState(sheetCollapsedTargetY)
22+
LaunchedEffect(navController) {
2023
playerViewModel.artistNavigationRequests.collectLatest { artistId ->
21-
sheetMotionController.snapCollapsed(sheetCollapsedTargetY)
24+
sheetMotionController.snapCollapsed(latestSheetCollapsedTargetY)
2225
playerViewModel.collapsePlayerSheet()
2326

2427
navController.navigateSafely(Screen.ArtistDetail.createRoute(artistId)) {

0 commit comments

Comments
 (0)