From fb8053ef60c4e8be73b31cde1b05f73a2e78f9cb Mon Sep 17 00:00:00 2001 From: Arty Bishop Date: Sun, 21 Sep 2025 18:20:24 +0100 Subject: [PATCH] Added animated visibility to the FloatingBar component --- .../look4sat/presentation/MainTheme.kt | 4 +- .../presentation/passes/PassesScreen.kt | 38 ++++++++++++++----- gradle/libs.versions.toml | 12 +++--- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/MainTheme.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/MainTheme.kt index 53939008..40b0d080 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/MainTheme.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/MainTheme.kt @@ -117,8 +117,8 @@ private val shapes = Shapes( extraSmall = RoundedCornerShape(4.dp), // menus, snackbars, text fields small = RoundedCornerShape(6.dp), // buttons, chips medium = RoundedCornerShape(8.dp), // cards, small FABs - large = RoundedCornerShape(12.dp), // extended FABs, FABs, nav drawers - extraLarge = RoundedCornerShape(16.dp) // large FABs + large = RoundedCornerShape(24.dp), // extended FABs, FABs, nav drawers + extraLarge = RoundedCornerShape(32.dp) // large FABs ) private val typography = Typography( diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt index 4c1f9e86..a2a9eb0f 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt @@ -1,5 +1,9 @@ package com.rtbishop.look4sat.presentation.passes +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -12,8 +16,10 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -25,6 +31,8 @@ import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource @@ -97,7 +105,10 @@ private fun PassesScreen(uiState: PassesState, navActions: NavActions) { uiState.takeAction(PassesAction.DismissWelcome) } } - ScreenColumn(floatingBar = { PassesFloatingBar(navActions) }) { isVerticalLayout -> + val gridState = rememberLazyGridState() + ScreenColumn( + floatingBar = { PassesFloatingBar(gridState.isScrolling(), navActions) } + ) { isVerticalLayout -> if (isVerticalLayout) { TopBar { IconCard(action = { showPassesDialog() }, resId = R.drawable.ic_filter) @@ -113,17 +124,19 @@ private fun PassesScreen(uiState: PassesState, navActions: NavActions) { IconCard(action = { showRadiosDialog() }, resId = R.drawable.ic_satellite) } } - PassesList(uiState.isRefreshing, uiState.itemsList, navActions.openRadar, refreshList) + PassesList(uiState.isRefreshing, uiState.itemsList, navActions.openRadar, refreshList, gridState) } } @Composable -private fun PassesFloatingBar(navActions: NavActions) { - FloatingBar( - startAction = navActions.openSettings, startIconResId = R.drawable.ic_settings, - centerAction = navActions.openSatellites, centerIconResId = R.drawable.ic_sputnik, - endAction = navActions.openMap, endIconResId = R.drawable.ic_map - ) +private fun PassesFloatingBar(visible: Boolean, navActions: NavActions) { + AnimatedVisibility(visible = visible, enter = fadeIn(tween(250)), exit = fadeOut(tween(250))) { + FloatingBar( + startAction = navActions.openSettings, startIconResId = R.drawable.ic_settings, + centerAction = navActions.openSatellites, centerIconResId = R.drawable.ic_sputnik, + endAction = navActions.openMap, endIconResId = R.drawable.ic_map + ) + } } @OptIn(ExperimentalMaterial3Api::class) @@ -132,7 +145,8 @@ private fun PassesList( isRefreshing: Boolean, passes: List, navigateToRadar: (Int, Long) -> Unit, - refreshPasses: () -> Unit + refreshPasses: () -> Unit, + gridState: LazyGridState ) { val isVerticalLayout = isVerticalLayout() val refreshState = rememberPullToRefreshState() @@ -155,6 +169,7 @@ private fun PassesList( EmptyListCard(message = stringResource(R.string.passes_empty_list_message)) } else { LazyVerticalGrid( + state = gridState, columns = GridCells.Adaptive(320.dp), modifier = Modifier.fillMaxSize() ) { @@ -310,3 +325,8 @@ private fun NearEarthPass( } } } + +@Composable +private fun LazyGridState.isScrolling(): Boolean { + return remember { derivedStateOf { !isScrollInProgress } }.value +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 83eb9797..ec3dad43 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,13 +5,12 @@ kotlin = "2.2.20" androidx-core-ktx = "1.17.0" androidx-core-splashscreen = "1.0.1" -androidx-room = "2.8.0" +androidx-room = "2.8.1" -compose-bom = "2025.09.00" +compose-bom = "2025.09.01" compose-activity = "1.11.0" -compose-lifecycle = "2.9.3" -#compose-material3 = "1.4.0-rc01" -compose-navigation = "2.9.4" +compose-lifecycle = "2.9.4" +compose-navigation = "2.9.5" other-coroutines = "1.10.2" other-json = "20250517" @@ -19,7 +18,7 @@ other-okhttp = "5.1.0" other-osmdroid = "6.1.20" test-junit4 = "4.13.2" -test-mockk = "1.14.5" +test-mockk = "1.14.6" androidTest-junit = "1.3.0" androidTest-espresso = "3.7.0" @@ -40,7 +39,6 @@ compose-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } compose-activity = { module = "androidx.activity:activity-compose", version.ref = "compose-activity" } compose-lifecycle = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "compose-lifecycle" } -#compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "compose-material3" } compose-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "compose-navigation" } compose-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "compose-lifecycle" }