Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 144 additions & 7 deletions android/src/main/java/com/luggmaps/core/GoogleMapProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.gms.maps.model.Polygon
import com.google.android.gms.maps.model.PolygonOptions
import com.google.android.gms.maps.model.PolylineOptions
import com.google.android.gms.maps.model.MapStyleOptions
import com.google.android.gms.maps.model.TileOverlayOptions
import com.google.android.gms.maps.model.UrlTileProvider
import com.luggmaps.LuggCalloutView
Expand Down Expand Up @@ -120,6 +121,11 @@ class GoogleMapProvider(private val context: Context) :
// Theme
private var theme: String = "system"

// POI
private var poiEnabled: Boolean = true
private var poiFilterMode: String = "including"
private var poiFilterCategories: List<String> = emptyList()

// Edge Insets
private var edgeInsets: EdgeInsets = EdgeInsets()

Expand Down Expand Up @@ -221,6 +227,7 @@ class GoogleMapProvider(private val context: Context) :
applyEdgeInsets()
applyInsetAdjustment()
applyTheme()
applyPoiStyle()
applyUserLocation()
processPendingMarkers()
processPendingPolylines()
Expand Down Expand Up @@ -546,11 +553,23 @@ class GoogleMapProvider(private val context: Context) :
applyInsetAdjustment()
}

override fun setPoiEnabled(enabled: Boolean) {}
override fun setPoiEnabled(enabled: Boolean) {
if (poiEnabled == enabled) return
poiEnabled = enabled
applyPoiStyle()
}

override fun setPoiFilterMode(mode: String) {}
override fun setPoiFilterMode(mode: String) {
if (poiFilterMode == mode) return
poiFilterMode = mode
applyPoiStyle()
}

override fun setPoiFilterCategories(categories: List<String>) {}
override fun setPoiFilterCategories(categories: List<String>) {
if (poiFilterCategories == categories) return
poiFilterCategories = categories
applyPoiStyle()
}

// endregion

Expand Down Expand Up @@ -1299,6 +1318,128 @@ class GoogleMapProvider(private val context: Context) :

override fun onTrimMemory(level: Int) {}

private fun applyPoiStyle() {
if (!poiEnabled) {
googleMap?.setMapStyle(MapStyleOptions(POI_STYLE_HIDE_ALL))
return
}

val mappedFeatureTypes = poiFilterCategories
.mapNotNull { POI_CATEGORY_TO_FEATURE_TYPE[it] }
.toSet()

if (mappedFeatureTypes.isEmpty()) {
googleMap?.setMapStyle(null)
return
}

val styleJson = buildString {
append("[")
if (poiFilterMode == "excluding") {
mappedFeatureTypes.forEach { featureType ->
append("""{"featureType":"$featureType","elementType":"all","stylers":[{"visibility":"off"}]},""")
}
} else {
// including: hide all POIs/transit, then re-enable only matching feature types
append("""{"featureType":"poi","elementType":"all","stylers":[{"visibility":"off"}]},""")
append("""{"featureType":"transit","elementType":"all","stylers":[{"visibility":"off"}]},""")
mappedFeatureTypes.forEach { featureType ->
append("""{"featureType":"$featureType","elementType":"all","stylers":[{"visibility":"on"}]},""")
}
}
if (endsWith(",")) deleteCharAt(length - 1)
append("]")
}

googleMap?.setMapStyle(MapStyleOptions(styleJson))
}

