Skip to content

Commit

Permalink
Don't use bottom sheets on non-android (#19)
Browse files Browse the repository at this point in the history
The skiko/native implementation is... bad, and super janky, and crashes.
  • Loading branch information
ZacSweers committed Jul 9, 2024
1 parent 068d198 commit 05db975
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 7 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ kotlin {
implementation(libs.circuit.foundation)
implementation(libs.circuit.overlay)
implementation(libs.circuitx.overlays)
implementation(libs.circuitx.gestureNav)
implementation(libs.ktor.client)
implementation(libs.okio)
implementation(libs.kotlinx.immutable)
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ bugsnag-android = "com.bugsnag:bugsnag-android:6.6.1"
circuit-foundation = { module = "com.slack.circuit:circuit-foundation", version.ref = "circuit" }
circuit-overlay = { module = "com.slack.circuit:circuit-overlay", version.ref = "circuit" }
circuitx-overlays = { module = "com.slack.circuit:circuitx-overlays", version.ref = "circuit" }
circuitx-gestureNav = { module = "com.slack.circuit:circuitx-gesture-navigation", version.ref = "circuit" }
compose-material-icons = { module = "org.jetbrains.compose.material:material-icons-core", version.ref = "compose-jb" }
compose-material-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-jb" }
# Tooling support (Previews, etc.)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (C) 2024 Zac Sweers
// SPDX-License-Identifier: Apache-2.0
package dev.zacsweers.fieldspottr.util

actual val CurrentPlatform: Platform = Platform.Android
2 changes: 1 addition & 1 deletion src/commonMain/composeResources/files/aboutlibraries.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/commonMain/kotlin/dev/zacsweers/fieldspottr/About.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
import com.slack.circuit.runtime.screen.StaticScreen
import dev.zacsweers.fieldspottr.parcel.CommonParcelize
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.withContext
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource

@CommonParcelize data object AboutScreen : StaticScreen

@OptIn(ExperimentalResourceApi::class)
@Composable
fun About(modifier: Modifier = Modifier) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.slack.circuit.foundation.CircuitCompositionLocals
import com.slack.circuit.foundation.NavigableCircuitContent
import com.slack.circuit.foundation.rememberCircuitNavigator
import com.slack.circuit.overlay.ContentWithOverlays
import com.slack.circuitx.gesturenavigation.GestureNavigationDecoration
import dev.zacsweers.fieldspottr.di.FSComponent
import dev.zacsweers.fieldspottr.theme.FSTheme

Expand All @@ -21,7 +22,11 @@ fun FieldSpottrApp(component: FSComponent, onRootPop: () -> Unit) {
val navigator = rememberCircuitNavigator(backStack) { onRootPop() }
CircuitCompositionLocals(component.circuit) {
ContentWithOverlays {
NavigableCircuitContent(navigator = navigator, backStack = backStack)
NavigableCircuitContent(
navigator = navigator,
backStack = backStack,
decoration = GestureNavigationDecoration(onBackInvoked = navigator::pop),
)
}
}
}
Expand Down
36 changes: 33 additions & 3 deletions src/commonMain/kotlin/dev/zacsweers/fieldspottr/Home.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.slack.circuit.overlay.OverlayEffect
import com.slack.circuit.retained.collectAsRetainedState
import com.slack.circuit.retained.rememberRetained
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.screen.Screen
import com.slack.circuitx.overlays.BottomSheetOverlay
import dev.zacsweers.fieldspottr.HomeScreen.Event.ChangeGroup
Expand All @@ -45,6 +46,8 @@ import dev.zacsweers.fieldspottr.PermitState.FieldState.Reserved
import dev.zacsweers.fieldspottr.data.Area
import dev.zacsweers.fieldspottr.data.PermitRepository
import dev.zacsweers.fieldspottr.parcel.CommonParcelize
import dev.zacsweers.fieldspottr.util.CurrentPlatform
import dev.zacsweers.fieldspottr.util.Platform
import kotlinx.coroutines.flow.map
import kotlinx.datetime.Clock.System
import kotlinx.datetime.LocalDate
Expand Down Expand Up @@ -78,8 +81,14 @@ data object HomeScreen : Screen {
}
}

/**
* The CM implementation of ModalBottomSheet on non-android platforms is extremely janky and crashy,
* so just make those go to new screens.
*/
private val USE_BOTTOM_SHEETS = CurrentPlatform == Platform.Android

@Composable
fun HomePresenter(repository: PermitRepository): HomeScreen.State {
fun HomePresenter(navigator: Navigator, repository: PermitRepository): HomeScreen.State {
var selectedDate by rememberRetained {
mutableStateOf(System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date)
}
Expand Down Expand Up @@ -123,7 +132,11 @@ fun HomePresenter(repository: PermitRepository): HomeScreen.State {
populateDb = true
}
is ShowInfo -> {
showInfo = event.show
if (USE_BOTTOM_SHEETS) {
showInfo = event.show
} else {
navigator.goTo(ScaffoldScreen(title = "", contentScreen = AboutScreen))
}
}
is FilterDate -> {
selectedDate = event.date
Expand All @@ -132,7 +145,24 @@ fun HomePresenter(repository: PermitRepository): HomeScreen.State {
selectedGroup = event.group
}
ClearEventDetail -> currentlyDetailedEvent = null
is ShowEventDetail -> currentlyDetailedEvent = event.event
is ShowEventDetail -> {
if (USE_BOTTOM_SHEETS) {
currentlyDetailedEvent = event.event
} else {
navigator.goTo(
ScaffoldScreen(
title = "Permit Details",
contentScreen =
PermitDetailsScreen(
name = event.event.title,
description = event.event.description,
group = selectedGroup,
org = event.event.org,
),
)
)
}
}
}
}
}
Expand Down
52 changes: 52 additions & 0 deletions src/commonMain/kotlin/dev/zacsweers/fieldspottr/ScaffoldScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (C) 2024 Zac Sweers
// SPDX-License-Identifier: Apache-2.0
package dev.zacsweers.fieldspottr

