@aguacerowx/react-native 0.0.36 → 0.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (403) hide show
  1. package/README.md +126 -126
  2. package/aguacerowx-react-native.podspec +38 -38
  3. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  4. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  5. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  6. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  7. package/android/.gradle/8.9/gc.properties +0 -0
  8. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  9. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  10. package/android/.gradle/vcs-1/gc.properties +0 -0
  11. package/android/build.gradle +107 -107
  12. package/android/src/main/AndroidManifest.xml +6 -6
  13. package/android/src/main/java/com/aguacerowx/reactnative/AguaceroPackage.java +33 -33
  14. package/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +688 -688
  15. package/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayerView.java +304 -304
  16. package/android/src/main/java/com/aguacerowx/reactnative/GridRenderManager.java +125 -125
  17. package/android/src/main/java/com/aguacerowx/reactnative/InspectorModule.java +71 -71
  18. package/android/src/main/java/com/aguacerowx/reactnative/ShaderUtils.java +106 -106
  19. package/android/src/main/java/com/aguacerowx/reactnative/WeatherFrameProcessorModule.java +151 -151
  20. package/android/src/main/res/raw/debug_fragment_shader.glsl +12 -12
  21. package/android/src/main/res/raw/debug_vertex_shader.glsl +12 -12
  22. package/android/src/main/res/raw/fragment_shader.glsl +180 -180
  23. package/android/src/main/res/raw/vertex_shader.glsl +19 -19
  24. package/index.js +2 -2
  25. package/ios/AguaceroPackage.m +18 -18
  26. package/ios/FragmentUniforms.swift +15 -15
  27. package/ios/GridRenderLayer.swift +1107 -1004
  28. package/ios/GridRenderLayerBridge.swift +44 -36
  29. package/ios/GridRenderLayerManager.mm +171 -157
  30. package/ios/GridRenderLayerView.h +30 -30
  31. package/ios/GridRenderLayerView.m +200 -216
  32. package/ios/InspectorDataCache.swift +63 -65
  33. package/ios/InspectorModule.m +9 -9
  34. package/ios/InspectorModule.swift +112 -63
  35. package/ios/Shaders.metal +319 -319
  36. package/ios/WeatherFrameProcessorModule.m +15 -15
  37. package/ios/WeatherFrameProcessorModule.swift +152 -103
  38. package/lib/commonjs/README.md +126 -126
  39. package/lib/commonjs/aguacerowx-react-native.podspec +38 -38
  40. package/lib/commonjs/android/build.gradle +107 -107
  41. package/lib/commonjs/android/src/main/AndroidManifest.xml +6 -6
  42. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/AguaceroPackage.java +33 -33
  43. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +688 -688
  44. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayerView.java +304 -304
  45. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/GridRenderManager.java +125 -125
  46. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/InspectorModule.java +71 -71
  47. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/ShaderUtils.java +106 -106
  48. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/WeatherFrameProcessorModule.java +151 -151
  49. package/lib/commonjs/android/src/main/res/raw/debug_fragment_shader.glsl +12 -12
  50. package/lib/commonjs/android/src/main/res/raw/debug_vertex_shader.glsl +12 -12
  51. package/lib/commonjs/android/src/main/res/raw/fragment_shader.glsl +180 -180
  52. package/lib/commonjs/android/src/main/res/raw/vertex_shader.glsl +19 -19
  53. package/lib/commonjs/babel.config.js.map +1 -1
  54. package/lib/commonjs/index.js.map +1 -1
  55. package/lib/commonjs/ios/AguaceroPackage.m +18 -18
  56. package/lib/commonjs/ios/FragmentUniforms.swift +15 -15
  57. package/lib/commonjs/ios/GridRenderLayer.swift +1107 -1004
  58. package/lib/commonjs/ios/GridRenderLayerBridge.swift +44 -36
  59. package/lib/commonjs/ios/GridRenderLayerManager.mm +171 -157
  60. package/lib/commonjs/ios/GridRenderLayerView.h +30 -30
  61. package/lib/commonjs/ios/GridRenderLayerView.m +200 -216
  62. package/lib/commonjs/ios/InspectorDataCache.swift +63 -65
  63. package/lib/commonjs/ios/InspectorModule.m +9 -9
  64. package/lib/commonjs/ios/InspectorModule.swift +112 -63
  65. package/lib/commonjs/ios/Shaders.metal +319 -319
  66. package/lib/commonjs/ios/WeatherFrameProcessorModule.m +15 -15
  67. package/lib/commonjs/ios/WeatherFrameProcessorModule.swift +152 -103
  68. package/lib/commonjs/package.json +72 -72
  69. package/lib/commonjs/react-native-builder-bob.config.js.map +1 -1
  70. package/lib/commonjs/scripts/compile-shaders.js.map +1 -1
  71. package/lib/commonjs/scripts/compile-shaders.sh +38 -38
  72. package/lib/commonjs/src/AguaceroContext.js.map +1 -1
  73. package/lib/commonjs/src/GridRenderLayer.js.map +1 -1
  74. package/lib/commonjs/src/GridRenderLayerNativeComponent.js.map +1 -1
  75. package/lib/commonjs/src/MapManager.js.map +1 -1
  76. package/lib/commonjs/src/MapRegistry.js.map +1 -1
  77. package/lib/commonjs/src/StyleApplicator.js +6 -6
  78. package/lib/commonjs/src/StyleApplicator.js.map +1 -1
  79. package/lib/commonjs/src/WeatherLayerManager.js +57 -15
  80. package/lib/commonjs/src/WeatherLayerManager.js.map +1 -1
  81. package/lib/commonjs/tsconfig.json +23 -23
  82. package/lib/module/README.md +126 -126
  83. package/lib/module/aguacerowx-react-native.podspec +38 -38
  84. package/lib/module/android/build.gradle +107 -107
  85. package/lib/module/android/src/main/AndroidManifest.xml +6 -6
  86. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/AguaceroPackage.java +33 -33
  87. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +688 -688
  88. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayerView.java +304 -304
  89. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/GridRenderManager.java +125 -125
  90. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/InspectorModule.java +71 -71
  91. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/ShaderUtils.java +106 -106
  92. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/WeatherFrameProcessorModule.java +151 -151
  93. package/lib/module/android/src/main/res/raw/debug_fragment_shader.glsl +12 -12
  94. package/lib/module/android/src/main/res/raw/debug_vertex_shader.glsl +12 -12
  95. package/lib/module/android/src/main/res/raw/fragment_shader.glsl +180 -180
  96. package/lib/module/android/src/main/res/raw/vertex_shader.glsl +19 -19
  97. package/lib/module/babel.config.js.map +1 -1
  98. package/lib/module/index.js.map +1 -1
  99. package/lib/module/ios/AguaceroPackage.m +18 -18
  100. package/lib/module/ios/FragmentUniforms.swift +15 -15
  101. package/lib/module/ios/GridRenderLayer.swift +1107 -1004
  102. package/lib/module/ios/GridRenderLayerBridge.swift +44 -36
  103. package/lib/module/ios/GridRenderLayerManager.mm +171 -157
  104. package/lib/module/ios/GridRenderLayerView.h +30 -30
  105. package/lib/module/ios/GridRenderLayerView.m +200 -216
  106. package/lib/module/ios/InspectorDataCache.swift +63 -65
  107. package/lib/module/ios/InspectorModule.m +9 -9
  108. package/lib/module/ios/InspectorModule.swift +112 -63
  109. package/lib/module/ios/Shaders.metal +319 -319
  110. package/lib/module/ios/WeatherFrameProcessorModule.m +15 -15
  111. package/lib/module/ios/WeatherFrameProcessorModule.swift +152 -103
  112. package/lib/module/lib/commonjs/README.md +126 -126
  113. package/lib/module/lib/commonjs/aguacerowx-react-native.podspec +38 -38
  114. package/lib/module/lib/commonjs/babel.config.js.map +1 -1
  115. package/lib/module/lib/commonjs/index.js.map +1 -1
  116. package/lib/module/lib/commonjs/ios/AguaceroPackage.m +18 -18
  117. package/lib/module/lib/commonjs/ios/FragmentUniforms.swift +15 -15
  118. package/lib/module/lib/commonjs/ios/GridRenderLayer.swift +1107 -1004
  119. package/lib/module/lib/commonjs/ios/GridRenderLayerBridge.swift +44 -36
  120. package/lib/module/lib/commonjs/ios/GridRenderLayerManager.mm +171 -157
  121. package/lib/module/lib/commonjs/ios/GridRenderLayerView.h +30 -30
  122. package/lib/module/lib/commonjs/ios/GridRenderLayerView.m +200 -216
  123. package/lib/module/lib/commonjs/ios/InspectorDataCache.swift +63 -65
  124. package/lib/module/lib/commonjs/ios/InspectorModule.m +9 -9
  125. package/lib/module/lib/commonjs/ios/InspectorModule.swift +112 -63
  126. package/lib/module/lib/commonjs/ios/Shaders.metal +319 -319
  127. package/lib/module/lib/commonjs/ios/WeatherFrameProcessorModule.m +15 -15
  128. package/lib/module/lib/commonjs/ios/WeatherFrameProcessorModule.swift +152 -103
  129. package/lib/module/lib/commonjs/package.json +72 -72
  130. package/lib/module/lib/commonjs/react-native-builder-bob.config.js.map +1 -1
  131. package/lib/module/lib/commonjs/scripts/compile-shaders.js.map +1 -1
  132. package/lib/module/lib/commonjs/scripts/compile-shaders.sh +38 -38
  133. package/lib/module/lib/commonjs/src/AguaceroContext.js.map +1 -1
  134. package/lib/module/lib/commonjs/src/GridRenderLayer.js.map +1 -1
  135. package/lib/module/lib/commonjs/src/GridRenderLayerNativeComponent.js.map +1 -1
  136. package/lib/module/lib/commonjs/src/MapManager.js.map +1 -1
  137. package/lib/module/lib/commonjs/src/MapRegistry.js.map +1 -1
  138. package/lib/module/lib/commonjs/src/StyleApplicator.js +6 -6
  139. package/lib/module/lib/commonjs/src/StyleApplicator.js.map +1 -1
  140. package/lib/module/lib/commonjs/src/WeatherLayerManager.js +57 -15
  141. package/lib/module/lib/commonjs/src/WeatherLayerManager.js.map +1 -1
  142. package/lib/module/lib/commonjs/tsconfig.json +23 -23
  143. package/lib/module/package.json +72 -72
  144. package/lib/module/react-native-builder-bob.config.js.map +1 -1
  145. package/lib/module/scripts/compile-shaders.js.map +1 -1
  146. package/lib/module/scripts/compile-shaders.sh +38 -38
  147. package/lib/module/src/AguaceroContext.js.map +1 -1
  148. package/lib/module/src/GridRenderLayer.js.map +1 -1
  149. package/lib/module/src/GridRenderLayerNativeComponent.js.map +1 -1
  150. package/lib/module/src/MapManager.js.map +1 -1
  151. package/lib/module/src/MapRegistry.js.map +1 -1
  152. package/lib/module/src/StyleApplicator.js +6 -6
  153. package/lib/module/src/StyleApplicator.js.map +1 -1
  154. package/lib/module/src/WeatherLayerManager.js +59 -16
  155. package/lib/module/src/WeatherLayerManager.js.map +1 -1
  156. package/lib/module/tsconfig.json +23 -23
  157. package/lib/typescript/src/WeatherLayerManager.d.ts.map +1 -1
  158. package/package.json +72 -72
  159. package/src/AguaceroContext.js +3 -3
  160. package/src/GridRenderLayer.js +215 -215
  161. package/src/GridRenderLayerNativeComponent.ts +15 -15
  162. package/src/MapManager.js +218 -218
  163. package/src/MapRegistry.js +34 -34
  164. package/src/StyleApplicator.js +240 -240
  165. package/src/WeatherLayerManager.js +1191 -1137
  166. package/android/build/.transforms/42e9b8fa82d77a1c205db5bf0d0ed519/results.bin +0 -1
  167. package/android/build/.transforms/42e9b8fa82d77a1c205db5bf0d0ed519/transformed/classes/classes_dex/classes.dex +0 -0
  168. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/results.bin +0 -1
  169. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/AguaceroPackage.dex +0 -0
  170. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/BuildConfig.dex +0 -0
  171. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.dex +0 -0
  172. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderLayer.dex +0 -0
  173. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderLayerView.dex +0 -0
  174. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderManager.dex +0 -0
  175. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/InspectorModule.dex +0 -0
  176. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/ShaderUtils.dex +0 -0
  177. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/WeatherFrameProcessorModule.dex +0 -0
  178. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.dex +0 -0
  179. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.dex +0 -0
  180. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  181. package/android/build/generated/source/buildConfig/debug/com/aguacerowx/reactnative/BuildConfig.java +0 -10
  182. package/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.java +0 -43
  183. package/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.java +0 -22
  184. package/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec-generated.cpp +0 -22
  185. package/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec.h +0 -24
  186. package/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
  187. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI-generated.cpp +0 -17
  188. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI.h +0 -19
  189. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.cpp +0 -22
  190. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.h +0 -24
  191. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.cpp +0 -16
  192. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.h +0 -23
  193. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.cpp +0 -62
  194. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.h +0 -40
  195. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.cpp +0 -17
  196. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.h +0 -32
  197. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.cpp +0 -16
  198. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.h +0 -20
  199. package/android/build/generated/source/codegen/schema.json +0 -1
  200. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -8
  201. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  202. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  203. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  204. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  205. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  206. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -4
  207. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_fragment_shader.glsl.flat +0 -0
  208. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_vertex_shader.glsl.flat +0 -0
  209. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  210. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_vertex_shader.glsl.flat +0 -0
  211. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -5
  212. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  213. package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
  214. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  215. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  216. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  217. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  218. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  219. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  220. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  221. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  222. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  223. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  224. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  225. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  226. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  227. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -6
  228. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -8
  229. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -8
  230. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  231. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  232. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_fragment_shader.glsl +0 -13
  233. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_vertex_shader.glsl +0 -13
  234. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +0 -181
  235. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/vertex_shader.glsl +0 -20
  236. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  237. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  238. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  239. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  240. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  241. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  242. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  243. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  244. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  245. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  246. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  247. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  248. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -5
  249. package/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -17
  250. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  251. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  252. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayerView.class.uniqueId2 +0 -0
  253. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  254. package/lib/commonjs/android/build/generated/source/buildConfig/debug/com/aguacerowx/reactnative/BuildConfig.java +0 -10
  255. package/lib/commonjs/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.java +0 -43
  256. package/lib/commonjs/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.java +0 -22
  257. package/lib/commonjs/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec-generated.cpp +0 -22
  258. package/lib/commonjs/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec.h +0 -24
  259. package/lib/commonjs/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
  260. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI-generated.cpp +0 -17
  261. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI.h +0 -19
  262. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.cpp +0 -22
  263. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.h +0 -24
  264. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.cpp +0 -16
  265. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.h +0 -23
  266. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.cpp +0 -62
  267. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.h +0 -40
  268. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.cpp +0 -17
  269. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.h +0 -32
  270. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.cpp +0 -16
  271. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.h +0 -20
  272. package/lib/commonjs/android/build/generated/source/codegen/schema.json +0 -1
  273. package/lib/commonjs/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -8
  274. package/lib/commonjs/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  275. package/lib/commonjs/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  276. package/lib/commonjs/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  277. package/lib/commonjs/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  278. package/lib/commonjs/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  279. package/lib/commonjs/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -4
  280. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_fragment_shader.glsl.flat +0 -0
  281. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_vertex_shader.glsl.flat +0 -0
  282. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  283. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_vertex_shader.glsl.flat +0 -0
  284. package/lib/commonjs/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -5
  285. package/lib/commonjs/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  286. package/lib/commonjs/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
  287. package/lib/commonjs/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  288. package/lib/commonjs/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  289. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  290. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  291. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  292. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  293. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  294. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  295. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  296. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  297. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  298. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  299. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  300. package/lib/commonjs/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -6
  301. package/lib/commonjs/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -8
  302. package/lib/commonjs/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -8
  303. package/lib/commonjs/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  304. package/lib/commonjs/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  305. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_fragment_shader.glsl +0 -13
  306. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_vertex_shader.glsl +0 -13
  307. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +0 -181
  308. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/vertex_shader.glsl +0 -20
  309. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  310. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  311. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  312. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  313. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  314. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  315. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  316. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  317. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  318. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  319. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  320. package/lib/commonjs/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  321. package/lib/commonjs/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -5
  322. package/lib/commonjs/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -17
  323. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  324. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  325. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayerView.class.uniqueId2 +0 -0
  326. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  327. package/lib/module/android/build/generated/source/buildConfig/debug/com/aguacerowx/reactnative/BuildConfig.java +0 -10
  328. package/lib/module/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.java +0 -43
  329. package/lib/module/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.java +0 -22
  330. package/lib/module/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec-generated.cpp +0 -22
  331. package/lib/module/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec.h +0 -24
  332. package/lib/module/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
  333. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI-generated.cpp +0 -17
  334. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI.h +0 -19
  335. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.cpp +0 -22
  336. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.h +0 -24
  337. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.cpp +0 -16
  338. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.h +0 -23
  339. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.cpp +0 -62
  340. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.h +0 -40
  341. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.cpp +0 -17
  342. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.h +0 -32
  343. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.cpp +0 -16
  344. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.h +0 -20
  345. package/lib/module/android/build/generated/source/codegen/schema.json +0 -1
  346. package/lib/module/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -8
  347. package/lib/module/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  348. package/lib/module/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  349. package/lib/module/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  350. package/lib/module/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  351. package/lib/module/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  352. package/lib/module/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -4
  353. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_fragment_shader.glsl.flat +0 -0
  354. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_vertex_shader.glsl.flat +0 -0
  355. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  356. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_vertex_shader.glsl.flat +0 -0
  357. package/lib/module/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -5
  358. package/lib/module/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  359. package/lib/module/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
  360. package/lib/module/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  361. package/lib/module/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  362. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  363. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  364. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  365. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  366. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  367. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  368. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  369. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  370. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  371. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  372. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  373. package/lib/module/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -6
  374. package/lib/module/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -8
  375. package/lib/module/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -8
  376. package/lib/module/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  377. package/lib/module/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  378. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_fragment_shader.glsl +0 -13
  379. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_vertex_shader.glsl +0 -13
  380. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +0 -181
  381. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/vertex_shader.glsl +0 -20
  382. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  383. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  384. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  385. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  386. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  387. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  388. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  389. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  390. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  391. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  392. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  393. package/lib/module/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  394. package/lib/module/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -5
  395. package/lib/module/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -17
  396. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  397. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  398. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayerView.class.uniqueId2 +0 -0
  399. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  400. package/lib/module/lib/commonjs/android/build.gradle +0 -108
  401. package/lib/module/lib/commonjs/android/src/main/AndroidManifest.xml +0 -7
  402. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders-device.metallib +0 -0
  403. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