companion object {
const val DEMO_MAP_ID = "DEMO_MAP_ID"

private val POI_CATEGORY_TO_FEATURE_TYPE = mapOf(
"airport" to "transit.station.airport",
"amusement-park" to "poi.attraction",
"aquarium" to "poi.attraction",
"atm" to "poi.business",
"bakery" to "poi.business",
"bank" to "poi.business",
"beach" to "poi",
"brewery" to "poi.business",
"cafe" to "poi.business",
"campground" to "poi",
"car-rental" to "poi.business",
"ev-charger" to "poi.business",
"fire-station" to "poi.government",
"fitness-center" to "poi.sports_complex",
"food-market" to "poi.business",
"gas-station" to "poi.business",
"hospital" to "poi.medical",
"hotel" to "poi.business",
"laundry" to "poi.business",
"library" to "poi.government",
"marina" to "poi",
"movie-theater" to "poi.attraction",
"museum" to "poi.attraction",
"national-park" to "poi.park",
"nightlife" to "poi.business",
"park" to "poi.park",
"parking" to "poi.business",
"pharmacy" to "poi.medical",
"police" to "poi.government",
"post-office" to "poi.government",
"public-transport" to "transit",
"restaurant" to "poi.business",
"restroom" to "poi",
"school" to "poi.school",
"stadium" to "poi.sports_complex",
"store" to "poi.business",
"theater" to "poi.attraction",
"university" to "poi.school",
"winery" to "poi.business",
"zoo" to "poi.attraction",
// iOS 18+
"animal-service" to "poi.business",
"automotive-repair" to "poi.business",
"baseball" to "poi.sports_complex",
"basketball" to "poi.sports_complex",
"beauty" to "poi.business",
"bowling" to "poi.sports_complex",
"castle" to "poi.attraction",
"convention-center" to "poi.business",
"distillery" to "poi.business",
"fairground" to "poi.attraction",
"fishing" to "poi",
"fortress" to "poi.attraction",
"go-kart" to "poi.sports_complex",
"golf" to "poi.sports_complex",
"hiking" to "poi.park",
"kayaking" to "poi",
"landmark" to "poi.attraction",
"mailbox" to "poi.government",
"mini-golf" to "poi.sports_complex",
"music-venue" to "poi.attraction",
"national-monument" to "poi.attraction",
"planetarium" to "poi.attraction",
"rock-climbing" to "poi.sports_complex",
"rv-park" to "poi",
"skate-park" to "poi.sports_complex",
"skating" to "poi.sports_complex",
"skiing" to "poi.sports_complex",
"soccer" to "poi.sports_complex",
"spa" to "poi.business",
"surfing" to "poi",
"swimming" to "poi.sports_complex",
"tennis" to "poi.sports_complex",
"volleyball" to "poi.sports_complex",
)

private val POI_STYLE_HIDE_ALL = """[
{"featureType":"poi","elementType":"all","stylers":[{"visibility":"off"}]},
{"featureType":"transit","elementType":"all","stylers":[{"visibility":"off"}]}
]"""
}

private fun applyTheme() {
val colorScheme = when (theme) {
"dark" -> MapColorScheme.DARK
Expand All @@ -1321,8 +1462,4 @@ class GoogleMapProvider(private val context: Context) :
}

// endregion

companion object {
const val DEMO_MAP_ID = "DEMO_MAP_ID"
}
}
4 changes: 2 additions & 2 deletions docs/MAPVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ import { MapView } from '@lugg/maps';
| `edgeInsets` | `EdgeInsets` | - | Map content edge insets |
| `userLocationEnabled` | `boolean` | `false` | Show current user location on the map |
| `userLocationButtonEnabled` | `boolean` | `false` | Show native my-location button (Android only) |
| `poiEnabled` | `boolean` | `true` | Show points of interest (Apple Maps only) |
| `poiFilter` | [`PoiFilter`](#poifilter) | - | Filter POI categories (Apple Maps only) |
| `poiEnabled` | `boolean` | `true` | Show points of interest. On Android, hides POIs and transit stops via map style. |
| `poiFilter` | [`PoiFilter`](#poifilter) | - | Filter POI categories. On Android, categories map to Google Maps Style feature types (coarser granularity). |
| `theme` | [`MapTheme`](#maptheme) | `'system'` | Map color theme |
| `insetAdjustment` | `'automatic' \| 'never'` | `'never'` | Safe area inset adjustment behavior |
| `onPress` | `(event: MapPressEvent) => void` | - | Called when the map is pressed |
Expand Down
Loading