Skip to content

Commit

Permalink
Create computeable callable (#820)
Browse files Browse the repository at this point in the history
* Create computeable callable

* Reduce visibility of error serializable

* Remove routing dependency

* chore(deps): update terraform google to v5.16.0 (#844)

Co-authored-by: playground-manager[bot] <126197455+playground-manager[bot]@users.noreply.github.com>

* fix(deps): update slack.circuit to v0.19.1 (#843)

* fix(deps): update slack.circuit to v0.19.1

* Adjust saveable back stack with initial screen

* Provide fake navigator with initial screen

---------

Co-authored-by: playground-manager[bot] <126197455+playground-manager[bot]@users.noreply.github.com>
Co-authored-by: Ash Davies <[email protected]>

* Adjust lat lng state and callback

* Move state hoisting to expect function

* Commas

---------

Co-authored-by: playground-manager[bot] <126197455+playground-manager[bot]@users.noreply.github.com>
  • Loading branch information
ashdavies and playground-manager[bot] authored Feb 13, 2024
1 parent 4d964f5 commit 040e2f9
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal class GetEventsCallable(
}

@Serializable
public data class GetEventsError(
internal data class GetEventsError(
override val message: String,
val code: Int,
) : Throwable()
5 changes: 2 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ google-accompanist-placeholderMaterial = { module = "com.google.accompanist:acco

google-android-identity = "com.google.android.libraries.identity.googleid:googleid:1.1.0"
google-android-location = "com.google.android.gms:play-services-location:21.1.0"
google-android-maps = "com.google.android.gms:play-services-maps:18.2.0"
google-android-material = "com.google.android.material:material:1.11.0"

google-auth-http = "com.google.auth:google-auth-library-oauth2-http:1.23.0"
Expand All @@ -64,8 +63,8 @@ google-firebase-appcheck-playintegrity = { module = "com.google.firebase:firebas

google-guava-jre = "com.google.guava:guava:33.0.0-jre"

google-maps-android-compose = { module = "com.google.maps.android:maps-compose", version.ref = "google-maps-compose" }
google-maps-android-compose-widgets = { module = "com.google.maps.android:maps-compose-widgets", version.ref = "google-maps-compose" }
google-maps-android-compose = "com.google.maps.android:maps-compose:4.3.2"
google-maps-android-utils = "com.google.maps.android:android-maps-utils:3.8.2"

kotlinx-cli = "org.jetbrains.kotlinx:kotlinx-cli:0.3.6"
kotlinx-collections-immutable = "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7"
Expand Down
15 changes: 15 additions & 0 deletions map-routes/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ plugins {
id("io.ashdavies.default")
id("io.ashdavies.parcelable")
id("io.ashdavies.properties")

alias(libs.plugins.build.config)
}

android {
Expand All @@ -15,22 +17,35 @@ android {
namespace = "io.ashdavies.routes"
}

buildConfig {
val androidApiKey by stringProperty { value ->
buildConfigField("ANDROID_API_KEY", value)
}

packageName.set(android.namespace)
}

kotlin {
commonMain.dependencies {
implementation(projects.circuitSupport)
implementation(projects.httpClient)
implementation(projects.httpCommon)
implementation(projects.mapsRouting)
implementation(projects.platformSupport)

implementation(compose.material3)
implementation(compose.runtime)

implementation(libs.androidx.annotation)
implementation(libs.ktor.client.core)
implementation(libs.slack.circuit.foundation)
}

androidMain.dependencies {
implementation(libs.google.accompanist.permissions)
implementation(libs.google.android.location)
implementation(libs.google.maps.android.compose)
implementation(libs.google.maps.android.utils)
implementation(libs.kotlinx.coroutines.play.services)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,59 @@ import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.CameraPosition
import com.google.maps.android.PolyUtil
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.Marker
import com.google.maps.android.compose.MarkerState
import com.google.maps.android.compose.Polyline
import com.google.maps.android.compose.rememberCameraPositionState

public actual typealias LatLng = com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.LatLng as GmsLatLng

private const val CAMERA_ANIMATE_DURATION = 2_000

@Composable
internal actual fun RouteMap(state: RouteMapState, modifier: Modifier) {
internal actual fun RouteMap(
state: RouteMapState,
modifier: Modifier,
onEndPosition: (LatLng) -> Unit,
) {
val cameraPositionState = rememberCameraPositionState()

LaunchedEffect(state.startPosition, state.zoomLevel) {
val cameraPosition = CameraPosition.fromLatLngZoom(state.startPosition, state.zoomLevel)
val startPosition = state.startPosition.asGmsLatLng()
val cameraPosition = CameraPosition.fromLatLngZoom(startPosition, state.zoomLevel)
val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)

cameraPositionState.animate(cameraUpdate, CAMERA_ANIMATE_DURATION)
}

GoogleMap(
cameraPositionState = cameraPositionState,
modifier = modifier.fillMaxSize(),
onMapClick = { state.endPosition = it },
onMapClick = { onEndPosition(it.asLatLng()) },
) {
Marker(
state = MarkerState(state.startPosition),
state = MarkerState(state.startPosition.asGmsLatLng()),
icon = rememberGreenMarker(),
title = "Start",
)

val endPosition = state.endPosition
if (endPosition != null) {
Marker(
state = MarkerState(endPosition),
state = MarkerState(endPosition.asGmsLatLng()),
icon = rememberRedMarker(),
title = "End",
)
}

if (state.routes.isNotEmpty()) {
Polyline(
points = state.routes.flatMap {
PolyUtil.decode(it.polyline.encodedPolyline)
},
)
}
}
}

Expand All @@ -59,3 +74,13 @@ private fun rememberGreenMarker(): BitmapDescriptor = remember {
private fun rememberRedMarker(): BitmapDescriptor = remember {
BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)
}

private fun GmsLatLng.asLatLng() = LatLng(
latitude = latitude,
longitude = longitude,
)

private fun LatLng.asGmsLatLng() = GmsLatLng(
/* latitude = */ latitude,
/* longitude = */ longitude,
)
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package io.ashdavies.routes

import androidx.compose.runtime.remember
import com.slack.circuit.runtime.presenter.Presenter
import com.slack.circuit.runtime.ui.Ui
import io.ashdavies.circuit.presenterFactoryOf
import io.ashdavies.circuit.uiFactoryOf
import io.ashdavies.content.PlatformContext

public fun RoutePresenterFactory(context: PlatformContext): Presenter.Factory {
val locationService = LocationService(context)
return presenterFactoryOf<RouteScreen> { _, _ ->
RoutePresenter(locationService)
RoutePresenter(remember(context) { LocationService(context) })
}
}

public fun RouteUiFactory(): Ui.Factory {
return uiFactoryOf<RouteScreen, RouteScreen.State> { _, state, modifier ->
RouteScreen(state, modifier)
RouteScreen(state, modifier) { state.eventSink(RouteScreen.Event.OnEndPosition(it)) }
}
}
18 changes: 8 additions & 10 deletions map-routes/src/commonMain/kotlin/io/ashdavies/routes/RouteMap.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,25 @@ package io.ashdavies.routes

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import io.ashdavies.routing.ComputeRoutesResponse

@Stable
internal data class RouteMapState(
val startPosition: LatLng = KnownLocations.Berlin,
val endPosition: LatLng? = null,
val routes: List<ComputeRoutesResponse.Route> = emptyList(),
val zoomLevel: Float = 12f,
) {

var endPosition by mutableStateOf<LatLng?>(null)
}
)

@Composable
internal expect fun RouteMap(
state: RouteMapState,
modifier: Modifier = Modifier,
onEndPosition: (LatLng) -> Unit,
)

public expect class LatLng(
latitude: Double,
longitude: Double,
internal data class LatLng(
val latitude: Double,
val longitude: Double,
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.ashdavies.http.LocalHttpClient
import io.ashdavies.routing.ComputeRoutesCallable
import io.ashdavies.routing.ComputeRoutesError
import io.ashdavies.routing.ComputeRoutesRequest
import io.ktor.client.HttpClient

@Composable
internal fun RoutePresenter(locationService: LocationService): RouteScreen.State {
internal fun RoutePresenter(
locationService: LocationService,
httpClient: HttpClient = LocalHttpClient.current,
): RouteScreen.State {
var startPosition by remember { mutableStateOf(KnownLocations.Berlin) }
val locationPermissionState = rememberLocationPermissionState()

Expand All @@ -19,9 +27,32 @@ internal fun RoutePresenter(locationService: LocationService): RouteScreen.State
}
}

val computeRoutes = remember { ComputeRoutesCallable(httpClient, BuildConfig.ANDROID_API_KEY) }
var mapState by remember { mutableStateOf(RouteMapState(startPosition)) }
var errorMessage = null as String?

LaunchedEffect(mapState.endPosition) {
val endPosition = mapState.endPosition ?: return@LaunchedEffect

val computeRoutesRequest = ComputeRoutesRequest(
origin = mapState.startPosition.asComputeRoutesRequestLatLng(),
destination = endPosition.asComputeRoutesRequestLatLng(),
)

try {
val computeRoutesResponse = computeRoutes(computeRoutesRequest)
mapState = mapState.copy(routes = computeRoutesResponse.routes)
} catch (exception: ComputeRoutesError) {
errorMessage = exception.message
}
}

return RouteScreen.State(
mapState = RouteMapState(
startPosition = startPosition,
),
mapState = mapState,
errorMessage = errorMessage,
) { }
}

private fun LatLng.asComputeRoutesRequestLatLng(): ComputeRoutesRequest.LatLng {
return ComputeRoutesRequest.LatLng(latitude, longitude)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ public fun RouteScreen(): Screen = RouteScreen

@Parcelize
internal object RouteScreen : Screen {
sealed interface Event : CircuitUiEvent
sealed interface Event : CircuitUiEvent {
data class OnEndPosition(val position: LatLng) : Event
}

data class State(
val mapState: RouteMapState,
val mapState: RouteMapState = RouteMapState(),
val errorMessage: String? = null,
val eventSink: (Event) -> Unit,
) : CircuitUiState
}
Expand All @@ -23,9 +26,11 @@ internal object RouteScreen : Screen {
internal fun RouteScreen(
state: RouteScreen.State,
modifier: Modifier = Modifier,
onEndPosition: (LatLng) -> Unit,
) {
RouteMap(
state = state.mapState,
modifier = modifier,
onEndPosition = onEndPosition,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier

public actual class LatLng actual constructor(
latitude: Double,
longitude: Double,
)

@Composable
internal actual fun RouteMap(state: RouteMapState, modifier: Modifier) {
internal actual fun RouteMap(
state: RouteMapState,
modifier: Modifier,
onEndPosition: (LatLng) -> Unit,
) {
Text("Unsupported Platform")
}
18 changes: 18 additions & 0 deletions maps-routing/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
plugins {
id("io.ashdavies.default")
}

android {
namespace = "io.ashdavies.routing"
}

kotlin {
commonMain.dependencies {
implementation(projects.httpClient)
implementation(projects.httpCommon)

implementation(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.datetime)
implementation(libs.ktor.client.core)
}
}
2 changes: 2 additions & 0 deletions maps-routing/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />
Loading

0 comments on commit 040e2f9

Please sign in to comment.