From 4c906b21fbc9834699c5dcd62e551b05b2526c53 Mon Sep 17 00:00:00 2001 From: OpenAI Codex Date: Mon, 7 Sep 2026 16:09:50 +0800 Subject: [PATCH] feat: add RN WeatherRuntime bridge test host --- .../MapLibreParticleRNTestHost/App.tsx | 62 + .../MapLibreParticleRNTestHost/README.md | 38 + .../MapLibreParticleRNTestHost/app.json | 11 + .../android/build.gradle | 19 + .../android/src/main/AndroidManifest.xml | 1 + .../weather/WeatherRuntimeBridgeModule.kt | 132 + .../weather/WeatherRuntimeBridgePackage.kt | 20 + .../weather-runtime-bridge/package.json | 14 + .../react-native.config.js | 1 + .../src/NativeWeatherRuntimeBridge.ts | 28 + .../weather-runtime-bridge/src/index.ts | 9 + .../package-lock.json | 6780 +++++++++++++++++ .../MapLibreParticleRNTestHost/package.json | 23 + .../plugins/withParticleNativeAndroid.js | 16 + .../react-native.config.js | 7 + .../src/weatherStyle.ts | 21 + .../MapLibreParticleRNTestHost/tsconfig.json | 5 + .../maplibre/android/maps/MapLibreMap.java | 36 + .../maplibre/android/maps/WeatherRuntime.java | 2 + 19 files changed, 7225 insertions(+) create mode 100644 integration/react-native/MapLibreParticleRNTestHost/App.tsx create mode 100644 integration/react-native/MapLibreParticleRNTestHost/README.md create mode 100644 integration/react-native/MapLibreParticleRNTestHost/app.json create mode 100644 integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/build.gradle create mode 100644 integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/src/main/AndroidManifest.xml create mode 100644 integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/src/main/java/org/maplibre/particle/rntesthost/weather/WeatherRuntimeBridgeModule.kt create mode 100644 integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/src/main/java/org/maplibre/particle/rntesthost/weather/WeatherRuntimeBridgePackage.kt create mode 100644 integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/package.json create mode 100644 integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/react-native.config.js create mode 100644 integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/src/NativeWeatherRuntimeBridge.ts create mode 100644 integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/src/index.ts create mode 100644 integration/react-native/MapLibreParticleRNTestHost/package-lock.json create mode 100644 integration/react-native/MapLibreParticleRNTestHost/package.json create mode 100644 integration/react-native/MapLibreParticleRNTestHost/plugins/withParticleNativeAndroid.js create mode 100644 integration/react-native/MapLibreParticleRNTestHost/react-native.config.js create mode 100644 integration/react-native/MapLibreParticleRNTestHost/src/weatherStyle.ts create mode 100644 integration/react-native/MapLibreParticleRNTestHost/tsconfig.json diff --git a/integration/react-native/MapLibreParticleRNTestHost/App.tsx b/integration/react-native/MapLibreParticleRNTestHost/App.tsx new file mode 100644 index 000000000..0d43bf6ed --- /dev/null +++ b/integration/react-native/MapLibreParticleRNTestHost/App.tsx @@ -0,0 +1,62 @@ +import { useCallback, useEffect, useMemo, useState } from "react"; +import { Button, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, View, findNodeHandle } from "react-native"; +import { Map } from "@maplibre/maplibre-react-native"; +import { WeatherRuntimeBridge, type RuntimeSnapshot, type TargetFps } from "@maplibre-particle/weather-runtime-bridge"; +import { weatherTestStyle } from "./src/weatherStyle"; + +const initialSnapshot: RuntimeSnapshot = { state: "WAITING_FOR_FIELDS", playbackState: "PAUSE", targetFps: "AUTO", disposed: false }; + +export default function App() { + const [reactTag, setReactTag] = useState(null); + const [snapshot, setSnapshot] = useState(initialSnapshot); + const [result, setResult] = useState("Style is loading"); + const [opacity, setOpacity] = useState("0.62"); + + const attach = useCallback(async (tag: number) => { + try { setSnapshot(await WeatherRuntimeBridge.attach(tag)); setReactTag(tag); setResult("WeatherRuntime attached"); } + catch (error) { setResult(String(error)); } + }, []); + + // MLRN forwards the native MapView event. Its target is the concrete Fabric MLRNMapView tag; + // this is the same tag consumed by MLRN's own NativeMapViewModule. + const onStyleReady = useCallback((event: unknown) => { + const tag = findNodeHandle((event as { target?: unknown }).target as never); + if (tag != null) void attach(tag); + }, [attach]); + + useEffect(() => () => { + if (reactTag != null) void WeatherRuntimeBridge.detach(reactTag).catch(() => undefined); + }, [reactTag]); + + const command = useCallback(async (name: string, operation: (tag: number) => Promise) => { + if (reactTag == null) return setResult("MAP_NOT_READY: wait for style ready"); + try { const value = await operation(reactTag); setResult(`${name}: ${String(value)}`); setSnapshot(await WeatherRuntimeBridge.getState(reactTag)); } + catch (error) { setResult(`${name}: ${String(error)}`); } + }, [reactTag]); + + const buttons = useMemo(() => [ + ["getState", (tag: number) => WeatherRuntimeBridge.getState(tag)], + ["enable", (tag: number) => WeatherRuntimeBridge.setWeatherEnabled(tag, true)], + ["weather visible", (tag: number) => WeatherRuntimeBridge.setWeatherColorVisible(tag, true)], + ["particle visible", (tag: number) => WeatherRuntimeBridge.setParticleVisible(tag, true)], + ["FPS 30", (tag: number) => WeatherRuntimeBridge.setTargetFps(tag, "FPS_30" as TargetFps)], + ["PLAY", (tag: number) => WeatherRuntimeBridge.setPlaybackState(tag, "PLAY")], + ["PAUSE", (tag: number) => WeatherRuntimeBridge.setPlaybackState(tag, "PAUSE")] + ] as const, []); + + return + + + reactTag: {reactTag ?? "not attached"} + runtime: {snapshot.state} / {snapshot.playbackState} / {snapshot.targetFps} + {result} + {buttons.map(([label, operation]) =>