From d8297c9e5951e1cb8d3b0e89c2fe4fee5eceb0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Fazekas?= Date: Sun, 15 Mar 2026 08:21:16 +0100 Subject: [PATCH] fix(android): fix Atmosphere NPE and incorrect removeFromMap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs fixed in RNMBXAtmosphere: 1. NPE in addStyles() when is used with no props — mReactStyle!! throws NullPointerException because setReactStyle() is never called before addToMap(). Replaced !! with safe null early-returns. (related to PR #4171) 2. removeFromMap() was calling removeTerrain() instead of removeAtmosphere() (copy-paste bug), causing terrain to disappear when toggling Atmosphere off while the atmosphere itself stayed. Also now nulls mAtmosphere on removal for clean state. Also adds atmosphere toggle + color cycling to TerrainSkyAtmosphere and QueryTerrainElevation examples, and updates BugReportExampleTS with the AtmosphereRaceRepro test case from PR #4171. Co-Authored-By: Claude Sonnet 4.6 --- .../styles/atmosphere/RNMBXAtmosphere.kt | 21 ++- example/src/examples/BugReportExampleTS.tsx | 139 ++++++++---------- .../src/examples/V10/QueryTerrainElevation.js | 36 +++-- .../src/examples/V10/TerrainSkyAtmosphere.tsx | 56 +++++-- 4 files changed, 145 insertions(+), 107 deletions(-) diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/atmosphere/RNMBXAtmosphere.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/atmosphere/RNMBXAtmosphere.kt index 8a55b1fd62..53debcf699 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/atmosphere/RNMBXAtmosphere.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/atmosphere/RNMBXAtmosphere.kt @@ -4,8 +4,7 @@ import android.content.Context import com.facebook.react.bridge.ReadableMap import com.mapbox.maps.MapboxMap import com.mapbox.maps.extension.style.atmosphere.generated.Atmosphere -import com.mapbox.maps.extension.style.terrain.generated.Terrain -import com.mapbox.maps.extension.style.terrain.generated.removeTerrain +import com.mapbox.maps.extension.style.atmosphere.generated.removeAtmosphere import com.rnmapbox.rnmbx.components.RemovalReason import com.rnmapbox.rnmbx.components.mapview.RNMBXMapView import com.rnmapbox.rnmbx.components.styles.RNMBXStyle @@ -42,7 +41,8 @@ class RNMBXAtmosphere(context: Context?) : AbstractSourceConsumer(context) { } override fun removeFromMap(mapView: RNMBXMapView, reason: RemovalReason): Boolean { - mapView.savedStyle?.let { it.removeTerrain() } + mapView.savedStyle?.let { it.removeAtmosphere() } + mAtmosphere = null mMap = null return super.removeFromMap(mapView, reason) } @@ -52,15 +52,14 @@ class RNMBXAtmosphere(context: Context?) : AbstractSourceConsumer(context) { } fun addStyles() { - mAtmosphere?.also { - RNMBXStyleFactory.setAtmosphereLayerStyle( - it, RNMBXStyle( - context, mReactStyle!!, - mMap!! - ) - ) - } ?: run { + val atmosphere = mAtmosphere ?: run { Logger.e("RNMBXAtmosphere", "mAtmosphere is null") + return } + val reactStyle = mReactStyle ?: return + val map = mMap ?: return + RNMBXStyleFactory.setAtmosphereLayerStyle( + atmosphere, RNMBXStyle(context, reactStyle, map) + ) } } \ No newline at end of file diff --git a/example/src/examples/BugReportExampleTS.tsx b/example/src/examples/BugReportExampleTS.tsx index e395f44ae9..aebc7f2008 100644 --- a/example/src/examples/BugReportExampleTS.tsx +++ b/example/src/examples/BugReportExampleTS.tsx @@ -1,88 +1,73 @@ -import { useState } from 'react'; -import { - Camera, - CircleLayer, - Images, - MapView, - ShapeSource, - SymbolLayer, -} from '@rnmapbox/maps'; -import { FeatureCollection } from 'geojson'; -import { Button } from 'react-native'; +import { useMemo, useState } from 'react'; +import { Button, StyleSheet, Text, View } from 'react-native'; +import { Atmosphere, Camera, MapView } from '@rnmapbox/maps'; -const styles = { - mapView: { flex: 1 }, - circleLayer: { - circleRadiusTransition: { duration: 5000, delay: 0 }, - circleColor: '#ff0000', - }, -}; +const STYLE_DARK = 'mapbox://styles/mapbox/dark-v11'; +const STYLE_STANDARD = 'mapbox://styles/mapbox/standard'; -const features: FeatureCollection = { - type: 'FeatureCollection', - features: [ - { - type: 'Feature', - id: 'a-feature', - properties: { - icon: 'example', - text: 'example-icon-and-label', - }, - geometry: { - type: 'Point', - coordinates: [-74.00597, 40.71427], - }, - }, - { - type: 'Feature', - id: 'b-feature', - properties: { - text: 'just-label', - }, - geometry: { - type: 'Point', - coordinates: [-74.001097, 40.71527], - }, - }, - { - type: 'Feature', - id: 'c-feature', - properties: { - icon: 'example', - }, - geometry: { - type: 'Point', - coordinates: [-74.00697, 40.72427], - }, - }, - ], -}; +const styles = StyleSheet.create({ + map: { + flex: 1, + }, + controls: { + position: 'absolute', + top: 50, + left: 16, + right: 16, + gap: 8, + backgroundColor: 'rgba(0,0,0,0.35)', + borderRadius: 10, + padding: 10, + }, + text: { + color: 'white', + }, +}); const BugReportExample = () => { - const [radius, setRadius] = useState(20); + const [styleURL, setStyleURL] = useState(STYLE_DARK); + const [showAtmosphere, setShowAtmosphere] = useState(true); + + const atmosphereStyle = useMemo(() => { + const isDark = styleURL === STYLE_DARK; + return { + color: isDark ? 'rgba(29,44,62,1)' : 'rgba(255,255,255,1)', + highColor: isDark ? 'rgba(11,11,25,1)' : 'rgba(255,255,255,1)', + spaceColor: isDark ? 'rgba(11,11,25,1)' : 'rgba(255,255,255,1)', + horizonBlend: 0.03, + starIntensity: isDark ? 0.6 : 0, + }; + }, [styleURL]); - const circleLayerStyle = { - ...styles.circleLayer, - ...{ circleRadius: radius }, - }; + function flipStyle() { + setStyleURL((prev) => (prev === STYLE_DARK ? STYLE_STANDARD : STYLE_DARK)); + } + + function remountAtmosphere() { + setShowAtmosphere(false); + requestAnimationFrame(() => setShowAtmosphere(true)); + } return ( - <> -