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 6c1431773b907838b935b505d4e0128d08d6c8ec..109786ee54b98b87c45cd046eb8d5af12d069ee3 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 @@ -60,6 +60,7 @@ import earth.maps.cardinal.data.PolylineUtils import earth.maps.cardinal.data.desaturate import earth.maps.cardinal.data.formatDuration import earth.maps.cardinal.data.room.OfflineArea +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 @@ -76,7 +77,10 @@ import kotlinx.serialization.json.encodeToJsonElement import org.maplibre.compose.camera.CameraState import org.maplibre.compose.expressions.dsl.Feature.get import org.maplibre.compose.expressions.dsl.Feature.has +import org.maplibre.compose.expressions.dsl.asString +import org.maplibre.compose.expressions.dsl.collator import org.maplibre.compose.expressions.dsl.const +import org.maplibre.compose.expressions.dsl.feature import org.maplibre.compose.expressions.dsl.image import org.maplibre.compose.expressions.dsl.offset import org.maplibre.compose.expressions.dsl.rgbColor @@ -181,9 +185,7 @@ fun MapView( val location by mapViewModel.locationFlow.collectAsState() val sensorHeading by mapViewModel.heading.collectAsState() val savedPlaces by mapViewModel.savedPlacesFlow.collectAsState(FeatureCollection()) - location?.let { LocationPuck(it, sensorHeading) } - - FavoritesLayer(savedPlaces, isSystemInDarkTheme()) + FavoritesLayer(savedPlaces, mapPins, isSystemInDarkTheme()) OfflineBoundsLayer(selectedOfflineArea) @@ -192,6 +194,8 @@ fun MapView( TransitLayer(currentTransitItinerary) PinsLayer(pinFeatures, isSystemInDarkTheme()) + + location?.let { LocationPuck(it, sensorHeading) } } } else { // Handle invalid port - could show an error message @@ -218,11 +222,17 @@ fun MapView( } @Composable -private fun FavoritesLayer(savedPlaces: FeatureCollection, isSystemInDarkTheme: Boolean) { +private fun FavoritesLayer( + savedPlaces: FeatureCollection, + activeMarkers: List, + isSystemInDarkTheme: Boolean +) { val textColor = MaterialTheme.colorScheme.onSurface + val activeMarkerIds = activeMarkers.mapNotNull { it.id } SymbolLayer( id = "user_favorites", source = rememberGeoJsonSource(GeoJsonData.Features(savedPlaces)), + iconAllowOverlap = const(true), iconImage = image( if (isSystemInDarkTheme) { painterResource(drawable.ic_stars_dark) @@ -230,8 +240,21 @@ private fun FavoritesLayer(savedPlaces: FeatureCollection, isSystemInDarkTheme: painterResource(drawable.ic_stars_light) } ), + // Make the icon transparent if there's a pin symbol above it. + iconOpacity = if (activeMarkerIds.isNotEmpty()) { + org.maplibre.compose.expressions.dsl.switch( + input = feature["saved_poi_id"].asString(), + org.maplibre.compose.expressions.dsl.case( + activeMarkers.mapNotNull { it.id }, + const(0f), + ), + fallback = const(1f) + ) + } else { + const(1f) + }, iconSize = const(0.8f), - textField = org.maplibre.compose.expressions.dsl.Feature["name"].cast(), + textField = feature["name"].asString(), textSize = const(0.8.em), textColor = rgbColor( const((textColor.red * 255.0f).toInt()), @@ -305,7 +328,7 @@ private fun RouteLayer(viewModel: MapViewModel, currentRoute: Route?, allRoutes: "routeIndex" to Json.encodeToJsonElement(index.toString()), "routeColor" to polylineColor, "routeColorCasing" to polylineCasingColor, - if(route == currentRoute) { + if (route == currentRoute) { "current" to Json.encodeToJsonElement(true) } else { "notCurrent" to Json.encodeToJsonElement(true) @@ -498,6 +521,8 @@ private fun PinsLayer(pinFeatures: List, isSystemInDarkTheme: Boolean) SymbolLayer( id = "map_pins", source = rememberGeoJsonSource(GeoJsonData.Features(FeatureCollection(features = pinFeatures))), + iconAllowOverlap = const(true), + iconAnchor = const(SymbolAnchor.Bottom), iconImage = image( if (isSystemInDarkTheme) { painterResource(drawable.map_pin_dark) 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 2ca0a057187e6819b3f91c1fbee12ca661ace3aa..c32c65d5c2f47972cce7e1849b425d9d132a17ac 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 @@ -104,9 +104,10 @@ class MapViewModel @Inject constructor( fun createFeatureFromPlace(place: Place): Feature { val properties = mutableMapOf( "name" to escapeJsonString(place.name), - "description" to escapeJsonString(place.description) + "description" to escapeJsonString(place.description), ) + place.id?.let { properties["id"] = escapeJsonString(it) } place.address?.houseNumber?.let { properties["addr:housenumber"] = escapeJsonString(it) } place.address?.road?.let { properties["addr:street"] = escapeJsonString(it) } place.address?.city?.let { properties["addr:city"] = escapeJsonString(it) } 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 7fad7f93adf1eed37162c61efff640501878e961..a7d81dfebab0f3abd40ea91bbe7740faa56e89b1 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 @@ -43,6 +43,7 @@ fun LocationPuckLayers(idPrefix: String, locationSource: Source, headingDegrees: SymbolLayer( id = "${idPrefix}-puck", source = locationSource, + iconAllowOverlap = const(true), iconImage = image(puckDrawable), iconRotate = const(headingDegrees ?: 0f), )