diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index f0715ba..e5800d2 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -52,6 +52,7 @@ kotlin { implementation(libs.moko.geo) implementation(libs.moko.geo.compose) implementation(projects.shared) + implementation(libs.ui.backhandler) } } diff --git a/composeApp/src/commonMain/kotlin/moe/lava/banksia/App.kt b/composeApp/src/commonMain/kotlin/moe/lava/banksia/App.kt index 7ed1423..b1229bf 100644 --- a/composeApp/src/commonMain/kotlin/moe/lava/banksia/App.kt +++ b/composeApp/src/commonMain/kotlin/moe/lava/banksia/App.kt @@ -18,13 +18,16 @@ import androidx.compose.material3.rememberStandardBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.backhandler.PredictiveBackHandler import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import dev.icerock.moko.geo.compose.BindLocationTrackerEffect @@ -44,6 +47,7 @@ import moe.lava.banksia.resources.my_location_24 import moe.lava.banksia.ui.Searcher import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.ui.tooling.preview.Preview +import kotlin.coroutines.cancellation.CancellationException import kotlin.math.roundToInt fun buildBounds(points: List): Pair { @@ -64,7 +68,7 @@ fun buildBounds(points: List): Pair { return Pair(Point(north, east), Point(south, west)) } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) @Composable @Preview fun App() { @@ -138,12 +142,17 @@ fun App() { newCameraPosition = Pair(Point(0.0, 0.0), bounds) } + var sheetSwipeEnabled by remember { mutableStateOf(true) } + var peekHeight by remember { mutableStateOf(128.dp) } + var peekHeightMultiplier by remember { mutableFloatStateOf(1F) } + MaterialTheme { BottomSheetScaffold( scaffoldState = scaffoldState, - sheetPeekHeight = 250.dp, + sheetPeekHeight = peekHeight * peekHeightMultiplier, modifier = Modifier.fillMaxSize(), sheetContent = { Box(modifier = Modifier) }, + sheetSwipeEnabled = sheetSwipeEnabled, ) { Maps( modifier = Modifier.fillMaxSize(), @@ -161,6 +170,27 @@ fun App() { onRouteChange = { route = it } ) + PredictiveBackHandler(scaffoldState.bottomSheetState.currentValue != SheetValue.Hidden) { progress -> + sheetSwipeEnabled = false + try { + progress.collect { backEvent -> + if (scaffoldState.bottomSheetState.currentValue == SheetValue.PartiallyExpanded) { + peekHeightMultiplier = 1F - backEvent.progress + } + } + if (scaffoldState.bottomSheetState.currentValue == SheetValue.Expanded) + scope.launch { scaffoldState.bottomSheetState.partialExpand() } + else if (scaffoldState.bottomSheetState.currentValue == SheetValue.PartiallyExpanded) + scope.launch { + scaffoldState.bottomSheetState.hide() + peekHeightMultiplier = 1F + } + } catch (_: CancellationException) { + peekHeightMultiplier = 1F + } + sheetSwipeEnabled = true + } + Box( Modifier.windowInsetsPadding(WindowInsets.safeContent.add(WindowInsets(bottom = extInsets))), contentAlignment = Alignment.BottomEnd diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d269c9d..2e3f43f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ androidx-espresso-core = "3.6.1" androidx-lifecycle = "2.8.4" androidx-material = "1.12.0" androidx-test-junit = "1.2.1" -compose-multiplatform = "1.7.3" +compose-multiplatform = "1.8.0-beta02" coroutines = "1.9.0" geo = "0.8.0" junit = "4.13.2" @@ -57,6 +57,7 @@ okio = { module = "com.squareup.okio:okio", version.ref = "okio" } play-services-location = { module = "com.google.android.gms:play-services-location", version.ref = "playServicesLocation" } play-services-maps = { module = "com.google.android.gms:play-services-maps", version.ref = "playServicesMaps" } secrets-gradle-plugin = { module = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin", version.ref = "secretsGradlePlugin" } +ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.ref = "compose-multiplatform" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" }