@@ -1,1138 +1,1192 @@
1
- // packages/react-native/src/WeatherLayerManager.js
2
-
3
- import React, { useState, useRef, useContext, useEffect, forwardRef, useImperativeHandle, useMemo } from 'react';
4
- import { AguaceroCore, getUnitConversionFunction, DICTIONARIES } from '@aguacerowx/javascript-sdk';
5
- import { AguaceroContext } from './AguaceroContext';
6
- import { GridRenderLayer } from './GridRenderLayer';
7
- import { fromByteArray } from 'base64-js';
8
- import { Platform, NativeModules } from 'react-native';
9
- import { mapRegistry } from './MapRegistry';
10
-
11
- function findLatestModelRun(modelsData, modelName) {
12
- const model = modelsData?.[modelName];
13
- if (!model) return null;
14
- const availableDates = Object.keys(model).sort((a, b) => b.localeCompare(a));
15
- for (const date of availableDates) {
16
- const runs = model[date];
17
- if (!runs) continue;
18
- const availableRuns = Object.keys(runs).sort((a, b) => b.localeCompare(a));
19
- if (availableRuns.length > 0) return { date: date, run: availableRuns[0] };
20
- }
21
- return null;
22
- }
23
- const { WeatherFrameProcessorModule, InspectorModule } = NativeModules;
24
-
25
- /**
26
- * A helper function to generate the raw RGBA byte buffer for the colormap texture.
27
- */
28
- const _generateColormapBytes = (colormap) => {
29
- const width = 256;
30
- const data = new Uint8Array(width * 4);
31
- const stops = colormap.reduce((acc, _, i) => (i % 2 === 0 ? [...acc, { value: colormap[i], color: colormap[i + 1] }] : acc), []);
32
-
33
- if (stops.length === 0) return data;
34
-
35
- const minVal = stops[0].value;
36
- const maxVal = stops[stops.length - 1].value;
37
-
38
- const hexToRgb = (hex) => {
39
- const r = parseInt(hex.slice(1, 3), 16);
40
- const g = parseInt(hex.slice(3, 5), 16);
41
- const b = parseInt(hex.slice(5, 7), 16);
42
- return [r, g, b];
43
- };
44
-
45
- for (let i = 0; i < width; i++) {
46
- const val = minVal + (i / (width - 1)) * (maxVal - minVal);
47
- let lower = stops[0];
48
- let upper = stops[stops.length - 1];
49
- for (let j = 0; j < stops.length - 1; j++) {
50
- if (val >= stops[j].value && val <= stops[j + 1].value) {
51
- lower = stops[j];
52
- upper = stops[j + 1];
53
- break;
54
- }
55
- }
56
- const t = (val - lower.value) / (upper.value - lower.value || 1);
57
- const lowerRgb = hexToRgb(lower.color);
58
- const upperRgb = hexToRgb(upper.color);
59
- const rgb = lowerRgb.map((c, idx) => c * (1 - t) + upperRgb[idx] * t);
60
-
61
- const offset = i * 4;
62
- data[offset + 0] = Math.round(rgb[0]);
63
- data[offset + 1] = Math.round(rgb[1]);
64
- data[offset + 2] = Math.round(rgb[2]);
65
- data[offset + 3] = 255;
66
- }
67
- return data;
68
- };
69
-
70
- AguaceroCore.prototype.setMapCenter = function(center) {
71
- this.emit('map:move', center);
72
- };
73
-
74
- export const WeatherLayerManager = forwardRef((props, ref) => {
75
- const {
76
- inspectorEnabled,
77
- onInspect,
78
- apiKey,
79
- customColormaps,
80
- initialMode,
81
- initialVariable,
82
- autoRefresh,
83
- autoRefreshInterval,
84
- initialModel,
85
- ...restProps
86
- } = props;
87
- const context = useContext(AguaceroContext);
88
-
89
- // Create the core here instead of getting it from context
90
- const core = useMemo(() => new AguaceroCore({
91
- apiKey: apiKey,
92
- customColormaps: customColormaps,
93
- // ADD: Pass layerOptions to the core's constructor
94
- layerOptions: {
95
- mode: initialMode,
96
- variable: initialVariable,
97
- model: initialModel
98
- }
99
- }), [apiKey]);
100
-
101
- const gridLayerRef = useRef(null);
102
- const currentGridDataRef = useRef(null);
103
- const autoRefreshIntervalId = useRef(null);
104
-
105
- // Cache for preloaded grid data - stores the processed data ready for GPU upload
106
- const preloadedDataCache = useRef(new Map());
107
-
108
- // Store geometry and colormap that don't change with forecast hour
109
- const cachedGeometry = useRef(null);
110
- const cachedColormap = useRef(null);
111
- const cachedDataRange = useRef([0, 1]);
112
-
113
- // Track if we've done the initial load
114
- const hasInitialLoad = useRef(false);
115
- const hasPreloadedRef = useRef(false);
116
-
117
- // Track the last state we processed to avoid redundant updates
118
- const lastProcessedState = useRef(null);
119
- const previousStateRef = useRef(null);
120
-
121
- const [renderProps, setRenderProps] = useState({
122
- opacity: 1,
123
- dataRange: [0, 1]
124
- });
125
-
126
- useImperativeHandle(ref, () => {
127
- const setAutoRefresh = (enabled, intervalSeconds) => {
128
- if (autoRefreshIntervalId.current) {
129
- clearInterval(autoRefreshIntervalId.current);
130
- autoRefreshIntervalId.current = null;
131
- }
132
- if (enabled) {
133
- const effectiveInterval = (intervalSeconds || autoRefreshInterval || 30) * 1000;
134
- // Run once immediately, then start the interval
135
- _checkForUpdates();
136
- autoRefreshIntervalId.current = setInterval(_checkForUpdates, effectiveInterval);
137
- }
138
- };
139
- return {
140
- play: () => {
141
- core.play();
142
- },
143
- pause: () => {
144
- core.pause();
145
- },
146
- togglePlay: () => {
147
- core.togglePlay();
148
- },
149
- step: (direction) => {
150
- core.step(direction);
151
- },
152
- setPlaybackSpeed: (speed) => {
153
- if (speed > 0) {
154
- core.playbackSpeed = speed;
155
- if (core.isPlaying) {
156
- core.pause();
157
- core.play();
158
- }
159
- }
160
- },
161
- setOpacity: (opacity) => core.setOpacity(opacity),
162
- setUnits: (units) => core.setUnits(units),
163
- switchMode: (options) => core.switchMode(options),
164
- getAvailableVariables: (model) => core.getAvailableVariables(model),
165
- getVariableDisplayName: (code) => core.getVariableDisplayName(code),
166
- setRun: (runString) => core.setState({ run: runString.split(':')[1] }),
167
- setState: (newState) => core.setState(newState),
168
- setMRMSTimestamp: (timestamp) => core.setMRMSTimestamp(timestamp),
169
- setSmoothing: (enabled) => {
170
- if (gridLayerRef.current) {
171
- gridLayerRef.current.setSmoothing(enabled);
172
- }
173
- },
174
- setAutoRefresh,
175
- refreshData: () => {
176
- _checkForUpdates();
177
- },
178
- };
179
- }, [core, autoRefreshInterval, _checkForUpdates]);
180
-
181
- const preloadAllFramesToDisk = async (state) => {
182
- if (hasPreloadedRef.current) {
183
- return;
184
- }
185
-
186
- const { isMRMS, model, date, run, variable, units, availableHours, availableTimestamps, forecastHour, mrmsTimestamp } = state;
187
-
188
- // CRITICAL: Don't start preloading if we don't have a valid current frame
189
- if (isMRMS && (mrmsTimestamp == null || !availableTimestamps || availableTimestamps.length === 0)) {
190
- hasPreloadedRef.current = false;
191
- return;
192
- }
193
-
194
- if (!isMRMS && (forecastHour == null || !availableHours || availableHours.length === 0)) {
195
- hasPreloadedRef.current = false;
196
- return;
197
- }
198
-
199
- // Only mark as "has preloaded" after validation passes
200
- hasPreloadedRef.current = true;
201
-
202
- // Fix the current forecast hour if it's invalid for this variable/model combo
203
- let effectiveForecastHour = forecastHour;
204
- if (!isMRMS && variable === 'ptypeRefl' && model === 'hrrr' && forecastHour === 0) {
205
- const validHours = availableHours.filter(hour => hour !== 0);
206
- effectiveForecastHour = validHours.length > 0 ? validHours[0] : 0;
207
- }
208
-
209
- if (!cachedGeometry.current || !cachedColormap.current) {
210
- const gridModel = isMRMS ? 'mrms' : model;
211
- const { corners, gridDef } = core._getGridCornersAndDef(gridModel);
212
- gridLayerRef.current.updateGeometry(corners, gridDef);
213
- cachedGeometry.current = { model: gridModel, variable };
214
-
215
- const { colormap, baseUnit } = core._getColormapForVariable(variable);
216
- const toUnit = core._getTargetUnit(baseUnit, units);
217
- const finalColormap = core._convertColormapUnits(colormap, baseUnit, toUnit);
218
- let dataRange;
219
- if (variable === 'ptypeRefl' || variable === 'ptypeRate') {
220
- dataRange = isMRMS ? [5, 380] : [5, 380];
221
- } else {
222
- dataRange = [finalColormap[0], finalColormap[finalColormap.length - 2]];
223
- }
224
- const colormapBytes = _generateColormapBytes(finalColormap);
225
- const colormapAsBase64 = fromByteArray(colormapBytes);
226
-
227
- gridLayerRef.current.updateColormapTexture(colormapAsBase64);
228
- cachedColormap.current = { key: `${variable}-${units}` };
229
- cachedDataRange.current = dataRange;
230
-
231
- setRenderProps({ opacity: state.opacity, dataRange: dataRange });
232
- hasInitialLoad.current = true;
233
- }
234
-
235
- // Apply the same filtering logic as in AguaceroCore._emitStateChange
236
- let filteredHours = availableHours;
237
- if (!isMRMS && variable === 'ptypeRefl' && model === 'hrrr' && availableHours && availableHours.length > 0) {
238
- filteredHours = availableHours.filter(hour => hour !== 0);
239
- }
240
-
241
- const allFrames = isMRMS ? availableTimestamps : filteredHours;
242
- if (!allFrames || allFrames.length === 0) {
243
- return;
244
- }
245
-
246
- const currentFrame = isMRMS ? mrmsTimestamp : effectiveForecastHour;
247
-
248
- // Double-check currentFrame is valid
249
- if (currentFrame == null) {
250
- hasPreloadedRef.current = false;
251
- }
252
-
253
- // Reverse the frame order to load from last to first
254
- const reversedFrames = [...allFrames].reverse();
255
- const framesToPreload = reversedFrames.filter(frame => frame !== currentFrame);
256
-
257
- const { corners, gridDef } = core._getGridCornersAndDef(isMRMS ? 'mrms' : model);
258
- const { nx, ny } = gridDef.grid_params;
259
-
260
- // Load the current frame FIRST and WAIT for it before continuing
261
- const currentCacheKey = isMRMS ? `mrms-${currentFrame}-${variable}` : `${model}-${date}-${run}-${currentFrame}-${variable}`;
262
-
263
- if (!preloadedDataCache.current.has(currentCacheKey)) {
264
- let resourcePath;
265
- if (isMRMS) {
266
- const frameDate = new Date(currentFrame * 1000);
267
- const y = frameDate.getUTCFullYear();
268
- const m = (frameDate.getUTCMonth() + 1).toString().padStart(2, '0');
269
- const d = frameDate.getUTCDate().toString().padStart(2, '0');
270
- resourcePath = `/grids/mrms/${y}${m}${d}/${currentFrame}/0/${variable}/0`;
271
- } else {
272
- resourcePath = `/grids/${model}/${date}/${run}/${currentFrame}/${variable}/0`;
273
- }
274
-
275
- const url = `${core.baseGridUrl}${resourcePath}?apiKey=${core.apiKey}`;
276
- const options = { url, apiKey: core.apiKey, bundleId: core.bundleId };
277
-
278
- try {
279
- const result = await WeatherFrameProcessorModule.processFrame(options);
280
-
281
- if (!result || !result.filePath) {
282
- return;
283
- }
284
-
285
- const { baseUnit } = core._getColormapForVariable(variable);
286
-
287
- const toUnit = core._getTargetUnit(baseUnit, units);
288
-
289
- const fieldInfo = DICTIONARIES?.fld?.[variable] || {};
290
- const serverDataUnit = fieldInfo.defaultUnit || baseUnit;
291
-
292
- let dataScale = result.scale;
293
- let dataOffset = result.offset;
294
-
295
- let convertedScale = dataScale;
296
- let convertedOffset = dataOffset;
297
-
298
- if (serverDataUnit !== baseUnit) {
299
- const conversionFunc = getUnitConversionFunction(serverDataUnit, baseUnit);
300
- if (conversionFunc) {
301
- if (result.scaleType === 'sqrt') {
302
- const physicalAtOffset = dataOffset * dataOffset;
303
- const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
304
- const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
305
- const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
306
- convertedOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
307
- const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
308
- convertedScale = newOffsetPlusScale - convertedOffset;
309
- } else {
310
- convertedOffset = conversionFunc(dataOffset);
311
- const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
312
- convertedScale = convertedOffsetPlusScale - convertedOffset;
313
- }
314
- dataScale = convertedScale;
315
- dataOffset = convertedOffset;
316
- }
317
- }
318
-
319
- if (baseUnit !== toUnit) {
320
- const conversionFunc = getUnitConversionFunction(baseUnit, toUnit);
321
- if (conversionFunc) {
322
- if (result.scaleType === 'sqrt') {
323
- const physicalAtOffset = dataOffset * dataOffset;
324
- const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
325
- const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
326
- const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
327
- convertedOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
328
- const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
329
- convertedScale = newOffsetPlusScale - convertedOffset;
330
- } else {
331
- convertedOffset = conversionFunc(dataOffset);
332
- const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
333
- convertedScale = convertedOffsetPlusScale - convertedOffset;
334
- }
335
- }
336
- }
337
-
338
- const frameData = {
339
- filePath: result.filePath,
340
- nx, ny,
341
- scale: convertedScale,
342
- offset: convertedOffset,
343
- missing: result.missing,
344
- corners,
345
- gridDef,
346
- scaleType: result.scaleType,
347
- originalScale: result.scale,
348
- originalOffset: result.offset
349
- };
350
-
351
- preloadedDataCache.current.set(currentCacheKey, frameData);
352
-
353
- // Update the GPU with the current frame
354
- gridLayerRef.current.updateDataTextureFromFile(
355
- frameData.filePath,
356
- frameData.nx, frameData.ny,
357
- frameData.scale, frameData.offset, frameData.missing,
358
- frameData.scaleType
359
- );
360
-
361
- currentGridDataRef.current = {
362
- nx: frameData.nx,
363
- ny: frameData.ny,
364
- scale: frameData.scale,
365
- offset: frameData.offset,
366
- missing: frameData.missing,
367
- gridDef: frameData.gridDef,
368
- variable: variable,
369
- units: units,
370
- scaleType: frameData.scaleType
371
- };
372
- } catch (error) {
373
- console.warn(`⚠️ [preloadAllFramesToDisk] Failed frame ${currentFrame}:`, error);
374
- hasPreloadedRef.current = false;
375
- }
376
- }
377
-
378
- // NOW preload the rest of the frames asynchronously
379
- framesToPreload.forEach((frame) => {
380
- const cacheKey = isMRMS ? `mrms-${frame}-${variable}` : `${model}-${date}-${run}-${frame}-${variable}`;
381
- if (preloadedDataCache.current.has(cacheKey)) {
382
- return;
383
- }
384
-
385
- let resourcePath;
386
- if (isMRMS) {
387
- const frameDate = new Date(frame * 1000);
388
- const y = frameDate.getUTCFullYear();
389
- const m = (frameDate.getUTCMonth() + 1).toString().padStart(2, '0');
390
- const d = frameDate.getUTCDate().toString().padStart(2, '0');
391
- resourcePath = `/grids/mrms/${y}${m}${d}/${frame}/0/${variable}/0`;
392
- } else {
393
- resourcePath = `/grids/${model}/${date}/${run}/${frame}/${variable}/0`;
394
- }
395
-
396
- const url = `${core.baseGridUrl}${resourcePath}?apiKey=${core.apiKey}`;
397
- const options = { url, apiKey: core.apiKey, bundleId: core.bundleId };
398
-
399
- WeatherFrameProcessorModule.processFrame(options)
400
- .then(result => {
401
- if (!result || !result.filePath) {
402
- console.warn(`⚠️ [preloadAllFramesToDisk] Failed frame ${frame}: No filePath`);
403
- return;
404
- }
405
-
406
- // ADD: Same two-step conversion as the current frame
407
- const { baseUnit } = core._getColormapForVariable(variable);
408
- const toUnit = core._getTargetUnit(baseUnit, units);
409
- const fieldInfo = DICTIONARIES?.fld?.[variable] || {};
410
- const serverDataUnit = fieldInfo.defaultUnit || baseUnit;
411
-
412
- let dataScale = result.scale;
413
- let dataOffset = result.offset;
414
-
415
- let convertedScale = dataScale;
416
- let convertedOffset = dataOffset;
417
-
418
- // Step 1: Convert from server unit to colormap base unit
419
- if (serverDataUnit !== baseUnit) {
420
- const conversionFunc = getUnitConversionFunction(serverDataUnit, baseUnit);
421
- if (conversionFunc) {
422
- if (result.scaleType === 'sqrt') {
423
- const physicalAtOffset = dataOffset * dataOffset;
424
- const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
425
- const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
426
- const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
427
- convertedOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
428
- const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
429
- convertedScale = newOffsetPlusScale - convertedOffset;
430
- } else {
431
- convertedOffset = conversionFunc(dataOffset);
432
- const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
433
- convertedScale = convertedOffsetPlusScale - convertedOffset;
434
- }
435
- dataScale = convertedScale;
436
- dataOffset = convertedOffset;
437
- }
438
- }
439
-
440
- // Step 2: Convert from colormap base unit to target display unit
441
- if (baseUnit !== toUnit) {
442
- const conversionFunc = getUnitConversionFunction(baseUnit, toUnit);
443
- if (conversionFunc) {
444
- if (result.scaleType === 'sqrt') {
445
- const physicalAtOffset = dataOffset * dataOffset;
446
- const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
447
- const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
448
- const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
449
- convertedOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
450
- const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
451
- convertedScale = newOffsetPlusScale - convertedOffset;
452
- } else {
453
- convertedOffset = conversionFunc(dataOffset);
454
- const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
455
- convertedScale = convertedOffsetPlusScale - convertedOffset;
456
- }
457
- }
458
- }
459
-
460
- const frameData = {
461
- filePath: result.filePath,
462
- nx, ny,
463
- scale: convertedScale,
464
- offset: convertedOffset,
465
- missing: result.missing,
466
- corners,
467
- gridDef,
468
- scaleType: result.scaleType,
469
- originalScale: result.scale,
470
- originalOffset: result.offset
471
- };
472
-
473
- preloadedDataCache.current.set(cacheKey, frameData);
474
-
475
- if (Platform.OS === 'ios' && gridLayerRef.current.primeGpuCache) {
476
- const frameInfoForGpu = {
477
- [cacheKey]: {
478
- filePath: frameData.filePath,
479
- nx: frameData.nx,
480
- ny: frameData.ny,
481
- scale: frameData.scale,
482
- offset: frameData.offset,
483
- missing: frameData.missing,
484
- scaleType: frameData.scaleType || 'linear',
485
- originalScale: frameData.originalScale,
486
- originalOffset: frameData.originalOffset
487
- }
488
- };
489
- gridLayerRef.current.primeGpuCache(frameInfoForGpu);
490
- }
491
- })
492
- .catch(error => {
493
- console.warn(`⚠️ [preloadAllFramesToDisk] Failed frame ${frame}:`, error);
494
- });
495
- });
496
- };
497
-
498
- useEffect(() => {
499
- // This effect manages the auto-refresh based on props
500
- if (autoRefresh) {
501
- const interval = (autoRefreshInterval || 30) * 1000;
502
- _checkForUpdates(); // Run immediately on enable
503
- autoRefreshIntervalId.current = setInterval(_checkForUpdates, interval);
504
- }
505
-
506
- // Cleanup function: this runs when the component unmounts or props change
507
- return () => {
508
- if (autoRefreshIntervalId.current) {
509
- clearInterval(autoRefreshIntervalId.current);
510
- autoRefreshIntervalId.current = null;
511
- }
512
- };
513
- }, [autoRefresh, autoRefreshInterval, _checkForUpdates]);
514
-
515
- const updateGPUWithCachedData = (state) => {
516
- const { model, date, run, forecastHour, variable, units, isMRMS, mrmsTimestamp } = state;
517
-
518
- const cacheKey = isMRMS
519
- ? `mrms-${mrmsTimestamp}-${variable}`
520
- : `${model}-${date}-${run}-${forecastHour}-${variable}`;
521
-
522
- if (Platform.OS === 'ios' && gridLayerRef.current.setActiveFrame) {
523
- // Get the cached data BEFORE calling setActiveFrame
524
- const cachedData = preloadedDataCache.current.get(cacheKey);
525
-
526
- if (cachedData) {
527
- currentGridDataRef.current = {
528
- nx: cachedData.nx,
529
- ny: cachedData.ny,
530
- scale: cachedData.scale,
531
- offset: cachedData.offset,
532
- missing: cachedData.missing,
533
- gridDef: cachedData.gridDef,
534
- variable: variable,
535
- units: units,
536
- scaleType: cachedData.scaleType
537
- };
538
- }
539
-
540
- // Now call setActiveFrame (which will async update the native cache)
541
- gridLayerRef.current.setActiveFrame(cacheKey);
542
- return true;
543
- }
544
-
545
- const cachedData = preloadedDataCache.current.get(cacheKey);
546
-
547
- if (!cachedData) {
548
- return false;
549
- }
550
-
551
- if (!gridLayerRef.current) {
552
- console.warn(`⚠️ [updateGPUWithCachedData] GridLayer ref not available`); // CHANGED
553
- return false;
554
- }
555
-
556
- if (!cachedGeometry.current || cachedGeometry.current.model !== (isMRMS ? 'mrms' : model) || cachedGeometry.current.variable !== variable) {
557
- gridLayerRef.current.updateGeometry(cachedData.corners, cachedData.gridDef);
558
- cachedGeometry.current = { model: (isMRMS ? 'mrms' : model), variable };
559
- }
560
-
561
- const colormapKey = `${variable}-${units}`;
562
- if (!cachedColormap.current || cachedColormap.current.key !== colormapKey) {
563
- const { colormap, baseUnit } = core._getColormapForVariable(variable);
564
- const toUnit = core._getTargetUnit(baseUnit, units);
565
- const finalColormap = core._convertColormapUnits(colormap, baseUnit, toUnit);
566
- let dataRange;
567
- if (variable === 'ptypeRefl' || variable === 'ptypeRate') {
568
- if (isMRMS) {
569
- dataRange = [5, 380];
570
- } else {
571
- dataRange = [5, 380];
572
- }
573
- } else {
574
- dataRange = [finalColormap[0], finalColormap[finalColormap.length - 2]];
575
- }
576
- const colormapBytes = _generateColormapBytes(finalColormap);
577
- const colormapAsBase64 = fromByteArray(colormapBytes);
578
-
579
- gridLayerRef.current.updateColormapTexture(colormapAsBase64);
580
- cachedColormap.current = { key: colormapKey };
581
- cachedDataRange.current = dataRange;
582
-
583
- setRenderProps(prev => ({ ...prev, dataRange }));
584
- }
585
-
586
- if (cachedData.filePath) {
587
- gridLayerRef.current.updateDataTextureFromFile(
588
- cachedData.filePath,
589
- cachedData.nx, cachedData.ny,
590
- cachedData.scale, cachedData.offset, cachedData.missing,
591
- cachedData.scaleType
592
- );
593
-
594
- // ADD THIS: Update inspector cache for file-based data too
595
- currentGridDataRef.current = {
596
- nx: cachedData.nx,
597
- ny: cachedData.ny,
598
- scale: cachedData.scale,
599
- offset: cachedData.offset,
600
- missing: cachedData.missing,
601
- gridDef: cachedData.gridDef,
602
- variable: variable,
603
- units: units
604
- };
605
- } else if (cachedData.dataAsBase64) {
606
- gridLayerRef.current.updateDataTexture(
607
- cachedData.dataAsBase64,
608
- cachedData.nx, cachedData.ny,
609
- cachedData.scale, cachedData.offset, cachedData.missing,
610
- cachedData.scaleType
611
- );
612
-
613
- // Update the inspector cache when using dataAsBase64
614
- const binaryString = atob(cachedData.dataAsBase64);
615
- const uint8Array = new Uint8Array(binaryString.length);
616
-
617
- for (let i = 0; i < binaryString.length; i++) {
618
- uint8Array[i] = binaryString.charCodeAt(i);
619
- }
620
-
621
- currentGridDataRef.current = {
622
- data: uint8Array,
623
- nx: cachedData.nx,
624
- ny: cachedData.ny,
625
- scale: cachedData.scale,
626
- offset: cachedData.offset,
627
- missing: cachedData.missing,
628
- gridDef: cachedData.gridDef,
629
- variable: variable,
630
- units: units
631
- };
632
- } else {
633
- console.error(`❌ [updateGPUWithCachedData] Cached data has no filePath or dataAsBase64!`);
634
- console.error('❌ [updateGPUWithCachedData] Cached data keys:', Object.keys(cachedData));
635
- return false;
636
- }
637
-
638
- // Update inspector parameters for file-based data too
639
- if (gridLayerRef.current && gridLayerRef.current.updateDataParameters) {
640
- gridLayerRef.current.updateDataParameters(cachedData.scale, cachedData.offset, cachedData.missing);
641
- }
642
- return true;
643
- };
644
-
645
- const handleStateChangeRef = useRef(null);
646
- const debounceTimeoutRef = useRef(null);
647
-
648
- useEffect(() => {
649
- if (core && props.customColormaps) {
650
- core.customColormaps = props.customColormaps;
651
- // Trigger a re-render if we already have data loaded
652
- if (hasInitialLoad.current) {
653
- core._emitStateChange();
654
- }
655
- }
656
- }, [core, props.customColormaps]);
657
-
658
- const getValueAtPoint = async (lng, lat) => {
659
- if (!core) {
660
- console.warn('🔍 [Inspector] Core not available');
661
- return null;
662
- }
663
-
664
- // ADD THIS: Check if we have valid data before attempting inspection
665
- if (!currentGridDataRef.current) {
666
- return null;
667
- }
668
-
669
- try {
670
- const gridIndices = core._getGridIndexFromLngLat(lng, lat);
671
- if (!gridIndices) return null;
672
-
673
- const { i, j } = gridIndices;
674
-
675
- const value = await InspectorModule.getValueAtGridIndex(i, j);
676
-
677
- if (value === null) {
678
- return null;
679
- }
680
-
681
- const { colormap, baseUnit } = core._getColormapForVariable(core.state.variable);
682
- const displayUnit = core._getTargetUnit(baseUnit, core.state.units);
683
- const finalColormap = core._convertColormapUnits(colormap, baseUnit, displayUnit);
684
- const minThreshold = finalColormap[0];
685
-
686
- if (value < minThreshold) {
687
- return null;
688
- }
689
-
690
- // Filter out values below the minimum threshold (matching shader behavior)
691
- if (value < minThreshold) {
692
- return null;
693
- }
694
-
695
- // Also check if value is NaN or effectively missing
696
- if (!isFinite(value)) {
697
- return null;
698
- }
699
-
700
- return {
701
- value: value,
702
- unit: displayUnit,
703
- variable: {
704
- code: core.state.variable,
705
- name: core.getVariableDisplayName(core.state.variable)
706
- },
707
- lngLat: { lng, lat }
708
- };
709
- } catch (error) {
710
- console.error('🔍 [Inspector] Error:', error);
711
- return null;
712
- }
713
- };
714
-
715
- const _checkForUpdates = useMemo(() => async () => {
716
- if (!core) return;
717
- const { isMRMS, model: currentModel, variable: currentVariable, date, run } = core.state;
718
-
719
- if (isMRMS) {
720
- // --- MRMS LOGIC (Keep existing logic) ---
721
- const oldTimestamps = new Set(core.mrmsStatus?.[currentVariable] || []);
722
- const mrmsStatus = await core.fetchMRMSStatus(true);
723
- const newTimestamps = mrmsStatus?.[currentVariable] || [];
724
- if (newTimestamps.length === 0) return;
725
-
726
- const newTimestampsToPreload = newTimestamps.filter(ts => !oldTimestamps.has(ts));
727
-
728
- if (newTimestampsToPreload.length > 0) {
729
- core.mrmsStatus = mrmsStatus;
730
- core._emitStateChange(); // Update UI slider without changing selection
731
-
732
- // ... (Keep your existing preloading logic here) ...
733
- const { corners, gridDef } = core._getGridCornersAndDef('mrms');
734
- const { nx, ny } = gridDef.grid_params;
735
-
736
- newTimestampsToPreload.forEach(frame => {
737
- const cacheKey = `mrms-${frame}-${currentVariable}`;
738
- if (preloadedDataCache.current.has(cacheKey)) return;
739
-
740
- const frameDate = new Date(frame * 1000);
741
- const y = frameDate.getUTCFullYear(), m = (frameDate.getUTCMonth() + 1).toString().padStart(2, '0'), d = frameDate.getUTCDate().toString().padStart(2, '0');
742
- const resourcePath = `/grids/mrms/${y}${m}${d}/${frame}/0/${currentVariable}/0`;
743
- const url = `${core.baseGridUrl}${resourcePath}?apiKey=${core.apiKey}`;
744
-
745
- WeatherFrameProcessorModule.processFrame({ url, apiKey: core.apiKey, bundleId: core.bundleId })
746
- .then(result => {
747
- if (!result || !result.filePath) return;
748
- const frameData = { filePath: result.filePath, nx, ny, scale: result.scale, offset: result.offset, missing: result.missing, corners, gridDef, scaleType: result.scaleType, originalScale: result.scale, originalOffset: result.offset };
749
- preloadedDataCache.current.set(cacheKey, frameData);
750
- if (Platform.OS === 'ios' && gridLayerRef.current?.primeGpuCache) {
751
- gridLayerRef.current.primeGpuCache({ [cacheKey]: frameData });
752
- }
753
- }).catch(error => console.warn(`[Auto-Refresh] Failed to preload frame ${frame}:`, error));
754
- });
755
-
756
- const newTimestampsSet = new Set(newTimestamps);
757
- oldTimestamps.forEach(oldTs => {
758
- if (!newTimestampsSet.has(oldTs)) {
759
- const cacheKey = `mrms-${oldTs}-${currentVariable}`;
760
- preloadedDataCache.current.delete(cacheKey);
761
- }
762
- });
763
- }
764
- } else {
765
- const modelStatus = await core.fetchModelStatus(true);
766
- core._emitStateChange();
767
-
768
- const latestRun = findLatestModelRun(modelStatus, currentModel);
769
- if (!latestRun) return;
770
- }
771
- }, [core]);
772
-
773
- useEffect(() => {
774
- if (!core) {
775
- console.warn('⚠️ [useEffect] Core is not available yet');
776
- return;
777
- }
778
-
779
- const handleStateChange = async (newState) => {
780
- props.onStateChange?.(newState);
781
-
782
- if (!previousStateRef.current) {
783
- previousStateRef.current = core.state;
784
- }
785
-
786
- const variableChanged = !previousStateRef.current || newState.variable !== previousStateRef.current.variable;
787
-
788
- if (variableChanged && gridLayerRef.current?.setVariable) {
789
- gridLayerRef.current.setVariable(newState.variable);
790
- }
791
-
792
- const stateKey = `${newState.model}-${newState.variable}-${newState.date}-${newState.run}-${newState.forecastHour}-${newState.units}-${newState.mrmsTimestamp}`;
793
-
794
- const isOpacityOnlyChange =
795
- hasInitialLoad.current &&
796
- newState.opacity !== renderProps.opacity &&
797
- newState.variable === previousStateRef.current?.variable &&
798
- newState.forecastHour === previousStateRef.current?.forecastHour &&
799
- newState.mrmsTimestamp === previousStateRef.current?.mrmsTimestamp &&
800
- newState.model === previousStateRef.current?.model &&
801
- newState.units === previousStateRef.current?.units;
802
-
803
- const isPlayStateOnlyChange =
804
- hasInitialLoad.current &&
805
- newState.isPlaying !== previousStateRef.current?.isPlaying &&
806
- newState.variable === previousStateRef.current?.variable &&
807
- newState.forecastHour === previousStateRef.current?.forecastHour &&
808
- newState.mrmsTimestamp === previousStateRef.current?.mrmsTimestamp &&
809
- newState.model === previousStateRef.current?.model &&
810
- newState.units === previousStateRef.current?.units &&
811
- newState.opacity === previousStateRef.current?.opacity;
812
-
813
- if (!isOpacityOnlyChange && !isPlayStateOnlyChange && lastProcessedState.current === stateKey) {
814
- previousStateRef.current = newState;
815
- return;
816
- }
817
-
818
- if (!isOpacityOnlyChange && !isPlayStateOnlyChange) {
819
- lastProcessedState.current = stateKey;
820
- }
821
-
822
- if (isOpacityOnlyChange) {
823
- setRenderProps(prev => ({ ...prev, opacity: newState.opacity }));
824
- previousStateRef.current = newState;
825
- return;
826
- }
827
-
828
- if (isPlayStateOnlyChange) {
829
- previousStateRef.current = newState;
830
- return;
831
- }
832
-
833
- const isUnitsOnlyChange =
834
- hasInitialLoad.current &&
835
- newState.model === previousStateRef.current.model &&
836
- newState.isMRMS === previousStateRef.current.isMRMS &&
837
- newState.variable === previousStateRef.current.variable &&
838
- newState.date === previousStateRef.current.date &&
839
- newState.run === previousStateRef.current.run &&
840
- newState.forecastHour === previousStateRef.current.forecastHour &&
841
- newState.mrmsTimestamp === previousStateRef.current.mrmsTimestamp &&
842
- newState.units !== previousStateRef.current.units;
843
-
844
- if (isUnitsOnlyChange) {
845
- const { variable, units, isMRMS, mrmsTimestamp, model, date, run, forecastHour } = newState;
846
- const oldCacheKey = isMRMS
847
- ? `mrms-${mrmsTimestamp}-${variable}`
848
- : `${model}-${date}-${run}-${forecastHour}-${variable}`;
849
-
850
- const cachedData = preloadedDataCache.current.get(oldCacheKey);
851
-
852
- if (cachedData && cachedData.originalScale !== undefined && cachedData.originalOffset !== undefined) {
853
- const { baseUnit } = core._getColormapForVariable(variable);
854
- const toUnit = core._getTargetUnit(baseUnit, units);
855
- const fieldInfo = DICTIONARIES?.fld?.[variable] || {};
856
- const serverDataUnit = fieldInfo.defaultUnit || baseUnit;
857
-
858
- let dataScale = cachedData.originalScale;
859
- let dataOffset = cachedData.originalOffset;
860
-
861
- if (serverDataUnit !== baseUnit) {
862
- const conversionFunc = getUnitConversionFunction(serverDataUnit, baseUnit);
863
- if (conversionFunc) {
864
- if (cachedData.scaleType === 'sqrt') {
865
- const physicalAtOffset = dataOffset * dataOffset;
866
- const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
867
- const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
868
- const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
869
- const newOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
870
- const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
871
- dataScale = newOffsetPlusScale - newOffset;
872
- dataOffset = newOffset;
873
- } else {
874
- const convertedOffset = conversionFunc(dataOffset);
875
- const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
876
- dataScale = convertedOffsetPlusScale - convertedOffset;
877
- dataOffset = convertedOffset;
878
- }
879
- }
880
- }
881
-
882
- if (baseUnit !== toUnit) {
883
- const conversionFunc = getUnitConversionFunction(baseUnit, toUnit);
884
- if (conversionFunc) {
885
- if (cachedData.scaleType === 'sqrt') {
886
- const physicalAtOffset = dataOffset * dataOffset;
887
- const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
888
- const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
889
- const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
890
- const newOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
891
- const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
892
- dataScale = newOffsetPlusScale - newOffset;
893
- dataOffset = newOffset;
894
- } else {
895
- const convertedOffset = conversionFunc(dataOffset);
896
- const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
897
- dataScale = convertedOffsetPlusScale - convertedOffset;
898
- dataOffset = convertedOffset;
899
- }
900
- }
901
- }
902
-
903
- const { colormap } = core._getColormapForVariable(variable);
904
- const finalColormap = core._convertColormapUnits(colormap, baseUnit, toUnit);
905
- let dataRange = (variable === 'ptypeRefl' || variable === 'ptypeRate') ? [5, 380] : [finalColormap[0], finalColormap[finalColormap.length - 2]];
906
- const colormapBytes = _generateColormapBytes(finalColormap);
907
- const colormapAsBase64 = fromByteArray(colormapBytes);
908
-
909
- gridLayerRef.current.updateColormapTexture(colormapAsBase64);
910
- cachedColormap.current = { key: `${variable}-${units}` };
911
- cachedDataRange.current = dataRange;
912
- setRenderProps(prev => ({ ...prev, dataRange, opacity: newState.opacity }));
913
-
914
- if (gridLayerRef.current && gridLayerRef.current.updateDataParameters) {
915
- const scaleTypeValue = cachedData.scaleType === 'sqrt' ? 1 : 0;
916
- gridLayerRef.current.updateDataParameters(dataScale, dataOffset, cachedData.missing, scaleTypeValue);
917
- }
918
-
919
- const newCacheKey = isMRMS ? `mrms-${mrmsTimestamp}-${variable}` : `${model}-${date}-${run}-${forecastHour}-${variable}`;
920
- preloadedDataCache.current.set(newCacheKey, { ...cachedData, scale: dataScale, offset: dataOffset });
921
- }
922
-
923
- previousStateRef.current = newState;
924
- return;
925
- }
926
-
927
- const needsFullLoad =
928
- !hasInitialLoad.current ||
929
- newState.model !== previousStateRef.current.model ||
930
- newState.isMRMS !== previousStateRef.current.isMRMS ||
931
- newState.variable !== previousStateRef.current.variable ||
932
- newState.date !== previousStateRef.current.date ||
933
- newState.run !== previousStateRef.current.run;
934
-
935
- if (needsFullLoad) {
936
- if (gridLayerRef.current) {
937
- gridLayerRef.current.setVariable(newState.variable);
938
- gridLayerRef.current.clear();
939
- if (Platform.OS === 'ios' && gridLayerRef.current.clearGpuCache) {
940
- gridLayerRef.current.clearGpuCache();
941
- }
942
- }
943
- hasPreloadedRef.current = false;
944
- preloadedDataCache.current.clear();
945
- cachedGeometry.current = null;
946
- cachedColormap.current = null;
947
- currentGridDataRef.current = null;
948
- WeatherFrameProcessorModule.cancelAllFrames();
949
-
950
- if (!newState.variable) {
951
- previousStateRef.current = newState;
952
- return;
953
- }
954
- preloadAllFramesToDisk(newState);
955
- } else if (newState.forecastHour !== previousStateRef.current.forecastHour || (newState.isMRMS && newState.mrmsTimestamp !== previousStateRef.current.mrmsTimestamp)) {
956
- const success = updateGPUWithCachedData(newState);
957
- if (success && newState.opacity !== renderProps.opacity) {
958
- setRenderProps(prev => ({ ...prev, opacity: newState.opacity }));
959
- }
960
- }
961
-
962
- previousStateRef.current = newState;
963
- };
964
- // --- END REPLACEMENT ---
965
-
966
- handleStateChangeRef.current = handleStateChange;
967
-
968
- const stableHandler = (newState) => {
969
- const isOpacityOnlyChange =
970
- previousStateRef.current &&
971
- newState.opacity !== previousStateRef.current.opacity &&
972
- newState.variable === previousStateRef.current.variable &&
973
- newState.forecastHour === previousStateRef.current.forecastHour &&
974
- newState.mrmsTimestamp === previousStateRef.current.mrmsTimestamp &&
975
- newState.model === previousStateRef.current.model &&
976
- newState.units === previousStateRef.current.units &&
977
- newState.date === previousStateRef.current.date &&
978
- newState.run === previousStateRef.current.run;
979
-
980
- if (isOpacityOnlyChange) {
981
- if (handleStateChangeRef.current) {
982
- handleStateChangeRef.current(newState);
983
- }
984
- return;
985
- }
986
-
987
- if (debounceTimeoutRef.current) {
988
- clearTimeout(debounceTimeoutRef.current);
989
- }
990
-
991
- debounceTimeoutRef.current = setTimeout(() => {
992
- if (handleStateChangeRef.current) {
993
- handleStateChangeRef.current(newState);
994
- }
995
- debounceTimeoutRef.current = null;
996
- }, 50);
997
- };
998
-
999
- core.on('state:change', stableHandler);
1000
-
1001
- return () => {
1002
- core.off('state:change', stableHandler);
1003
- if (debounceTimeoutRef.current) {
1004
- clearTimeout(debounceTimeoutRef.current);
1005
- }
1006
- };
1007
- }, [core]);
1008
-
1009
- useEffect(() => {
1010
- return () => {
1011
- preloadedDataCache.current.clear();
1012
- hasInitialLoad.current = false;
1013
- lastProcessedState.current = null;
1014
- };
1015
- }, []);
1016
-
1017
- const lastInspectorUpdateRef = useRef(0);
1018
- const INSPECTOR_THROTTLE_MS = 50;
1019
-
1020
- useEffect(() => {
1021
- if (!core || !inspectorEnabled) {
1022
- return;
1023
- }
1024
-
1025
- const handleMapMove = async (center) => {
1026
- if (!center || !Array.isArray(center) || center.length !== 2) {
1027
- return;
1028
- }
1029
-
1030
- // Throttle updates
1031
- const now = Date.now();
1032
- if (now - lastInspectorUpdateRef.current < INSPECTOR_THROTTLE_MS) {
1033
- return;
1034
- }
1035
- lastInspectorUpdateRef.current = now;
1036
-
1037
- const [longitude, latitude] = center;
1038
-
1039
- const payload = await getValueAtPoint(longitude, latitude);
1040
- onInspect?.(payload);
1041
- };
1042
-
1043
- core.on('map:move', handleMapMove);
1044
-
1045
- if (context && context.getCenter) {
1046
- const center = context.getCenter();
1047
- if (center) {
1048
- handleMapMove(center);
1049
- }
1050
- }
1051
-
1052
- return () => {
1053
- core.off('map:move', handleMapMove);
1054
- };
1055
- }, [inspectorEnabled, onInspect, core, context]);
1056
-
1057
- useEffect(() => {
1058
- if (!core || !inspectorEnabled) {
1059
- return;
1060
- }
1061
-
1062
- const triggerReinspection = () => {
1063
- const mapRef = mapRegistry.getMap();
1064
- const center = mapRef?._currentCenter;
1065
-
1066
- if (center && Array.isArray(center) && center.length === 2) {
1067
- const [longitude, latitude] = center;
1068
-
1069
- getValueAtPoint(longitude, latitude).then(payload => {
1070
- onInspect?.(payload);
1071
- });
1072
- }
1073
- };
1074
-
1075
- // Small delay to ensure data is loaded before re-inspecting
1076
- const timer = setTimeout(triggerReinspection, 100);
1077
-
1078
- return () => clearTimeout(timer);
1079
- }, [
1080
- core?.state?.variable,
1081
- core?.state?.model,
1082
- core?.state?.forecastHour,
1083
- core?.state?.mrmsTimestamp,
1084
- core?.state?.units,
1085
- inspectorEnabled,
1086
- onInspect
1087
- ]);
1088
-
1089
- useEffect(() => {
1090
- if (!core) {
1091
- return;
1092
- }
1093
-
1094
- const handleCameraChange = (center) => {
1095
- if (core && center) {
1096
- core.setMapCenter(center);
1097
- }
1098
- };
1099
-
1100
- // Register with the global registry
1101
- mapRegistry.addCameraListener(handleCameraChange);
1102
-
1103
- // Try to get initial center
1104
- const mapRef = mapRegistry.getMap();
1105
- if (mapRef?._currentCenter) {
1106
- handleCameraChange(mapRef._currentCenter);
1107
- }
1108
-
1109
- return () => {
1110
- mapRegistry.removeCameraListener(handleCameraChange);
1111
- };
1112
- }, [core]);
1113
-
1114
- useEffect(() => {
1115
- core.initialize();
1116
- return () => {
1117
- core.destroy();
1118
- };
1119
- }, [core]);
1120
-
1121
- return (
1122
- <GridRenderLayer
1123
- ref={gridLayerRef}
1124
- opacity={renderProps.opacity}
1125
- dataRange={renderProps.dataRange}
1126
- belowID="AML_-_terrain"
1127
- />
1128
- );
1129
- });
1130
-
1131
- WeatherLayerManager.getAvailableVariables = (options) => {
1132
- if (!options || !options.apiKey) {
1133
- console.error("API key must be provided to get available variables.");
1134
- return [];
1135
- }
1136
- const core = new AguaceroCore({ apiKey: options.apiKey });
1137
- return core.getAvailableVariables('mrms');
1
+ // packages/react-native/src/WeatherLayerManager.js
2
+
3
+ import { AguaceroCore, DICTIONARIES, getUnitConversionFunction } from '@aguacerowx/javascript-sdk';
4
+ import { fromByteArray } from 'base64-js';
5
+ import React, { forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
6
+ import { NativeModules, Platform } from 'react-native';
7
+ import { AguaceroContext } from './AguaceroContext';
8
+ import { GridRenderLayer } from './GridRenderLayer';
9
+ import { mapRegistry } from './MapRegistry';
10
+
11
+ // --- PERFORMANCE HELPER ---
12
+ const perfLog = (msg) => {
13
+ // Enable this if you want JS logs alongside native logs
14
+ console.log(`⚡️ [PERF] [JS] ${msg} | ${performance.now().toFixed(2)}ms`);
15
+ };
16
+ // --------------------------
17
+
18
+ function findLatestModelRun(modelsData, modelName) {
19
+ const model = modelsData?.[modelName];
20
+ if (!model) return null;
21
+ const availableDates = Object.keys(model).sort((a, b) => b.localeCompare(a));
22
+ for (const date of availableDates) {
23
+ const runs = model[date];
24
+ if (!runs) continue;
25
+ const availableRuns = Object.keys(runs).sort((a, b) => b.localeCompare(a));
26
+ if (availableRuns.length > 0) return { date: date, run: availableRuns[0] };
27
+ }
28
+ return null;
29
+ }
30
+ const { WeatherFrameProcessorModule, InspectorModule } = NativeModules;
31
+
32
+ /**
33
+ * A helper function to generate the raw RGBA byte buffer for the colormap texture.
34
+ */
35
+ const _generateColormapBytes = (colormap) => {
36
+ const width = 256;
37
+ const data = new Uint8Array(width * 4);
38
+ const stops = colormap.reduce((acc, _, i) => (i % 2 === 0 ? [...acc, { value: colormap[i], color: colormap[i + 1] }] : acc), []);
39
+
40
+ if (stops.length === 0) return data;
41
+
42
+ const minVal = stops[0].value;
43
+ const maxVal = stops[stops.length - 1].value;
44
+
45
+ const hexToRgb = (hex) => {
46
+ const r = parseInt(hex.slice(1, 3), 16);
47
+ const g = parseInt(hex.slice(3, 5), 16);
48
+ const b = parseInt(hex.slice(5, 7), 16);
49
+ return [r, g, b];
50
+ };
51
+
52
+ for (let i = 0; i < width; i++) {
53
+ const val = minVal + (i / (width - 1)) * (maxVal - minVal);
54
+ let lower = stops[0];
55
+ let upper = stops[stops.length - 1];
56
+ for (let j = 0; j < stops.length - 1; j++) {
57
+ if (val >= stops[j].value && val <= stops[j + 1].value) {
58
+ lower = stops[j];
59
+ upper = stops[j + 1];
60
+ break;
61
+ }
62
+ }
63
+ const t = (val - lower.value) / (upper.value - lower.value || 1);
64
+ const lowerRgb = hexToRgb(lower.color);
65
+ const upperRgb = hexToRgb(upper.color);
66
+ const rgb = lowerRgb.map((c, idx) => c * (1 - t) + upperRgb[idx] * t);
67
+
68
+ const offset = i * 4;
69
+ data[offset + 0] = Math.round(rgb[0]);
70
+ data[offset + 1] = Math.round(rgb[1]);
71
+ data[offset + 2] = Math.round(rgb[2]);
72
+ data[offset + 3] = 255;
73
+ }
74
+ return data;
75
+ };
76
+
77
+ AguaceroCore.prototype.setMapCenter = function (center) {
78
+ this.emit('map:move', center);
79
+ };
80
+
81
+ export const WeatherLayerManager = forwardRef((props, ref) => {
82
+ const {
83
+ inspectorEnabled,
84
+ onInspect,
85
+ apiKey,
86
+ customColormaps,
87
+ initialMode,
88
+ initialVariable,
89
+ autoRefresh,
90
+ autoRefreshInterval,
91
+ initialModel,
92
+ ...restProps
93
+ } = props;
94
+ const context = useContext(AguaceroContext);
95
+
96
+ // Create the core here instead of getting it from context
97
+ const core = useMemo(() => new AguaceroCore({
98
+ apiKey: apiKey,
99
+ customColormaps: customColormaps,
100
+ // ADD: Pass layerOptions to the core's constructor
101
+ layerOptions: {
102
+ mode: initialMode,
103
+ variable: initialVariable,
104
+ model: initialModel
105
+ }
106
+ }), [apiKey]);
107
+
108
+ const gridLayerRef = useRef(null);
109
+ const currentGridDataRef = useRef(null);
110
+ const autoRefreshIntervalId = useRef(null);
111
+
112
+ // Cache for preloaded grid data - stores the processed data ready for GPU upload
113
+ const preloadedDataCache = useRef(new Map());
114
+
115
+ // Store geometry and colormap that don't change with forecast hour
116
+ const cachedGeometry = useRef(null);
117
+ const cachedColormap = useRef(null);
118
+ const cachedDataRange = useRef([0, 1]);
119
+
120
+ // Track if we've done the initial load
121
+ const hasInitialLoad = useRef(false);
122
+ const hasPreloadedRef = useRef(false);
123
+
124
+ // Track the last state we processed to avoid redundant updates
125
+ const lastProcessedState = useRef(null);
126
+ const previousStateRef = useRef(null);
127
+
128
+ const [renderProps, setRenderProps] = useState({
129
+ opacity: 1,
130
+ dataRange: [0, 1]
131
+ });
132
+
133
+ useImperativeHandle(ref, () => {
134
+ const setAutoRefresh = (enabled, intervalSeconds) => {
135
+ if (autoRefreshIntervalId.current) {
136
+ clearInterval(autoRefreshIntervalId.current);
137
+ autoRefreshIntervalId.current = null;
138
+ }
139
+ if (enabled) {
140
+ const effectiveInterval = (intervalSeconds || autoRefreshInterval || 30) * 1000;
141
+ // Run once immediately, then start the interval
142
+ _checkForUpdates();
143
+ autoRefreshIntervalId.current = setInterval(_checkForUpdates, effectiveInterval);
144
+ }
145
+ };
146
+ return {
147
+ play: () => {
148
+ core.play();
149
+ },
150
+ pause: () => {
151
+ core.pause();
152
+ },
153
+ togglePlay: () => {
154
+ core.togglePlay();
155
+ },
156
+ step: (direction) => {
157
+ core.step(direction);
158
+ },
159
+ setPlaybackSpeed: (speed) => {
160
+ if (speed > 0) {
161
+ core.playbackSpeed = speed;
162
+ if (core.isPlaying) {
163
+ core.pause();
164
+ core.play();
165
+ }
166
+ }
167
+ },
168
+ setOpacity: (opacity) => core.setOpacity(opacity),
169
+ setUnits: (units) => core.setUnits(units),
170
+ switchMode: (options) => core.switchMode(options),
171
+ getAvailableVariables: (model) => core.getAvailableVariables(model),
172
+ getVariableDisplayName: (code) => core.getVariableDisplayName(code),
173
+ setRun: (runString) => core.setState({ run: runString.split(':')[1] }),
174
+ setState: (newState) => core.setState(newState),
175
+ setMRMSTimestamp: (timestamp) => core.setMRMSTimestamp(timestamp),
176
+ setSmoothing: (enabled) => {
177
+ if (gridLayerRef.current) {
178
+ gridLayerRef.current.setSmoothing(enabled);
179
+ }
180
+ },
181
+ setAutoRefresh,
182
+ refreshData: () => {
183
+ _checkForUpdates();
184
+ },
185
+ };
186
+ }, [core, autoRefreshInterval, _checkForUpdates]);
187
+
188
+ const preloadAllFramesToDisk = async (state) => {
189
+ const start = performance.now();
190
+ perfLog("preloadAllFramesToDisk called");
191
+
192
+ if (hasPreloadedRef.current) {
193
+ return;
194
+ }
195
+
196
+ const { isMRMS, model, date, run, variable, units, availableHours, availableTimestamps, forecastHour, mrmsTimestamp } = state;
197
+
198
+ // CRITICAL: Don't start preloading if we don't have a valid current frame
199
+ if (isMRMS && (mrmsTimestamp == null || !availableTimestamps || availableTimestamps.length === 0)) {
200
+ hasPreloadedRef.current = false;
201
+ return;
202
+ }
203
+
204
+ if (!isMRMS && (forecastHour == null || !availableHours || availableHours.length === 0)) {
205
+ hasPreloadedRef.current = false;
206
+ return;
207
+ }
208
+
209
+ // Only mark as "has preloaded" after validation passes
210
+ hasPreloadedRef.current = true;
211
+
212
+ // Fix the current forecast hour if it's invalid for this variable/model combo
213
+ let effectiveForecastHour = forecastHour;
214
+ if (!isMRMS && variable === 'ptypeRefl' && model === 'hrrr' && forecastHour === 0) {
215
+ const validHours = availableHours.filter(hour => hour !== 0);
216
+ effectiveForecastHour = validHours.length > 0 ? validHours[0] : 0;
217
+ }
218
+
219
+ if (!cachedGeometry.current || !cachedColormap.current) {
220
+ const gridModel = isMRMS ? 'mrms' : model;
221
+ const { corners, gridDef } = core._getGridCornersAndDef(gridModel);
222
+ gridLayerRef.current.updateGeometry(corners, gridDef);
223
+ cachedGeometry.current = { model: gridModel, variable };
224
+
225
+ const { colormap, baseUnit } = core._getColormapForVariable(variable);
226
+ const toUnit = core._getTargetUnit(baseUnit, units);
227
+ const finalColormap = core._convertColormapUnits(colormap, baseUnit, toUnit);
228
+ let dataRange;
229
+ if (variable === 'ptypeRefl' || variable === 'ptypeRate') {
230
+ dataRange = isMRMS ? [5, 380] : [5, 380];
231
+ } else {
232
+ dataRange = [finalColormap[0], finalColormap[finalColormap.length - 2]];
233
+ }
234
+ const colormapBytes = _generateColormapBytes(finalColormap);
235
+ const colormapAsBase64 = fromByteArray(colormapBytes);
236
+
237
+ gridLayerRef.current.updateColormapTexture(colormapAsBase64);
238
+ cachedColormap.current = { key: `${variable}-${units}` };
239
+ cachedDataRange.current = dataRange;
240
+
241
+ setRenderProps({ opacity: state.opacity, dataRange: dataRange });
242
+ hasInitialLoad.current = true;
243
+ }
244
+
245
+ // Apply the same filtering logic as in AguaceroCore._emitStateChange
246
+ let filteredHours = availableHours;
247
+ if (!isMRMS && variable === 'ptypeRefl' && model === 'hrrr' && availableHours && availableHours.length > 0) {
248
+ filteredHours = availableHours.filter(hour => hour !== 0);
249
+ }
250
+
251
+ const allFrames = isMRMS ? availableTimestamps : filteredHours;
252
+ if (!allFrames || allFrames.length === 0) {
253
+ return;
254
+ }
255
+
256
+ const currentFrame = isMRMS ? mrmsTimestamp : effectiveForecastHour;
257
+
258
+ // Double-check currentFrame is valid
259
+ if (currentFrame == null) {
260
+ hasPreloadedRef.current = false;
261
+ }
262
+
263
+ // Reverse the frame order to load from last to first
264
+ const reversedFrames = [...allFrames].reverse();
265
+ const framesToPreload = reversedFrames.filter(frame => frame !== currentFrame);
266
+
267
+ const { corners, gridDef } = core._getGridCornersAndDef(isMRMS ? 'mrms' : model);
268
+ const { nx, ny } = gridDef.grid_params;
269
+
270
+ // Load the current frame FIRST and WAIT for it before continuing
271
+ const currentCacheKey = isMRMS ? `mrms-${currentFrame}-${variable}` : `${model}-${date}-${run}-${currentFrame}-${variable}`;
272
+
273
+ if (!preloadedDataCache.current.has(currentCacheKey)) {
274
+ let resourcePath;
275
+ if (isMRMS) {
276
+ const frameDate = new Date(currentFrame * 1000);
277
+ const y = frameDate.getUTCFullYear();
278
+ const m = (frameDate.getUTCMonth() + 1).toString().padStart(2, '0');
279
+ const d = frameDate.getUTCDate().toString().padStart(2, '0');
280
+ resourcePath = `/grids/mrms/${y}${m}${d}/${currentFrame}/0/${variable}/0`;
281
+ } else {
282
+ resourcePath = `/grids/${model}/${date}/${run}/${currentFrame}/${variable}/0`;
283
+ }
284
+
285
+ const url = `${core.baseGridUrl}${resourcePath}?apiKey=${core.apiKey}`;
286
+ const options = { url, apiKey: core.apiKey, bundleId: core.bundleId };
287
+
288
+ try {
289
+ const netStart = performance.now();
290
+ const result = await WeatherFrameProcessorModule.processFrame(options);
291
+ perfLog(`First frame fetched in ${(performance.now() - netStart).toFixed(2)}ms`);
292
+
293
+ if (!result || !result.filePath) {
294
+ return;
295
+ }
296
+
297
+ const { baseUnit } = core._getColormapForVariable(variable);
298
+
299
+ const toUnit = core._getTargetUnit(baseUnit, units);
300
+
301
+ const fieldInfo = DICTIONARIES?.fld?.[variable] || {};
302
+ const serverDataUnit = fieldInfo.defaultUnit || baseUnit;
303
+
304
+ let dataScale = result.scale;
305
+ let dataOffset = result.offset;
306
+
307
+ let convertedScale = dataScale;
308
+ let convertedOffset = dataOffset;
309
+
310
+ if (serverDataUnit !== baseUnit) {
311
+ const conversionFunc = getUnitConversionFunction(serverDataUnit, baseUnit);
312
+ if (conversionFunc) {
313
+ if (result.scaleType === 'sqrt') {
314
+ const physicalAtOffset = dataOffset * dataOffset;
315
+ const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
316
+ const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
317
+ const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
318
+ convertedOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
319
+ const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
320
+ convertedScale = newOffsetPlusScale - convertedOffset;
321
+ } else {
322
+ convertedOffset = conversionFunc(dataOffset);
323
+ const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
324
+ convertedScale = convertedOffsetPlusScale - convertedOffset;
325
+ }
326
+ dataScale = convertedScale;
327
+ dataOffset = convertedOffset;
328
+ }
329
+ }
330
+
331
+ if (baseUnit !== toUnit) {
332
+ const conversionFunc = getUnitConversionFunction(baseUnit, toUnit);
333
+ if (conversionFunc) {
334
+ if (result.scaleType === 'sqrt') {
335
+ const physicalAtOffset = dataOffset * dataOffset;
336
+ const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
337
+ const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
338
+ const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
339
+ convertedOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
340
+ const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
341
+ convertedScale = newOffsetPlusScale - convertedOffset;
342
+ } else {
343
+ convertedOffset = conversionFunc(dataOffset);
344
+ const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
345
+ convertedScale = convertedOffsetPlusScale - convertedOffset;
346
+ }
347
+ }
348
+ }
349
+
350
+ const frameData = {
351
+ filePath: result.filePath,
352
+ nx, ny,
353
+ scale: convertedScale,
354
+ offset: convertedOffset,
355
+ missing: result.missing,
356
+ corners,
357
+ gridDef,
358
+ scaleType: result.scaleType,
359
+ originalScale: result.scale,
360
+ originalOffset: result.offset
361
+ };
362
+
363
+ preloadedDataCache.current.set(currentCacheKey, frameData);
364
+
365
+ // Update the GPU with the current frame
366
+ gridLayerRef.current.updateDataTextureFromFile(
367
+ frameData.filePath,
368
+ frameData.nx, frameData.ny,
369
+ frameData.scale, frameData.offset, frameData.missing,
370
+ frameData.scaleType
371
+ );
372
+
373
+ perfLog(`First frame updated to GPU`);
374
+
375
+ currentGridDataRef.current = {
376
+ nx: frameData.nx,
377
+ ny: frameData.ny,
378
+ scale: frameData.scale,
379
+ offset: frameData.offset,
380
+ missing: frameData.missing,
381
+ gridDef: frameData.gridDef,
382
+ variable: variable,
383
+ units: units,
384
+ scaleType: frameData.scaleType
385
+ };
386
+ } catch (error) {
387
+ console.warn(`⚠️ [preloadAllFramesToDisk] Failed frame ${currentFrame}:`, error);
388
+ hasPreloadedRef.current = false;
389
+ }
390
+ }
391
+
392
+ // NOW preload the rest of the frames asynchronously
393
+ perfLog(`Triggering fetch for ${framesToPreload.length} background frames`);
394
+
395
+ framesToPreload.forEach((frame) => {
396
+ const cacheKey = isMRMS ? `mrms-${frame}-${variable}` : `${model}-${date}-${run}-${frame}-${variable}`;
397
+ if (preloadedDataCache.current.has(cacheKey)) {
398
+ return;
399
+ }
400
+
401
+ let resourcePath;
402
+ if (isMRMS) {
403
+ const frameDate = new Date(frame * 1000);
404
+ const y = frameDate.getUTCFullYear();
405
+ const m = (frameDate.getUTCMonth() + 1).toString().padStart(2, '0');
406
+ const d = frameDate.getUTCDate().toString().padStart(2, '0');
407
+ resourcePath = `/grids/mrms/${y}${m}${d}/${frame}/0/${variable}/0`;
408
+ } else {
409
+ resourcePath = `/grids/${model}/${date}/${run}/${frame}/${variable}/0`;
410
+ }
411
+
412
+ const url = `${core.baseGridUrl}${resourcePath}?apiKey=${core.apiKey}`;
413
+ const options = { url, apiKey: core.apiKey, bundleId: core.bundleId };
414
+
415
+ WeatherFrameProcessorModule.processFrame(options)
416
+ .then(result => {
417
+ if (!result || !result.filePath) {
418
+ console.warn(`⚠️ [preloadAllFramesToDisk] Failed frame ${frame}: No filePath`);
419
+ return;
420
+ }
421
+
422
+ // ADD: Same two-step conversion as the current frame
423
+ const { baseUnit } = core._getColormapForVariable(variable);
424
+ const toUnit = core._getTargetUnit(baseUnit, units);
425
+ const fieldInfo = DICTIONARIES?.fld?.[variable] || {};
426
+ const serverDataUnit = fieldInfo.defaultUnit || baseUnit;
427
+
428
+ let dataScale = result.scale;
429
+ let dataOffset = result.offset;
430
+
431
+ let convertedScale = dataScale;
432
+ let convertedOffset = dataOffset;
433
+
434
+ // Step 1: Convert from server unit to colormap base unit
435
+ if (serverDataUnit !== baseUnit) {
436
+ const conversionFunc = getUnitConversionFunction(serverDataUnit, baseUnit);
437
+ if (conversionFunc) {
438
+ if (result.scaleType === 'sqrt') {
439
+ const physicalAtOffset = dataOffset * dataOffset;
440
+ const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
441
+ const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
442
+ const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
443
+ convertedOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
444
+ const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
445
+ convertedScale = newOffsetPlusScale - convertedOffset;
446
+ } else {
447
+ convertedOffset = conversionFunc(dataOffset);
448
+ const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
449
+ convertedScale = convertedOffsetPlusScale - convertedOffset;
450
+ }
451
+ dataScale = convertedScale;
452
+ dataOffset = convertedOffset;
453
+ }
454
+ }
455
+
456
+ // Step 2: Convert from colormap base unit to target display unit
457
+ if (baseUnit !== toUnit) {
458
+ const conversionFunc = getUnitConversionFunction(baseUnit, toUnit);
459
+ if (conversionFunc) {
460
+ if (result.scaleType === 'sqrt') {
461
+ const physicalAtOffset = dataOffset * dataOffset;
462
+ const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
463
+ const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
464
+ const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
465
+ convertedOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
466
+ const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
467
+ convertedScale = newOffsetPlusScale - convertedOffset;
468
+ } else {
469
+ convertedOffset = conversionFunc(dataOffset);
470
+ const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
471
+ convertedScale = convertedOffsetPlusScale - convertedOffset;
472
+ }
473
+ }
474
+ }
475
+
476
+ const frameData = {
477
+ filePath: result.filePath,
478
+ nx, ny,
479
+ scale: convertedScale,
480
+ offset: convertedOffset,
481
+ missing: result.missing,
482
+ corners,
483
+ gridDef,
484
+ scaleType: result.scaleType,
485
+ originalScale: result.scale,
486
+ originalOffset: result.offset
487
+ };
488
+
489
+ preloadedDataCache.current.set(cacheKey, frameData);
490
+
491
+ if (Platform.OS === 'ios' && gridLayerRef.current.primeGpuCache) {
492
+ const frameInfoForGpu = {
493
+ [cacheKey]: {
494
+ filePath: frameData.filePath,
495
+ nx: frameData.nx,
496
+ ny: frameData.ny,
497
+ scale: frameData.scale,
498
+ offset: frameData.offset,
499
+ missing: frameData.missing,
500
+ scaleType: frameData.scaleType || 'linear',
501
+ originalScale: frameData.originalScale,
502
+ originalOffset: frameData.originalOffset
503
+ }
504
+ };
505
+ gridLayerRef.current.primeGpuCache(frameInfoForGpu);
506
+ }
507
+ })
508
+ .catch(error => {
509
+ console.warn(`⚠️ [preloadAllFramesToDisk] Failed frame ${frame}:`, error);
510
+ });
511
+ });
512
+
513
+ perfLog(`Completed preload triggering in ${(performance.now() - start).toFixed(2)}ms`);
514
+ };
515
+
516
+ useEffect(() => {
517
+ // This effect manages the auto-refresh based on props
518
+ if (autoRefresh) {
519
+ const interval = (autoRefreshInterval || 30) * 1000;
520
+ _checkForUpdates(); // Run immediately on enable
521
+ autoRefreshIntervalId.current = setInterval(_checkForUpdates, interval);
522
+ }
523
+
524
+ // Cleanup function: this runs when the component unmounts or props change
525
+ return () => {
526
+ if (autoRefreshIntervalId.current) {
527
+ clearInterval(autoRefreshIntervalId.current);
528
+ autoRefreshIntervalId.current = null;
529
+ }
530
+ };
531
+ }, [autoRefresh, autoRefreshInterval, _checkForUpdates]);
532
+
533
+ const updateGPUWithCachedData = (state) => {
534
+ const start = performance.now();
535
+ const { model, date, run, forecastHour, variable, units, isMRMS, mrmsTimestamp } = state;
536
+
537
+ const cacheKey = isMRMS
538
+ ? `mrms-${mrmsTimestamp}-${variable}`
539
+ : `${model}-${date}-${run}-${forecastHour}-${variable}`;
540
+
541
+ if (Platform.OS === 'ios' && gridLayerRef.current.setActiveFrame) {
542
+ // Get the cached data BEFORE calling setActiveFrame
543
+ const cachedData = preloadedDataCache.current.get(cacheKey);
544
+
545
+ if (cachedData) {
546
+ currentGridDataRef.current = {
547
+ nx: cachedData.nx,
548
+ ny: cachedData.ny,
549
+ scale: cachedData.scale,
550
+ offset: cachedData.offset,
551
+ missing: cachedData.missing,
552
+ gridDef: cachedData.gridDef,
553
+ variable: variable,
554
+ units: units,
555
+ scaleType: cachedData.scaleType
556
+ };
557
+ }
558
+
559
+ if (__DEV__) {
560
+ console.log(`[WeatherLayerManager] setActiveFrame: ${cacheKey}`);
561
+ }
562
+ gridLayerRef.current.setActiveFrame(cacheKey);
563
+ perfLog(`setActiveFrame sent in ${(performance.now() - start).toFixed(2)}ms`);
564
+ return true;
565
+ }
566
+
567
+ const cachedData = preloadedDataCache.current.get(cacheKey);
568
+
569
+ if (!cachedData) {
570
+ return false;
571
+ }
572
+
573
+ if (!gridLayerRef.current) {
574
+ console.warn(`⚠️ [updateGPUWithCachedData] GridLayer ref not available`); // CHANGED
575
+ return false;
576
+ }
577
+
578
+ if (!cachedGeometry.current || cachedGeometry.current.model !== (isMRMS ? 'mrms' : model) || cachedGeometry.current.variable !== variable) {
579
+ gridLayerRef.current.updateGeometry(cachedData.corners, cachedData.gridDef);
580
+ cachedGeometry.current = { model: (isMRMS ? 'mrms' : model), variable };
581
+ }
582
+
583
+ const colormapKey = `${variable}-${units}`;
584
+ if (!cachedColormap.current || cachedColormap.current.key !== colormapKey) {
585
+ const { colormap, baseUnit } = core._getColormapForVariable(variable);
586
+ const toUnit = core._getTargetUnit(baseUnit, units);
587
+ const finalColormap = core._convertColormapUnits(colormap, baseUnit, toUnit);
588
+ let dataRange;
589
+ if (variable === 'ptypeRefl' || variable === 'ptypeRate') {
590
+ if (isMRMS) {
591
+ dataRange = [5, 380];
592
+ } else {
593
+ dataRange = [5, 380];
594
+ }
595
+ } else {
596
+ dataRange = [finalColormap[0], finalColormap[finalColormap.length - 2]];
597
+ }
598
+ const colormapBytes = _generateColormapBytes(finalColormap);
599
+ const colormapAsBase64 = fromByteArray(colormapBytes);
600
+
601
+ gridLayerRef.current.updateColormapTexture(colormapAsBase64);
602
+ cachedColormap.current = { key: colormapKey };
603
+ cachedDataRange.current = dataRange;
604
+
605
+ setRenderProps(prev => ({ ...prev, dataRange }));
606
+ }
607
+
608
+ if (cachedData.filePath) {
609
+ gridLayerRef.current.updateDataTextureFromFile(
610
+ cachedData.filePath,
611
+ cachedData.nx, cachedData.ny,
612
+ cachedData.scale, cachedData.offset, cachedData.missing,
613
+ cachedData.scaleType
614
+ );
615
+
616
+ // ADD THIS: Update inspector cache for file-based data too
617
+ currentGridDataRef.current = {
618
+ nx: cachedData.nx,
619
+ ny: cachedData.ny,
620
+ scale: cachedData.scale,
621
+ offset: cachedData.offset,
622
+ missing: cachedData.missing,
623
+ gridDef: cachedData.gridDef,
624
+ variable: variable,
625
+ units: units
626
+ };
627
+ } else if (cachedData.dataAsBase64) {
628
+ gridLayerRef.current.updateDataTexture(
629
+ cachedData.dataAsBase64,
630
+ cachedData.nx, cachedData.ny,
631
+ cachedData.scale, cachedData.offset, cachedData.missing,
632
+ cachedData.scaleType
633
+ );
634
+
635
+ // Update the inspector cache when using dataAsBase64
636
+ const binaryString = atob(cachedData.dataAsBase64);
637
+ const uint8Array = new Uint8Array(binaryString.length);
638
+
639
+ for (let i = 0; i < binaryString.length; i++) {
640
+ uint8Array[i] = binaryString.charCodeAt(i);
641
+ }
642
+
643
+ currentGridDataRef.current = {
644
+ data: uint8Array,
645
+ nx: cachedData.nx,
646
+ ny: cachedData.ny,
647
+ scale: cachedData.scale,
648
+ offset: cachedData.offset,
649
+ missing: cachedData.missing,
650
+ gridDef: cachedData.gridDef,
651
+ variable: variable,
652
+ units: units
653
+ };
654
+ } else {
655
+ console.error(`❌ [updateGPUWithCachedData] Cached data has no filePath or dataAsBase64!`);
656
+ console.error('❌ [updateGPUWithCachedData] Cached data keys:', Object.keys(cachedData));
657
+ return false;
658
+ }
659
+
660
+ // Update inspector parameters for file-based data too
661
+ if (gridLayerRef.current && gridLayerRef.current.updateDataParameters) {
662
+ gridLayerRef.current.updateDataParameters(cachedData.scale, cachedData.offset, cachedData.missing);
663
+ }
664
+ return true;
665
+ };
666
+
667
+ const handleStateChangeRef = useRef(null);
668
+ const debounceTimeoutRef = useRef(null);
669
+
670
+ useEffect(() => {
671
+ if (core && props.customColormaps) {
672
+ core.customColormaps = props.customColormaps;
673
+ // Trigger a re-render if we already have data loaded
674
+ if (hasInitialLoad.current) {
675
+ core._emitStateChange();
676
+ }
677
+ }
678
+ }, [core, props.customColormaps]);
679
+
680
+ const getValueAtPoint = async (lng, lat) => {
681
+ if (!core) {
682
+ console.warn('🔍 [Inspector] Core not available');
683
+ return null;
684
+ }
685
+
686
+ // ADD THIS: Check if we have valid data before attempting inspection
687
+ if (!currentGridDataRef.current) {
688
+ return null;
689
+ }
690
+
691
+ try {
692
+ const gridIndices = core._getGridIndexFromLngLat(lng, lat);
693
+ if (!gridIndices) return null;
694
+
695
+ const { i, j } = gridIndices;
696
+
697
+ const value = await InspectorModule.getValueAtGridIndex(i, j);
698
+
699
+ if (value === null) {
700
+ return null;
701
+ }
702
+
703
+ const { colormap, baseUnit } = core._getColormapForVariable(core.state.variable);
704
+ const displayUnit = core._getTargetUnit(baseUnit, core.state.units);
705
+ const finalColormap = core._convertColormapUnits(colormap, baseUnit, displayUnit);
706
+ const minThreshold = finalColormap[0];
707
+
708
+ if (value < minThreshold) {
709
+ return null;
710
+ }
711
+
712
+ // Filter out values below the minimum threshold (matching shader behavior)
713
+ if (value < minThreshold) {
714
+ return null;
715
+ }
716
+
717
+ // Also check if value is NaN or effectively missing
718
+ if (!isFinite(value)) {
719
+ return null;
720
+ }
721
+
722
+ return {
723
+ value: value,
724
+ unit: displayUnit,
725
+ variable: {
726
+ code: core.state.variable,
727
+ name: core.getVariableDisplayName(core.state.variable)
728
+ },
729
+ lngLat: { lng, lat }
730
+ };
731
+ } catch (error) {
732
+ console.error('🔍 [Inspector] Error:', error);
733
+ return null;
734
+ }
735
+ };
736
+
737
+ const _checkForUpdates = useMemo(() => async () => {
738
+ if (!core) return;
739
+ const { isMRMS, model: currentModel, variable: currentVariable, date, run } = core.state;
740
+
741
+ if (isMRMS) {
742
+ // --- MRMS LOGIC (Keep existing logic) ---
743
+ const oldTimestamps = new Set(core.mrmsStatus?.[currentVariable] || []);
744
+ const mrmsStatus = await core.fetchMRMSStatus(true);
745
+ const newTimestamps = mrmsStatus?.[currentVariable] || [];
746
+ if (newTimestamps.length === 0) return;
747
+
748
+ const newTimestampsToPreload = newTimestamps.filter(ts => !oldTimestamps.has(ts));
749
+
750
+ if (newTimestampsToPreload.length > 0) {
751
+ core.mrmsStatus = mrmsStatus;
752
+ core._emitStateChange(); // Update UI slider without changing selection
753
+
754
+ // ... (Keep your existing preloading logic here) ...
755
+ const { corners, gridDef } = core._getGridCornersAndDef('mrms');
756
+ const { nx, ny } = gridDef.grid_params;
757
+
758
+ newTimestampsToPreload.forEach(frame => {
759
+ const cacheKey = `mrms-${frame}-${currentVariable}`;
760
+ if (preloadedDataCache.current.has(cacheKey)) return;
761
+
762
+ const frameDate = new Date(frame * 1000);
763
+ const y = frameDate.getUTCFullYear(), m = (frameDate.getUTCMonth() + 1).toString().padStart(2, '0'), d = frameDate.getUTCDate().toString().padStart(2, '0');
764
+ const resourcePath = `/grids/mrms/${y}${m}${d}/${frame}/0/${currentVariable}/0`;
765
+ const url = `${core.baseGridUrl}${resourcePath}?apiKey=${core.apiKey}`;
766
+
767
+ WeatherFrameProcessorModule.processFrame({ url, apiKey: core.apiKey, bundleId: core.bundleId })
768
+ .then(result => {
769
+ if (!result || !result.filePath) return;
770
+ const frameData = { filePath: result.filePath, nx, ny, scale: result.scale, offset: result.offset, missing: result.missing, corners, gridDef, scaleType: result.scaleType, originalScale: result.scale, originalOffset: result.offset };
771
+ preloadedDataCache.current.set(cacheKey, frameData);
772
+ if (Platform.OS === 'ios' && gridLayerRef.current?.primeGpuCache) {
773
+ gridLayerRef.current.primeGpuCache({ [cacheKey]: frameData });
774
+ }
775
+ }).catch(error => console.warn(`[Auto-Refresh] Failed to preload frame ${frame}:`, error));
776
+ });
777
+
778
+ const newTimestampsSet = new Set(newTimestamps);
779
+ oldTimestamps.forEach(oldTs => {
780
+ if (!newTimestampsSet.has(oldTs)) {
781
+ const cacheKey = `mrms-${oldTs}-${currentVariable}`;
782
+ preloadedDataCache.current.delete(cacheKey);
783
+ }
784
+ });
785
+ }
786
+ } else {
787
+ const modelStatus = await core.fetchModelStatus(true);
788
+ core._emitStateChange();
789
+
790
+ const latestRun = findLatestModelRun(modelStatus, currentModel);
791
+ if (!latestRun) return;
792
+ }
793
+ }, [core]);
794
+
795
+ useEffect(() => {
796
+ if (!core) {
797
+ console.warn('⚠️ [useEffect] Core is not available yet');
798
+ return;
799
+ }
800
+
801
+ const handleStateChange = (newState) => {
802
+ if (!previousStateRef.current) {
803
+ previousStateRef.current = core.state;
804
+ }
805
+
806
+ const variableChanged = !previousStateRef.current || newState.variable !== previousStateRef.current.variable;
807
+
808
+ if (variableChanged && gridLayerRef.current?.setVariable) {
809
+ gridLayerRef.current.setVariable(newState.variable);
810
+ }
811
+
812
+ const stateKey = `${newState.model}-${newState.variable}-${newState.date}-${newState.run}-${newState.forecastHour}-${newState.units}-${newState.mrmsTimestamp}`;
813
+
814
+ const isOpacityOnlyChange =
815
+ hasInitialLoad.current &&
816
+ newState.opacity !== renderProps.opacity &&
817
+ newState.variable === previousStateRef.current?.variable &&
818
+ newState.forecastHour === previousStateRef.current?.forecastHour &&
819
+ newState.mrmsTimestamp === previousStateRef.current?.mrmsTimestamp &&
820
+ newState.model === previousStateRef.current?.model &&
821
+ newState.units === previousStateRef.current?.units;
822
+
823
+ const isPlayStateOnlyChange =
824
+ hasInitialLoad.current &&
825
+ newState.isPlaying !== previousStateRef.current?.isPlaying &&
826
+ newState.variable === previousStateRef.current?.variable &&
827
+ newState.forecastHour === previousStateRef.current?.forecastHour &&
828
+ newState.mrmsTimestamp === previousStateRef.current?.mrmsTimestamp &&
829
+ newState.model === previousStateRef.current?.model &&
830
+ newState.units === previousStateRef.current?.units &&
831
+ newState.opacity === previousStateRef.current?.opacity;
832
+
833
+ if (!isOpacityOnlyChange && !isPlayStateOnlyChange && lastProcessedState.current === stateKey) {
834
+ previousStateRef.current = newState;
835
+ return;
836
+ }
837
+
838
+ if (!isOpacityOnlyChange && !isPlayStateOnlyChange) {
839
+ lastProcessedState.current = stateKey;
840
+ }
841
+
842
+ if (isOpacityOnlyChange) {
843
+ setRenderProps(prev => ({ ...prev, opacity: newState.opacity }));
844
+ previousStateRef.current = newState;
845
+ return;
846
+ }
847
+
848
+ if (isPlayStateOnlyChange) {
849
+ previousStateRef.current = newState;
850
+ return;
851
+ }
852
+
853
+ const isUnitsOnlyChange =
854
+ hasInitialLoad.current &&
855
+ newState.model === previousStateRef.current.model &&
856
+ newState.isMRMS === previousStateRef.current.isMRMS &&
857
+ newState.variable === previousStateRef.current.variable &&
858
+ newState.date === previousStateRef.current.date &&
859
+ newState.run === previousStateRef.current.run &&
860
+ newState.forecastHour === previousStateRef.current.forecastHour &&
861
+ newState.mrmsTimestamp === previousStateRef.current.mrmsTimestamp &&
862
+ newState.units !== previousStateRef.current.units;
863
+
864
+ if (isUnitsOnlyChange) {
865
+ const { variable, units, isMRMS, mrmsTimestamp, model, date, run, forecastHour } = newState;
866
+ const oldCacheKey = isMRMS
867
+ ? `mrms-${mrmsTimestamp}-${variable}`
868
+ : `${model}-${date}-${run}-${forecastHour}-${variable}`;
869
+
870
+ const cachedData = preloadedDataCache.current.get(oldCacheKey);
871
+
872
+ if (cachedData && cachedData.originalScale !== undefined && cachedData.originalOffset !== undefined) {
873
+ const { baseUnit } = core._getColormapForVariable(variable);
874
+ const toUnit = core._getTargetUnit(baseUnit, units);
875
+ const fieldInfo = DICTIONARIES?.fld?.[variable] || {};
876
+ const serverDataUnit = fieldInfo.defaultUnit || baseUnit;
877
+
878
+ let dataScale = cachedData.originalScale;
879
+ let dataOffset = cachedData.originalOffset;
880
+
881
+ if (serverDataUnit !== baseUnit) {
882
+ const conversionFunc = getUnitConversionFunction(serverDataUnit, baseUnit);
883
+ if (conversionFunc) {
884
+ if (cachedData.scaleType === 'sqrt') {
885
+ const physicalAtOffset = dataOffset * dataOffset;
886
+ const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
887
+ const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
888
+ const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
889
+ const newOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
890
+ const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
891
+ dataScale = newOffsetPlusScale - newOffset;
892
+ dataOffset = newOffset;
893
+ } else {
894
+ const convertedOffset = conversionFunc(dataOffset);
895
+ const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
896
+ dataScale = convertedOffsetPlusScale - convertedOffset;
897
+ dataOffset = convertedOffset;
898
+ }
899
+ }
900
+ }
901
+
902
+ if (baseUnit !== toUnit) {
903
+ const conversionFunc = getUnitConversionFunction(baseUnit, toUnit);
904
+ if (conversionFunc) {
905
+ if (cachedData.scaleType === 'sqrt') {
906
+ const physicalAtOffset = dataOffset * dataOffset;
907
+ const physicalAtOffsetPlusScale = (dataOffset + dataScale) * (dataOffset + dataScale);
908
+ const convertedPhysicalAtOffset = conversionFunc(physicalAtOffset);
909
+ const convertedPhysicalAtOffsetPlusScale = conversionFunc(physicalAtOffsetPlusScale);
910
+ const newOffset = Math.sqrt(Math.abs(convertedPhysicalAtOffset)) * Math.sign(convertedPhysicalAtOffset);
911
+ const newOffsetPlusScale = Math.sqrt(Math.abs(convertedPhysicalAtOffsetPlusScale)) * Math.sign(convertedPhysicalAtOffsetPlusScale);
912
+ dataScale = newOffsetPlusScale - newOffset;
913
+ dataOffset = newOffset;
914
+ } else {
915
+ const convertedOffset = conversionFunc(dataOffset);
916
+ const convertedOffsetPlusScale = conversionFunc(dataOffset + dataScale);
917
+ dataScale = convertedOffsetPlusScale - convertedOffset;
918
+ dataOffset = convertedOffset;
919
+ }
920
+ }
921
+ }
922
+
923
+ const { colormap } = core._getColormapForVariable(variable);
924
+ const finalColormap = core._convertColormapUnits(colormap, baseUnit, toUnit);
925
+ let dataRange = (variable === 'ptypeRefl' || variable === 'ptypeRate') ? [5, 380] : [finalColormap[0], finalColormap[finalColormap.length - 2]];
926
+ const colormapBytes = _generateColormapBytes(finalColormap);
927
+ const colormapAsBase64 = fromByteArray(colormapBytes);
928
+
929
+ gridLayerRef.current.updateColormapTexture(colormapAsBase64);
930
+ cachedColormap.current = { key: `${variable}-${units}` };
931
+ cachedDataRange.current = dataRange;
932
+ setRenderProps(prev => ({ ...prev, dataRange, opacity: newState.opacity }));
933
+
934
+ if (gridLayerRef.current && gridLayerRef.current.updateDataParameters) {
935
+ const scaleTypeValue = cachedData.scaleType === 'sqrt' ? 1 : 0;
936
+ gridLayerRef.current.updateDataParameters(dataScale, dataOffset, cachedData.missing, scaleTypeValue);
937
+ }
938
+
939
+ const newCacheKey = isMRMS ? `mrms-${mrmsTimestamp}-${variable}` : `${model}-${date}-${run}-${forecastHour}-${variable}`;
940
+ preloadedDataCache.current.set(newCacheKey, { ...cachedData, scale: dataScale, offset: dataOffset });
941
+ }
942
+
943
+ previousStateRef.current = newState;
944
+ return;
945
+ }
946
+
947
+ const needsFullLoad =
948
+ !hasInitialLoad.current ||
949
+ newState.model !== previousStateRef.current.model ||
950
+ newState.isMRMS !== previousStateRef.current.isMRMS ||
951
+ newState.variable !== previousStateRef.current.variable ||
952
+ newState.date !== previousStateRef.current.date ||
953
+ newState.run !== previousStateRef.current.run;
954
+
955
+ if (needsFullLoad) {
956
+ if (gridLayerRef.current) {
957
+ gridLayerRef.current.setVariable(newState.variable);
958
+ gridLayerRef.current.clear();
959
+ if (Platform.OS === 'ios' && gridLayerRef.current.clearGpuCache) {
960
+ gridLayerRef.current.clearGpuCache();
961
+ }
962
+ }
963
+ hasPreloadedRef.current = false;
964
+ preloadedDataCache.current.clear();
965
+ cachedGeometry.current = null;
966
+ cachedColormap.current = null;
967
+ currentGridDataRef.current = null;
968
+ WeatherFrameProcessorModule.cancelAllFrames();
969
+
970
+ if (!newState.variable) {
971
+ previousStateRef.current = newState;
972
+ return;
973
+ }
974
+ preloadAllFramesToDisk(newState);
975
+ } else if (newState.forecastHour !== previousStateRef.current.forecastHour || (newState.isMRMS && newState.mrmsTimestamp !== previousStateRef.current.mrmsTimestamp)) {
976
+ const success = updateGPUWithCachedData(newState);
977
+ if (success && newState.opacity !== renderProps.opacity) {
978
+ setRenderProps(prev => ({ ...prev, opacity: newState.opacity }));
979
+ }
980
+ }
981
+
982
+ previousStateRef.current = newState;
983
+ };
984
+
985
+ handleStateChangeRef.current = handleStateChange;
986
+
987
+ const stableHandler = (newState) => {
988
+ // OPTIMIZATION: If playing (high speed), prioritize MAP update and skip debounce
989
+ if (newState.isPlaying) {
990
+ // 1. Update Map FIRST (Native Enqueue)
991
+ if (handleStateChangeRef.current) {
992
+ handleStateChangeRef.current(newState);
993
+ }
994
+
995
+ // 2. Update UI Slider SECOND
996
+ // This ensures the heavy map frame is processing while React reconciles the slider
997
+ props.onStateChange?.(newState);
998
+
999
+ if (debounceTimeoutRef.current) {
1000
+ clearTimeout(debounceTimeoutRef.current);
1001
+ debounceTimeoutRef.current = null;
1002
+ }
1003
+ return;
1004
+ }
1005
+
1006
+ // --- Existing Logic for scrubbing/paused ---
1007
+
1008
+ // 1. Immediate Slider Update for responsiveness
1009
+ props.onStateChange?.(newState);
1010
+
1011
+ if (debounceTimeoutRef.current) {
1012
+ clearTimeout(debounceTimeoutRef.current);
1013
+ }
1014
+
1015
+ // Opacity and Play state changes should be immediate for the native layer too
1016
+ const isOpacityOnlyChange =
1017
+ previousStateRef.current &&
1018
+ newState.opacity !== previousStateRef.current.opacity &&
1019
+ newState.variable === previousStateRef.current.variable &&
1020
+ newState.forecastHour === previousStateRef.current.forecastHour &&
1021
+ newState.mrmsTimestamp === previousStateRef.current.mrmsTimestamp &&
1022
+ newState.model === previousStateRef.current.model &&
1023
+ newState.units === previousStateRef.current.units;
1024
+
1025
+ const isPlayStateOnlyChange =
1026
+ previousStateRef.current &&
1027
+ newState.isPlaying !== previousStateRef.current.isPlaying &&
1028
+ newState.variable === previousStateRef.current.variable &&
1029
+ newState.forecastHour === previousStateRef.current.forecastHour &&
1030
+ newState.mrmsTimestamp === previousStateRef.current.mrmsTimestamp &&
1031
+ newState.model === previousStateRef.current.model &&
1032
+ newState.units === previousStateRef.current.units;
1033
+
1034
+ if (isOpacityOnlyChange || isPlayStateOnlyChange || !previousStateRef.current) {
1035
+ if (handleStateChangeRef.current) {
1036
+ handleStateChangeRef.current(newState);
1037
+ }
1038
+ return;
1039
+ }
1040
+
1041
+ debounceTimeoutRef.current = setTimeout(() => {
1042
+ if (handleStateChangeRef.current) {
1043
+ handleStateChangeRef.current(newState);
1044
+ }
1045
+ debounceTimeoutRef.current = null;
1046
+ }, 16); // ~60fps map updates
1047
+ };
1048
+
1049
+ core.on('state:change', stableHandler);
1050
+
1051
+ return () => {
1052
+ core.off('state:change', stableHandler);
1053
+ if (debounceTimeoutRef.current) {
1054
+ clearTimeout(debounceTimeoutRef.current);
1055
+ }
1056
+ };
1057
+ }, [core]);
1058
+
1059
+ useEffect(() => {
1060
+ return () => {
1061
+ preloadedDataCache.current.clear(); // This drops JS references
1062
+ hasInitialLoad.current = false;
1063
+ lastProcessedState.current = null;
1064
+ // Native cleanup
1065
+ if (gridLayerRef.current && Platform.OS === 'ios') {
1066
+ gridLayerRef.current.clearGpuCache();
1067
+ }
1068
+ };
1069
+ }, []);
1070
+
1071
+ const lastInspectorUpdateRef = useRef(0);
1072
+ const INSPECTOR_THROTTLE_MS = 50;
1073
+
1074
+ useEffect(() => {
1075
+ if (!core || !inspectorEnabled) {
1076
+ return;
1077
+ }
1078
+
1079
+ const handleMapMove = async (center) => {
1080
+ if (!center || !Array.isArray(center) || center.length !== 2) {
1081
+ return;
1082
+ }
1083
+
1084
+ // Throttle updates
1085
+ const now = Date.now();
1086
+ if (now - lastInspectorUpdateRef.current < INSPECTOR_THROTTLE_MS) {
1087
+ return;
1088
+ }
1089
+ lastInspectorUpdateRef.current = now;
1090
+
1091
+ const [longitude, latitude] = center;
1092
+
1093
+ const payload = await getValueAtPoint(longitude, latitude);
1094
+ onInspect?.(payload);
1095
+ };
1096
+
1097
+ core.on('map:move', handleMapMove);
1098
+
1099
+ if (context && context.getCenter) {
1100
+ const center = context.getCenter();
1101
+ if (center) {
1102
+ handleMapMove(center);
1103
+ }
1104
+ }
1105
+
1106
+ return () => {
1107
+ core.off('map:move', handleMapMove);
1108
+ };
1109
+ }, [inspectorEnabled, onInspect, core, context]);
1110
+
1111
+ useEffect(() => {
1112
+ if (!core || !inspectorEnabled) {
1113
+ return;
1114
+ }
1115
+
1116
+ const triggerReinspection = () => {
1117
+ const mapRef = mapRegistry.getMap();
1118
+ const center = mapRef?._currentCenter;
1119
+
1120
+ if (center && Array.isArray(center) && center.length === 2) {
1121
+ const [longitude, latitude] = center;
1122
+
1123
+ getValueAtPoint(longitude, latitude).then(payload => {
1124
+ onInspect?.(payload);
1125
+ });
1126
+ }
1127
+ };
1128
+
1129
+ // Small delay to ensure data is loaded before re-inspecting
1130
+ const timer = setTimeout(triggerReinspection, 100);
1131
+
1132
+ return () => clearTimeout(timer);
1133
+ }, [
1134
+ core?.state?.variable,
1135
+ core?.state?.model,
1136
+ core?.state?.forecastHour,
1137
+ core?.state?.mrmsTimestamp,
1138
+ core?.state?.units,
1139
+ inspectorEnabled,
1140
+ onInspect
1141
+ ]);
1142
+
1143
+ useEffect(() => {
1144
+ if (!core) {
1145
+ return;
1146
+ }
1147
+
1148
+ const handleCameraChange = (center) => {
1149
+ if (core && center) {
1150
+ core.setMapCenter(center);
1151
+ }
1152
+ };
1153
+
1154
+ // Register with the global registry
1155
+ mapRegistry.addCameraListener(handleCameraChange);
1156
+
1157
+ // Try to get initial center
1158
+ const mapRef = mapRegistry.getMap();
1159
+ if (mapRef?._currentCenter) {
1160
+ handleCameraChange(mapRef._currentCenter);
1161
+ }
1162
+
1163
+ return () => {
1164
+ mapRegistry.removeCameraListener(handleCameraChange);
1165
+ };
1166
+ }, [core]);
1167
+
1168
+ useEffect(() => {
1169
+ core.initialize();
1170
+ return () => {
1171
+ core.destroy();
1172
+ };
1173
+ }, [core]);
1174
+
1175
+ return (
1176
+ <GridRenderLayer
1177
+ ref={gridLayerRef}
1178
+ opacity={renderProps.opacity}
1179
+ dataRange={renderProps.dataRange}
1180
+ belowID="AML_-_terrain"
1181
+ />
1182
+ );
1183
+ });
1184
+
1185
+ WeatherLayerManager.getAvailableVariables = (options) => {
1186
+ if (!options || !options.apiKey) {
1187
+ console.error("API key must be provided to get available variables.");
1188
+ return [];
1189
+ }
1190
+ const core = new AguaceroCore({ apiKey: options.apiKey });
1191
+ return core.getAvailableVariables('mrms');
1138
1192
  };