From 3c621dcae761a30ac07ac493d1f49e62df9c76fb Mon Sep 17 00:00:00 2001 From: Ellen Poe Date: Mon, 8 Dec 2025 10:55:29 -0800 Subject: [PATCH] chore: update dependency versions --- cardinal-android/app/build.gradle.kts | 2 +- .../earth/maps/cardinal/data/BoundingBox.kt | 4 +- .../java/earth/maps/cardinal/data/Place.kt | 2 +- .../earth/maps/cardinal/data/PolylineUtils.kt | 3 +- .../maps/cardinal/data/ViewportPreferences.kt | 3 +- .../maps/cardinal/routing/FerrostarWrapper.kt | 9 ++-- .../earth/maps/cardinal/ui/core/AppContent.kt | 4 +- .../earth/maps/cardinal/ui/core/MapView.kt | 39 +++++++++------- .../maps/cardinal/ui/core/MapViewModel.kt | 32 ++++++++------ .../ui/directions/DirectionsScreen.kt | 2 +- .../maps/cardinal/ui/map/LocationPuck.kt | 11 ++--- .../maps/cardinal/ui/core/MapViewModelTest.kt | 2 +- cardinal-android/gradle/libs.versions.toml | 44 +++++++++---------- 13 files changed, 87 insertions(+), 70 deletions(-) diff --git a/cardinal-android/app/build.gradle.kts b/cardinal-android/app/build.gradle.kts index cc66aac..e1190a3 100644 --- a/cardinal-android/app/build.gradle.kts +++ b/cardinal-android/app/build.gradle.kts @@ -26,7 +26,7 @@ plugins { alias(libs.plugins.hilt) alias(libs.plugins.cargo.ndk) alias(libs.plugins.detekt) - kotlin("plugin.serialization") version "2.2.10" + kotlin("plugin.serialization") version "2.2.21" } android { diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/data/BoundingBox.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/data/BoundingBox.kt index 66942cc..963ae74 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/data/BoundingBox.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/data/BoundingBox.kt @@ -21,8 +21,8 @@ package earth.maps.cardinal.data data class BoundingBox( val north: Double, val south: Double, val east: Double, val west: Double ) { - fun toGeoJsonBoundingBox(): io.github.dellisd.spatialk.geojson.BoundingBox { - return io.github.dellisd.spatialk.geojson.BoundingBox( + fun toGeoJsonBoundingBox(): org.maplibre.spatialk.geojson.BoundingBox { + return org.maplibre.spatialk.geojson.BoundingBox( north = north, south = south, west = west, diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/data/Place.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/data/Place.kt index e57db4c..1636073 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/data/Place.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/data/Place.kt @@ -18,7 +18,7 @@ package earth.maps.cardinal.data -import io.github.dellisd.spatialk.geojson.Position +import org.maplibre.spatialk.geojson.Position data class Place( val id: String? = null, diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/data/PolylineUtils.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/data/PolylineUtils.kt index 912b409..77c7634 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/data/PolylineUtils.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/data/PolylineUtils.kt @@ -18,7 +18,8 @@ package earth.maps.cardinal.data -import io.github.dellisd.spatialk.geojson.Position +import org.maplibre.spatialk.geojson.Position + /** * Utility functions for working with encoded polylines and route geometry. diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/data/ViewportPreferences.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/data/ViewportPreferences.kt index 2185216..d206d8f 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/data/ViewportPreferences.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/data/ViewportPreferences.kt @@ -21,6 +21,7 @@ package earth.maps.cardinal.data import android.content.Context import android.content.SharedPreferences import org.maplibre.compose.camera.CameraPosition +import org.maplibre.spatialk.geojson.Position /** * Helper class to save and load viewport preferences using SharedPreferences. @@ -68,7 +69,7 @@ class ViewportPreferences(context: Context) { val tilt = prefs.getDouble(KEY_TILT, 0.0) return CameraPosition( - target = io.github.dellisd.spatialk.geojson.Position(longitude, latitude), + target = Position(longitude, latitude), zoom = zoom, bearing = bearing, tilt = tilt diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/routing/FerrostarWrapper.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/routing/FerrostarWrapper.kt index e37001d..d156913 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/routing/FerrostarWrapper.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/routing/FerrostarWrapper.kt @@ -43,6 +43,7 @@ import uniffi.ferrostar.RouteAdapter import uniffi.ferrostar.RouteDeviationTracking import uniffi.ferrostar.UserLocation import uniffi.ferrostar.WaypointAdvanceMode +import uniffi.ferrostar.WellKnownRouteProvider import uniffi.ferrostar.stepAdvanceDistanceEntryAndExit import uniffi.ferrostar.stepAdvanceDistanceToEndOfStep import java.util.concurrent.Executor @@ -111,13 +112,13 @@ class FerrostarWrapper( var core = FerrostarCore( - routeAdapter = RouteAdapter.newValhallaHttp( + routeAdapter = RouteAdapter.fromWellKnownRouteProvider(WellKnownRouteProvider.Valhalla( endpointUrl = localValhallaEndpoint, profile = mode.value, optionsJson = routingOptions?.toValhallaOptionsJson() ?: routingProfileRepository.createDefaultOptionsForMode(mode) ?.toValhallaOptionsJson() - ), + )), httpClient = OkHttpClientProvider(OkHttpClient()), locationProvider = locationProvider, navigationControllerConfig = NavigationControllerConfig( @@ -144,11 +145,11 @@ class FerrostarWrapper( val routingOptions = newRoutingOptions ?: previousRouteOptions previousRouteOptions = routingOptions core = FerrostarCore( - routeAdapter = RouteAdapter.newValhallaHttp( + routeAdapter = RouteAdapter.fromWellKnownRouteProvider(WellKnownRouteProvider.Valhalla( endpointUrl = localValhallaEndpoint, profile = mode.value, optionsJson = previousRouteOptions?.toValhallaOptionsJson() - ), + )), httpClient = OkHttpClientProvider(OkHttpClient()), locationProvider = locationProvider, navigationControllerConfig = NavigationControllerConfig( diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/AppContent.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/AppContent.kt index 648024b..1fdea8f 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/AppContent.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/AppContent.kt @@ -129,11 +129,11 @@ import earth.maps.cardinal.ui.settings.ProfileEditorScreen import earth.maps.cardinal.ui.settings.RoutingProfilesScreen import earth.maps.cardinal.ui.settings.SettingsScreen import earth.maps.cardinal.ui.settings.SettingsViewModel -import io.github.dellisd.spatialk.geojson.BoundingBox -import io.github.dellisd.spatialk.geojson.Position import kotlinx.coroutines.launch import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraState +import org.maplibre.spatialk.geojson.BoundingBox +import org.maplibre.spatialk.geojson.Position val TOOLBAR_HEIGHT_DP = 64.dp diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/MapView.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/MapView.kt index 109786e..f0b8886 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/MapView.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/MapView.kt @@ -64,12 +64,6 @@ import earth.maps.cardinal.data.room.SavedPlace import earth.maps.cardinal.transit.Itinerary import earth.maps.cardinal.transit.Mode import earth.maps.cardinal.ui.map.LocationPuck -import io.github.dellisd.spatialk.geojson.Feature -import io.github.dellisd.spatialk.geojson.FeatureCollection -import io.github.dellisd.spatialk.geojson.LineString -import io.github.dellisd.spatialk.geojson.Point -import io.github.dellisd.spatialk.geojson.Polygon -import io.github.dellisd.spatialk.geojson.Position import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement @@ -99,6 +93,13 @@ import org.maplibre.compose.sources.rememberGeoJsonSource import org.maplibre.compose.style.BaseStyle import org.maplibre.compose.style.rememberStyleState import org.maplibre.compose.util.ClickResult +import org.maplibre.spatialk.geojson.Feature +import org.maplibre.spatialk.geojson.FeatureCollection +import org.maplibre.spatialk.geojson.LineString +import org.maplibre.spatialk.geojson.Point +import org.maplibre.spatialk.geojson.Polygon +import org.maplibre.spatialk.geojson.Position +import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection import uniffi.ferrostar.Route import kotlin.math.max import kotlin.math.min @@ -223,7 +224,7 @@ fun MapView( @Composable private fun FavoritesLayer( - savedPlaces: FeatureCollection, + savedPlaces: FeatureCollection>, activeMarkers: List, isSystemInDarkTheme: Boolean ) { @@ -231,7 +232,7 @@ private fun FavoritesLayer( val activeMarkerIds = activeMarkers.mapNotNull { it.id } SymbolLayer( id = "user_favorites", - source = rememberGeoJsonSource(GeoJsonData.Features(savedPlaces)), + source = rememberGeoJsonSource(GeoJsonData.JsonString(Json.encodeToString(savedPlaces))), iconAllowOverlap = const(true), iconImage = image( if (isSystemInDarkTheme) { @@ -281,9 +282,15 @@ private fun OfflineBoundsLayer(selectedOfflineArea: OfflineArea?) { ) ) ) - val boundsFeature = Feature(geometry = boundsPolygon) + val boundsFeature = Feature(geometry = boundsPolygon, properties = null) val offlineDownloadBoundsSource = rememberGeoJsonSource( - GeoJsonData.Features(FeatureCollection(features = listOf(boundsFeature))) + GeoJsonData.JsonString( + Json.encodeToString( + buildFeatureCollection { + add(boundsFeature) + } + ) + ) ) val color = MaterialTheme.colorScheme.onSurface @@ -340,7 +347,7 @@ private fun RouteLayer(viewModel: MapViewModel, currentRoute: Route?, allRoutes: // Create single source for all routes val routeSource = rememberGeoJsonSource( - GeoJsonData.Features(FeatureCollection(features = routeFeatures)) + GeoJsonData.JsonString(Json.encodeToString(FeatureCollection(features = routeFeatures))) ) // Route casing layer @@ -425,7 +432,7 @@ private fun RouteAnnotations( ) } val annotationSource = rememberGeoJsonSource( - GeoJsonData.Features(FeatureCollection(features = features)) + GeoJsonData.JsonString(Json.encodeToString(FeatureCollection(features = features))) ) val textHaloColor = MaterialTheme.colorScheme.surface val textColor = MaterialTheme.colorScheme.onSurface @@ -461,9 +468,9 @@ private fun TransitLayer(currentTransitItinerary: Itinerary?) { ) if (positions.isNotEmpty()) { val lineString = LineString(positions) - val feature = Feature(geometry = lineString) + val feature = Feature(geometry = lineString, properties = null) val source = rememberGeoJsonSource( - GeoJsonData.Features(FeatureCollection(features = listOf(feature))) + GeoJsonData.JsonString(Json.encodeToString(FeatureCollection(features = listOf(feature)))) ) // Parse route color or use default based on mode @@ -517,10 +524,10 @@ private fun TransitLayer(currentTransitItinerary: Itinerary?) { } @Composable -private fun PinsLayer(pinFeatures: List, isSystemInDarkTheme: Boolean) { +private fun PinsLayer(pinFeatures: List>>, isSystemInDarkTheme: Boolean) { SymbolLayer( id = "map_pins", - source = rememberGeoJsonSource(GeoJsonData.Features(FeatureCollection(features = pinFeatures))), + source = rememberGeoJsonSource(GeoJsonData.JsonString(Json.encodeToString(FeatureCollection(features = pinFeatures)))), iconAllowOverlap = const(true), iconAnchor = const(SymbolAnchor.Bottom), iconImage = image( diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/MapViewModel.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/MapViewModel.kt index c32c65d..cb2408d 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/MapViewModel.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/MapViewModel.kt @@ -40,10 +40,6 @@ import earth.maps.cardinal.data.room.SavedPlace import earth.maps.cardinal.data.room.SavedPlaceDao import earth.maps.cardinal.geocoding.OfflineGeocodingService import earth.maps.cardinal.ui.util.AnnotationPlacer -import io.github.dellisd.spatialk.geojson.Feature -import io.github.dellisd.spatialk.geojson.FeatureCollection -import io.github.dellisd.spatialk.geojson.Point -import io.github.dellisd.spatialk.geojson.Position import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -54,6 +50,11 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.jsonPrimitive import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraState +import org.maplibre.spatialk.geojson.Feature +import org.maplibre.spatialk.geojson.FeatureCollection +import org.maplibre.spatialk.geojson.Geometry +import org.maplibre.spatialk.geojson.Point +import org.maplibre.spatialk.geojson.Position import uniffi.ferrostar.Route import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject @@ -94,14 +95,14 @@ class MapViewModel @Inject constructor( var screenHeight: Dp = 0.dp var screenWidth: Dp = 0.dp - val savedPlacesFlow: Flow = placeDao.getAllPlacesAsFlow().map { placeList -> + val savedPlacesFlow: Flow>> = placeDao.getAllPlacesAsFlow().map { placeList -> FeatureCollection(placeList.map { createFeatureFromSavedPlace(it) }) } /** * Creates a Feature from a Place with proper JSON escaping. */ - fun createFeatureFromPlace(place: Place): Feature { + fun createFeatureFromPlace(place: Place): Feature> { val properties = mutableMapOf( "name" to escapeJsonString(place.name), "description" to escapeJsonString(place.description), @@ -131,7 +132,7 @@ class MapViewModel @Inject constructor( /** * Creates a Feature from a SavedPlace with proper JSON escaping. */ - private fun createFeatureFromSavedPlace(place: SavedPlace): Feature { + private fun createFeatureFromSavedPlace(place: SavedPlace): Feature> { val name = place.customName ?: place.name val description = place.customDescription ?: place.type @@ -213,7 +214,7 @@ class MapViewModel @Inject constructor( if (routeAnnotationFeature != null) { // Extract route index from layer ID val routeIndex = - routeAnnotationFeature.properties["routeIndex"]?.jsonPrimitive?.content?.toIntOrNull() + routeAnnotationFeature.properties?.get("routeIndex")?.jsonPrimitive?.content?.toIntOrNull() if (routeIndex != null && onRouteAnnotationClick != null) { onRouteAnnotationClick(routeIndex) @@ -221,7 +222,7 @@ class MapViewModel @Inject constructor( } } - val features = cameraState.projection?.queryRenderedFeatures( + val features: List>>? = cameraState.projection?.queryRenderedFeatures( dpOffset, layerIds = setOf( "map_pins", @@ -231,7 +232,9 @@ class MapViewModel @Inject constructor( "poi_z16", "poi_transit" ) - ) + )?.map { feature -> + Feature(feature.geometry, feature.properties?.toMap() ?: mapOf()) + } Log.d(TAG, "${features?.count()} features available at tap location") val filteredFeatures = features?.filter { it.geometry is Point @@ -246,20 +249,23 @@ class MapViewModel @Inject constructor( val feature = convertFeatureToPlace( feature ) - onMapPoiClick(feature) + feature?.let { onMapPoiClick(it) } } else { onMapInteraction() } } - fun convertFeatureToPlace(feature: Feature): Place { + fun convertFeatureToPlace(feature: Feature>): Place? { // Convert JsonElement properties to Map val tags = feature.properties.mapValues { (_, value) -> value.jsonPrimitive.content } // Extract coordinates from geometry (assuming Point geometry) - val point = feature.geometry as Point + val point = feature.geometry + if (point !is Point) { + return null + } val coordinates = point.coordinates val longitude = coordinates.longitude val latitude = coordinates.latitude diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt index 2194e2a..fd04339 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt @@ -81,10 +81,10 @@ import earth.maps.cardinal.ui.core.NavigationUtils import earth.maps.cardinal.ui.core.Screen import earth.maps.cardinal.ui.place.SearchResults import earth.maps.cardinal.ui.saved.QuickSuggestions -import io.github.dellisd.spatialk.geojson.BoundingBox import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch +import org.maplibre.spatialk.geojson.BoundingBox import uniffi.ferrostar.Route enum class FieldFocusState { diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/map/LocationPuck.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/map/LocationPuck.kt index a7d81df..8fc9e1b 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/map/LocationPuck.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/map/LocationPuck.kt @@ -23,14 +23,15 @@ import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.ui.res.painterResource import earth.maps.cardinal.R.drawable -import io.github.dellisd.spatialk.geojson.Point -import io.github.dellisd.spatialk.geojson.Position +import kotlinx.serialization.json.Json import org.maplibre.compose.expressions.dsl.const import org.maplibre.compose.expressions.dsl.image import org.maplibre.compose.layers.SymbolLayer import org.maplibre.compose.sources.GeoJsonData import org.maplibre.compose.sources.Source import org.maplibre.compose.sources.rememberGeoJsonSource +import org.maplibre.spatialk.geojson.Point +import org.maplibre.spatialk.geojson.Position @Composable @@ -54,13 +55,13 @@ fun LocationPuck(location: Location, sensorHeading: Float? = null) { Log.d("Location", "$location") val locationSource = rememberGeoJsonSource( - data = GeoJsonData.Features( - Point( + data = GeoJsonData.JsonString( + Json.encodeToString(Point( coordinates = Position( location.longitude, location.latitude ), - ) + )) ) ) diff --git a/cardinal-android/app/src/test/java/earth/maps/cardinal/ui/core/MapViewModelTest.kt b/cardinal-android/app/src/test/java/earth/maps/cardinal/ui/core/MapViewModelTest.kt index 6d15d7b..17046a5 100644 --- a/cardinal-android/app/src/test/java/earth/maps/cardinal/ui/core/MapViewModelTest.kt +++ b/cardinal-android/app/src/test/java/earth/maps/cardinal/ui/core/MapViewModelTest.kt @@ -10,7 +10,6 @@ import earth.maps.cardinal.data.ViewportRepository import earth.maps.cardinal.data.room.SavedPlace import earth.maps.cardinal.geocoding.OfflineGeocodingService import earth.maps.cardinal.ui.util.AnnotationPlacer -import io.github.dellisd.spatialk.geojson.Position import io.mockk.coEvery import io.mockk.every import io.mockk.mockk @@ -25,6 +24,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.maplibre.compose.camera.CameraPosition +import org.maplibre.spatialk.geojson.Position import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner diff --git a/cardinal-android/gradle/libs.versions.toml b/cardinal-android/gradle/libs.versions.toml index 32d9c35..76c8a36 100644 --- a/cardinal-android/gradle/libs.versions.toml +++ b/cardinal-android/gradle/libs.versions.toml @@ -1,39 +1,39 @@ [versions] -agp = "8.13.0" +agp = "8.13.1" androidaddressformatter = "8f279fe" assertjCore = "3.27.6" desugar_jdk_libs = "2.1.5" -kotlin = "2.2.10" -ksp = "2.2.10-2.0.2" +kotlin = "2.2.21" +ksp = "2.2.21-2.0.4" coreKtx = "1.17.0" junit = "4.13.2" junitVersion = "1.3.0" espressoCore = "3.7.0" kotlinxCoroutinesAndroid = "1.10.2" kotlinSerializationJson = "1.9.0" -ktor = "3.2.3" -lifecycleRuntimeKtx = "2.9.3" -activityCompose = "1.10.1" -composeBom = "2025.08.01" -maplibreCompose = "0.11.1" +ktor = "3.3.3" +lifecycleRuntimeKtx = "2.10.0" +activityCompose = "1.12.1" +composeBom = "2025.12.00" +maplibreCompose = "0.12.1" robolectric = "4.16" -room = "2.7.2" -navigation = "2.9.3" -gson = "2.13.1" -hilt = "2.57.1" -hiltPlugin = "2.57.1" -hiltNavigationCompose = "1.2.0" +room = "2.8.4" +navigation = "2.9.6" +gson = "2.13.2" +hilt = "2.57.2" +hiltPlugin = "2.57.2" +hiltNavigationCompose = "1.3.0" cargo-ndk = "0.3.4" -valhallaMobile = "0.1.6" +valhallaMobile = "0.3.0" valhallaMobileConfig = "0.0.9" -ferrostar = "0.41.0" -okhttp3 = "5.1.0" -material3 = "1.5.0-alpha04" -detekt = "2.0.0-alpha.0" -mockk = "1.14.6" +ferrostar = "0.45.0" +okhttp3 = "5.3.2" +material3 = "1.5.0-alpha10" +detekt = "2.0.0-alpha.1" +mockk = "1.14.7" kotlinxCoroutinesTest = "1.10.2" -hiltAndroidTesting = "2.57.1" -openinghoursparser = "0.28.2" +hiltAndroidTesting = "2.57.2" +openinghoursparser = "0.29.0" [libraries] androidaddressformatter = { module = "com.github.woheller69:AndroidAddressFormatter", version.ref = "androidaddressformatter" } -- GitLab