import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import com.slack.circuit.foundation.CircuitContent
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.screen.Screen
import dev.zacsweers.fieldspottr.parcel.CommonParcelize

@CommonParcelize
data class ScaffoldScreen(val title: String = "Field Spottr", val contentScreen: Screen) : Screen {
data class State(val title: String, val contentScreen: Screen, val onBackPressed: () -> Unit) :
CircuitUiState
}

@Composable
fun ScaffoldPresenter(screen: ScaffoldScreen, navigator: Navigator): ScaffoldScreen.State {
return ScaffoldScreen.State(screen.title, screen.contentScreen, navigator::pop)
}

@Composable
fun ScaffoldScreenContent(state: ScaffoldScreen.State, modifier: Modifier = Modifier) {
Scaffold(
modifier = modifier,
topBar = {
CenterAlignedTopAppBar(
title = { Text(state.title, fontWeight = FontWeight.Black, fontStyle = FontStyle.Italic) },
navigationIcon = {
// TODO platform-default back button?
IconButton(onClick = { state.onBackPressed() }) {
Icon(Icons.AutoMirrored.Default.ArrowBack, contentDescription = "Close")
}
},
)
},
) { innerPadding ->
CircuitContent(state.contentScreen, modifier = Modifier.padding(innerPadding))
}
}
17 changes: 15 additions & 2 deletions src/commonMain/kotlin/dev/zacsweers/fieldspottr/di/FSComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ package dev.zacsweers.fieldspottr.di

import androidx.compose.runtime.Immutable
import com.slack.circuit.foundation.Circuit
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.presenter.presenterOf
import dev.zacsweers.fieldspottr.About
import dev.zacsweers.fieldspottr.AboutScreen
import dev.zacsweers.fieldspottr.FSAppDirs
import dev.zacsweers.fieldspottr.Home
import dev.zacsweers.fieldspottr.HomePresenter
import dev.zacsweers.fieldspottr.HomeScreen
import dev.zacsweers.fieldspottr.PermitDetails
import dev.zacsweers.fieldspottr.PermitDetailsPresenter
import dev.zacsweers.fieldspottr.PermitDetailsScreen
import dev.zacsweers.fieldspottr.ScaffoldPresenter
import dev.zacsweers.fieldspottr.ScaffoldScreen
import dev.zacsweers.fieldspottr.ScaffoldScreenContent
import dev.zacsweers.fieldspottr.SqlDriverFactory
import dev.zacsweers.fieldspottr.data.PermitRepository

Expand All @@ -31,8 +37,8 @@ class FSComponent(private val shared: SharedPlatformFSComponent) :

val circuit: Circuit by lazy {
Circuit.Builder()
.addPresenter<HomeScreen, HomeScreen.State> { _, _, _ ->
presenterOf { HomePresenter(permitRepository) }
.addPresenter<HomeScreen, HomeScreen.State> { _, navigator, _ ->
presenterOf { HomePresenter(navigator, permitRepository) }
}
.addUi<HomeScreen, HomeScreen.State> { state, modifier -> Home(state, modifier) }
.addPresenter<PermitDetailsScreen, PermitDetailsScreen.State> { screen, _, _ ->
Expand All @@ -41,6 +47,13 @@ class FSComponent(private val shared: SharedPlatformFSComponent) :
.addUi<PermitDetailsScreen, PermitDetailsScreen.State> { state, modifier ->
PermitDetails(state, modifier)
}
.addPresenter<ScaffoldScreen, ScaffoldScreen.State> { screen, navigator, _ ->
presenterOf { ScaffoldPresenter(screen, navigator) }
}
.addUi<ScaffoldScreen, ScaffoldScreen.State> { state, modifier ->
ScaffoldScreenContent(state, modifier)
}
.addStaticUi<AboutScreen, CircuitUiState> { _, modifier -> About(modifier) }
.build()
}
}
11 changes: 11 additions & 0 deletions src/commonMain/kotlin/dev/zacsweers/fieldspottr/util/platform.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (C) 2024 Zac Sweers
// SPDX-License-Identifier: Apache-2.0
package dev.zacsweers.fieldspottr.util

enum class Platform {
Android,
Jvm,
Native,
}

expect val CurrentPlatform: Platform
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (C) 2024 Zac Sweers
// SPDX-License-Identifier: Apache-2.0
package dev.zacsweers.fieldspottr.util

actual val CurrentPlatform: Platform = Platform.Jvm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (C) 2024 Zac Sweers
// SPDX-License-Identifier: Apache-2.0
package dev.zacsweers.fieldspottr.util

actual val CurrentPlatform: Platform = Platform.Native

0 comments on commit 05db975

Please sign in to comment.