@aguacerowx/react-native 0.0.37 → 0.0.39

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