pythonnative 0.40.0__cp313-cp313-win_amd64.whl

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 (418) hide show
  1. pythonnative/__init__.py +411 -0
  2. pythonnative/_ios_log.py +92 -0
  3. pythonnative/_yoga.cp313-win_amd64.pyd +0 -0
  4. pythonnative/alerts.py +236 -0
  5. pythonnative/animated.py +1687 -0
  6. pythonnative/animation_graph.py +78 -0
  7. pythonnative/appearance.py +124 -0
  8. pythonnative/bootstrap.py +100 -0
  9. pythonnative/bridge/__init__.py +302 -0
  10. pythonnative/bridge/android.py +78 -0
  11. pythonnative/bridge/codec.py +170 -0
  12. pythonnative/bridge/commits.py +114 -0
  13. pythonnative/bridge/fake.py +243 -0
  14. pythonnative/bridge/ios.py +138 -0
  15. pythonnative/bridge/web.py +489 -0
  16. pythonnative/cli/__init__.py +7 -0
  17. pythonnative/cli/pn.py +1214 -0
  18. pythonnative/component.py +271 -0
  19. pythonnative/components/__init__.py +111 -0
  20. pythonnative/components/_base.py +166 -0
  21. pythonnative/components/controls.py +521 -0
  22. pythonnative/components/layout.py +518 -0
  23. pythonnative/components/lists.py +785 -0
  24. pythonnative/components/media.py +204 -0
  25. pythonnative/components/overlays.py +107 -0
  26. pythonnative/components/pressable.py +252 -0
  27. pythonnative/components/structural.py +167 -0
  28. pythonnative/components/text.py +291 -0
  29. pythonnative/devclient.py +824 -0
  30. pythonnative/devserver/__init__.py +34 -0
  31. pythonnative/devserver/server.py +718 -0
  32. pythonnative/devserver/static/animation_graph.js +82 -0
  33. pythonnative/devserver/static/bridge.js +147 -0
  34. pythonnative/devserver/static/colors.js +70 -0
  35. pythonnative/devserver/static/host.js +552 -0
  36. pythonnative/devserver/static/index.html +60 -0
  37. pythonnative/devserver/static/layout.js +85 -0
  38. pythonnative/devserver/static/preview.css +415 -0
  39. pythonnative/devserver/static/renderer.js +1994 -0
  40. pythonnative/devserver/static/shell.js +345 -0
  41. pythonnative/devserver/static/yoga/LICENSE +21 -0
  42. pythonnative/devserver/static/yoga/binaries/yoga-wasm-base64-esm.js +75 -0
  43. pythonnative/devserver/static/yoga/src/generated/YGEnums.d.ts +189 -0
  44. pythonnative/devserver/static/yoga/src/generated/YGEnums.js +211 -0
  45. pythonnative/devserver/static/yoga/src/generated/YGEnums.js.map +1 -0
  46. pythonnative/devserver/static/yoga/src/index.d.ts +12 -0
  47. pythonnative/devserver/static/yoga/src/index.js +16 -0
  48. pythonnative/devserver/static/yoga/src/index.js.map +1 -0
  49. pythonnative/devserver/static/yoga/src/load.d.ts +11 -0
  50. pythonnative/devserver/static/yoga/src/load.js +17 -0
  51. pythonnative/devserver/static/yoga/src/load.js.map +1 -0
  52. pythonnative/devserver/static/yoga/src/wrapAssembly.d.ts +155 -0
  53. pythonnative/devserver/static/yoga/src/wrapAssembly.js +125 -0
  54. pythonnative/devserver/static/yoga/src/wrapAssembly.js.map +1 -0
  55. pythonnative/devserver/watcher.py +267 -0
  56. pythonnative/devserver/ws.py +421 -0
  57. pythonnative/diagnostics.py +241 -0
  58. pythonnative/element.py +159 -0
  59. pythonnative/equality.py +19 -0
  60. pythonnative/events.py +231 -0
  61. pythonnative/gestures.py +1333 -0
  62. pythonnative/hooks.py +1621 -0
  63. pythonnative/hosts/__init__.py +63 -0
  64. pythonnative/hosts/base.py +596 -0
  65. pythonnative/hosts/native.py +302 -0
  66. pythonnative/hot_reload.py +585 -0
  67. pythonnative/layout.py +328 -0
  68. pythonnative/mutations.py +142 -0
  69. pythonnative/native/android/build.gradle +52 -0
  70. pythonnative/native/android/gradle.properties +3 -0
  71. pythonnative/native/android/settings.gradle +12 -0
  72. pythonnative/native/android/src/main/AndroidManifest.xml +11 -0
  73. pythonnative/native/android/src/main/cpp/CMakeLists.txt +9 -0
  74. pythonnative/native/android/src/main/cpp/yoga_jni.cpp +52 -0
  75. pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeModules.kt +5 -0
  76. pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeProps.kt +3705 -0
  77. pythonnative/native/android/src/main/java/com/pythonnative/generated/PNContracts.kt +129 -0
  78. pythonnative/native/android/src/main/java/com/pythonnative/runtime/PNBridge.kt +261 -0
  79. pythonnative/native/android/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
  80. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationGraph.kt +108 -0
  81. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
  82. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +257 -0
  83. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/CommitState.kt +106 -0
  84. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
  85. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +40 -0
  86. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
  87. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
  88. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
  89. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +117 -0
  90. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
  91. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +37 -0
  92. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +32 -0
  93. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
  94. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
  95. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
  96. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
  97. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
  98. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +162 -0
  99. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
  100. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
  101. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +86 -0
  102. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
  103. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
  104. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScreenStackManager.kt +110 -0
  105. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
  106. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
  107. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
  108. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
  109. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +250 -0
  110. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
  111. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
  112. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +159 -0
  113. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
  114. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
  115. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
  116. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
  117. pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/NativeLayout.kt +145 -0
  118. pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/YogaNode.kt +29 -0
  119. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
  120. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
  121. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +61 -0
  122. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
  123. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +158 -0
  124. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
  125. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +99 -0
  126. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
  127. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
  128. pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
  129. pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +188 -0
  130. pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
  131. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt +48 -0
  132. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNBorderDrawable.kt +76 -0
  133. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
  134. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNFrameLayout.kt +49 -0
  135. pythonnative/native/android/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
  136. pythonnative/native/android/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
  137. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
  138. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
  139. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PromiseTest.kt +89 -0
  140. pythonnative/native/ios/Package.swift +23 -0
  141. pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimationGraph.swift +199 -0
  142. pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimator.swift +312 -0
  143. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNBridge.swift +255 -0
  144. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNCommit.swift +104 -0
  145. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNRegistry.swift +142 -0
  146. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNTransaction.swift +166 -0
  147. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
  148. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNButtonManagers.swift +207 -0
  149. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
  150. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
  151. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
  152. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
  153. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNImageManager.swift +222 -0
  154. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
  155. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
  156. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScreenStackManager.swift +107 -0
  157. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
  158. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
  159. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextInputManager.swift +297 -0
  160. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
  161. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
  162. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
  163. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
  164. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
  165. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +155 -0
  166. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
  167. pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeModules.swift +1 -0
  168. pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeProps.swift +3775 -0
  169. pythonnative/native/ios/Sources/PythonNativeKit/Generated/PNContracts.swift +46 -0
  170. pythonnative/native/ios/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
  171. pythonnative/native/ios/Sources/PythonNativeKit/Layout/PNLayout.swift +173 -0
  172. pythonnative/native/ios/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
  173. pythonnative/native/ios/Sources/PythonNativeKit/Modules/HostModule.swift +80 -0
  174. pythonnative/native/ios/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
  175. pythonnative/native/ios/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
  176. pythonnative/native/ios/Sources/PythonNativeKit/Modules/PNNativeModule.swift +168 -0
  177. pythonnative/native/ios/Sources/PythonNativeKit/Modules/PermissionModules.swift +266 -0
  178. pythonnative/native/ios/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
  179. pythonnative/native/ios/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
  180. pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
  181. pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNViewController.swift +237 -0
  182. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
  183. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
  184. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
  185. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
  186. pythonnative/native/ios/Tests/PythonNativeKitTests/PNAnimationGraphTests.swift +26 -0
  187. pythonnative/native/ios/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
  188. pythonnative/native/ios/Tests/PythonNativeKitTests/PNCommitTests.swift +86 -0
  189. pythonnative/native/ios/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
  190. pythonnative/native/ios/Tests/PythonNativeKitTests/PNManagerTests.swift +126 -0
  191. pythonnative/native/ios/Tests/PythonNativeKitTests/PNModuleTests.swift +111 -0
  192. pythonnative/native/ios/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
  193. pythonnative/native/yoga/LICENSE +21 -0
  194. pythonnative/native/yoga/Package.swift +9 -0
  195. pythonnative/native/yoga/VENDORED.md +2 -0
  196. pythonnative/native/yoga/include/PNStyle.h +10 -0
  197. pythonnative/native/yoga/include/module.modulemap +5 -0
  198. pythonnative/native/yoga/include/yoga/YGConfig.h +158 -0
  199. pythonnative/native/yoga/include/yoga/YGEnums.h +142 -0
  200. pythonnative/native/yoga/include/yoga/YGMacros.h +99 -0
  201. pythonnative/native/yoga/include/yoga/YGNode.h +304 -0
  202. pythonnative/native/yoga/include/yoga/YGNodeLayout.h +35 -0
  203. pythonnative/native/yoga/include/yoga/YGNodeStyle.h +130 -0
  204. pythonnative/native/yoga/include/yoga/YGPixelGrid.h +29 -0
  205. pythonnative/native/yoga/include/yoga/YGValue.h +84 -0
  206. pythonnative/native/yoga/include/yoga/Yoga.h +21 -0
  207. pythonnative/native/yoga/python.cpp +16 -0
  208. pythonnative/native/yoga/style.cpp +272 -0
  209. pythonnative/native/yoga/yoga/CMakeLists.txt +41 -0
  210. pythonnative/native/yoga/yoga/YGConfig.cpp +92 -0
  211. pythonnative/native/yoga/yoga/YGConfig.h +158 -0
  212. pythonnative/native/yoga/yoga/YGEnums.cpp +262 -0
  213. pythonnative/native/yoga/yoga/YGEnums.h +142 -0
  214. pythonnative/native/yoga/yoga/YGMacros.h +99 -0
  215. pythonnative/native/yoga/yoga/YGNode.cpp +366 -0
  216. pythonnative/native/yoga/yoga/YGNode.h +304 -0
  217. pythonnative/native/yoga/yoga/YGNodeLayout.cpp +92 -0
  218. pythonnative/native/yoga/yoga/YGNodeLayout.h +35 -0
  219. pythonnative/native/yoga/yoga/YGNodeStyle.cpp +405 -0
  220. pythonnative/native/yoga/yoga/YGNodeStyle.h +130 -0
  221. pythonnative/native/yoga/yoga/YGPixelGrid.cpp +22 -0
  222. pythonnative/native/yoga/yoga/YGPixelGrid.h +29 -0
  223. pythonnative/native/yoga/yoga/YGValue.cpp +20 -0
  224. pythonnative/native/yoga/yoga/YGValue.h +84 -0
  225. pythonnative/native/yoga/yoga/Yoga.h +21 -0
  226. pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.cpp +563 -0
  227. pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.h +41 -0
  228. pythonnative/native/yoga/yoga/algorithm/Align.h +72 -0
  229. pythonnative/native/yoga/yoga/algorithm/Baseline.cpp +78 -0
  230. pythonnative/native/yoga/yoga/algorithm/Baseline.h +21 -0
  231. pythonnative/native/yoga/yoga/algorithm/BoundAxis.h +79 -0
  232. pythonnative/native/yoga/yoga/algorithm/Cache.cpp +121 -0
  233. pythonnative/native/yoga/yoga/algorithm/Cache.h +30 -0
  234. pythonnative/native/yoga/yoga/algorithm/CalculateLayout.cpp +2428 -0
  235. pythonnative/native/yoga/yoga/algorithm/CalculateLayout.h +38 -0
  236. pythonnative/native/yoga/yoga/algorithm/FlexDirection.h +120 -0
  237. pythonnative/native/yoga/yoga/algorithm/FlexLine.cpp +124 -0
  238. pythonnative/native/yoga/yoga/algorithm/FlexLine.h +75 -0
  239. pythonnative/native/yoga/yoga/algorithm/PixelGrid.cpp +132 -0
  240. pythonnative/native/yoga/yoga/algorithm/PixelGrid.h +29 -0
  241. pythonnative/native/yoga/yoga/algorithm/SizingMode.h +73 -0
  242. pythonnative/native/yoga/yoga/algorithm/TrailingPosition.h +44 -0
  243. pythonnative/native/yoga/yoga/config/Config.cpp +135 -0
  244. pythonnative/native/yoga/yoga/config/Config.h +92 -0
  245. pythonnative/native/yoga/yoga/debug/AssertFatal.cpp +53 -0
  246. pythonnative/native/yoga/yoga/debug/AssertFatal.h +29 -0
  247. pythonnative/native/yoga/yoga/debug/Log.cpp +107 -0
  248. pythonnative/native/yoga/yoga/debug/Log.h +34 -0
  249. pythonnative/native/yoga/yoga/enums/Align.h +47 -0
  250. pythonnative/native/yoga/yoga/enums/BoxSizing.h +40 -0
  251. pythonnative/native/yoga/yoga/enums/Dimension.h +40 -0
  252. pythonnative/native/yoga/yoga/enums/Direction.h +41 -0
  253. pythonnative/native/yoga/yoga/enums/Display.h +41 -0
  254. pythonnative/native/yoga/yoga/enums/Edge.h +47 -0
  255. pythonnative/native/yoga/yoga/enums/Errata.h +41 -0
  256. pythonnative/native/yoga/yoga/enums/ExperimentalFeature.h +39 -0
  257. pythonnative/native/yoga/yoga/enums/FlexDirection.h +42 -0
  258. pythonnative/native/yoga/yoga/enums/Gutter.h +41 -0
  259. pythonnative/native/yoga/yoga/enums/Justify.h +44 -0
  260. pythonnative/native/yoga/yoga/enums/LogLevel.h +44 -0
  261. pythonnative/native/yoga/yoga/enums/MeasureMode.h +41 -0
  262. pythonnative/native/yoga/yoga/enums/NodeType.h +40 -0
  263. pythonnative/native/yoga/yoga/enums/Overflow.h +41 -0
  264. pythonnative/native/yoga/yoga/enums/PhysicalEdge.h +21 -0
  265. pythonnative/native/yoga/yoga/enums/PositionType.h +41 -0
  266. pythonnative/native/yoga/yoga/enums/Unit.h +42 -0
  267. pythonnative/native/yoga/yoga/enums/Wrap.h +41 -0
  268. pythonnative/native/yoga/yoga/enums/YogaEnums.h +85 -0
  269. pythonnative/native/yoga/yoga/event/event.cpp +87 -0
  270. pythonnative/native/yoga/yoga/event/event.h +130 -0
  271. pythonnative/native/yoga/yoga/module.modulemap +21 -0
  272. pythonnative/native/yoga/yoga/node/CachedMeasurement.h +53 -0
  273. pythonnative/native/yoga/yoga/node/LayoutResults.cpp +48 -0
  274. pythonnative/native/yoga/yoga/node/LayoutResults.h +122 -0
  275. pythonnative/native/yoga/yoga/node/LayoutableChildren.h +148 -0
  276. pythonnative/native/yoga/yoga/node/Node.cpp +443 -0
  277. pythonnative/native/yoga/yoga/node/Node.h +337 -0
  278. pythonnative/native/yoga/yoga/numeric/Comparison.h +81 -0
  279. pythonnative/native/yoga/yoga/numeric/FloatOptional.h +93 -0
  280. pythonnative/native/yoga/yoga/style/SmallValueBuffer.h +133 -0
  281. pythonnative/native/yoga/yoga/style/Style.h +757 -0
  282. pythonnative/native/yoga/yoga/style/StyleLength.h +107 -0
  283. pythonnative/native/yoga/yoga/style/StyleValueHandle.h +98 -0
  284. pythonnative/native/yoga/yoga/style/StyleValuePool.h +127 -0
  285. pythonnative/native_modules/__init__.py +124 -0
  286. pythonnative/native_modules/app_state.py +99 -0
  287. pythonnative/native_modules/battery.py +75 -0
  288. pythonnative/native_modules/biometrics.py +42 -0
  289. pythonnative/native_modules/camera.py +65 -0
  290. pythonnative/native_modules/clipboard.py +46 -0
  291. pythonnative/native_modules/fallback.py +324 -0
  292. pythonnative/native_modules/file_system.py +145 -0
  293. pythonnative/native_modules/haptics.py +75 -0
  294. pythonnative/native_modules/linking.py +123 -0
  295. pythonnative/native_modules/location.py +75 -0
  296. pythonnative/native_modules/net_info.py +112 -0
  297. pythonnative/native_modules/notifications.py +129 -0
  298. pythonnative/native_modules/permissions.py +108 -0
  299. pythonnative/native_modules/registry.py +526 -0
  300. pythonnative/native_modules/secure_store.py +52 -0
  301. pythonnative/native_modules/share.py +51 -0
  302. pythonnative/native_views/__init__.py +375 -0
  303. pythonnative/native_views/base.py +316 -0
  304. pythonnative/native_views/bridge_backend.py +277 -0
  305. pythonnative/navigation/__init__.py +103 -0
  306. pythonnative/navigation/container.py +154 -0
  307. pythonnative/navigation/handle.py +540 -0
  308. pythonnative/navigation/hooks.py +133 -0
  309. pythonnative/navigation/host.py +58 -0
  310. pythonnative/navigation/linking.py +200 -0
  311. pythonnative/navigation/navigators.py +659 -0
  312. pythonnative/navigation/screen.py +149 -0
  313. pythonnative/navigation/state.py +269 -0
  314. pythonnative/net.py +248 -0
  315. pythonnative/platform.py +166 -0
  316. pythonnative/platform_metrics.py +252 -0
  317. pythonnative/preview.py +287 -0
  318. pythonnative/profiling.py +101 -0
  319. pythonnative/project/__init__.py +68 -0
  320. pythonnative/project/android.py +557 -0
  321. pythonnative/project/builder.py +817 -0
  322. pythonnative/project/config.py +773 -0
  323. pythonnative/project/deps.py +719 -0
  324. pythonnative/project/devices.py +304 -0
  325. pythonnative/project/doctor.py +283 -0
  326. pythonnative/project/fingerprint.py +171 -0
  327. pythonnative/project/icons.py +247 -0
  328. pythonnative/project/ios.py +325 -0
  329. pythonnative/project/lockfile.py +100 -0
  330. pythonnative/project/permissions.py +361 -0
  331. pythonnative/project/plugins.py +519 -0
  332. pythonnative/project/runtime_assets.py +183 -0
  333. pythonnative/py.typed +0 -0
  334. pythonnative/query.py +153 -0
  335. pythonnative/reconciler/__init__.py +29 -0
  336. pythonnative/reconciler/boundaries.py +375 -0
  337. pythonnative/reconciler/children.py +88 -0
  338. pythonnative/reconciler/core.py +1165 -0
  339. pythonnative/reconciler/layout_pass.py +393 -0
  340. pythonnative/reconciler/vnode.py +266 -0
  341. pythonnative/refresh.py +55 -0
  342. pythonnative/runtime.py +306 -0
  343. pythonnative/scheduler.py +159 -0
  344. pythonnative/sdk/__init__.py +153 -0
  345. pythonnative/sdk/_components.py +427 -0
  346. pythonnative/sdk/builtins.py +91 -0
  347. pythonnative/sdk/codegen.py +149 -0
  348. pythonnative/sdk/module_codegen.py +184 -0
  349. pythonnative/sdk/schema.py +224 -0
  350. pythonnative/sdk/templates/contracts.kt +46 -0
  351. pythonnative/sdk/templates/contracts.swift +46 -0
  352. pythonnative/storage.py +184 -0
  353. pythonnative/style.py +841 -0
  354. pythonnative/suspense.py +183 -0
  355. pythonnative/templates/android_template/app/build.gradle +75 -0
  356. pythonnative/templates/android_template/app/proguard-rules.pro +21 -0
  357. pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +24 -0
  358. pythonnative/templates/android_template/app/src/debug/AndroidManifest.xml +7 -0
  359. pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +32 -0
  360. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +130 -0
  361. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -0
  362. pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
  363. pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
  364. pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +10 -0
  365. pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
  366. pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
  367. pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  368. pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  369. pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  370. pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  371. pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  372. pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  373. pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  374. pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  375. pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  376. pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  377. pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +22 -0
  378. pythonnative/templates/android_template/app/src/main/res/values/colors.xml +5 -0
  379. pythonnative/templates/android_template/app/src/main/res/values/strings.xml +5 -0
  380. pythonnative/templates/android_template/app/src/main/res/values/themes.xml +9 -0
  381. pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +7 -0
  382. pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +13 -0
  383. pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
  384. pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +17 -0
  385. pythonnative/templates/android_template/build.gradle +10 -0
  386. pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
  387. pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +6 -0
  388. pythonnative/templates/android_template/gradle.properties +23 -0
  389. pythonnative/templates/android_template/gradlew +185 -0
  390. pythonnative/templates/android_template/gradlew.bat +89 -0
  391. pythonnative/templates/android_template/settings.gradle +17 -0
  392. pythonnative/templates/ios_template/ios_template/AppDelegate.swift +51 -0
  393. pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  394. pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
  395. pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +6 -0
  396. pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +25 -0
  397. pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
  398. pythonnative/templates/ios_template/ios_template/Info.plist +28 -0
  399. pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +390 -0
  400. pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +61 -0
  401. pythonnative/templates/ios_template/ios_template/ViewController.swift +23 -0
  402. pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +745 -0
  403. pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  404. pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +36 -0
  405. pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +41 -0
  406. pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +32 -0
  407. pythonnative/testing/__init__.py +53 -0
  408. pythonnative/testing/backend.py +276 -0
  409. pythonnative/testing/harness.py +369 -0
  410. pythonnative/utils.py +145 -0
  411. pythonnative-0.40.0.dist-info/DELVEWHEEL +2 -0
  412. pythonnative-0.40.0.dist-info/METADATA +150 -0
  413. pythonnative-0.40.0.dist-info/RECORD +418 -0
  414. pythonnative-0.40.0.dist-info/WHEEL +5 -0
  415. pythonnative-0.40.0.dist-info/entry_points.txt +2 -0
  416. pythonnative-0.40.0.dist-info/licenses/LICENSE +21 -0
  417. pythonnative-0.40.0.dist-info/top_level.txt +1 -0
  418. pythonnative.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
@@ -0,0 +1,257 @@
1
+ package com.pythonnative.runtime.animation
2
+
3
+ import android.animation.Animator
4
+ import android.animation.AnimatorListenerAdapter
5
+ import android.animation.ArgbEvaluator
6
+ import android.animation.TimeInterpolator
7
+ import android.animation.ValueAnimator
8
+ import android.view.View
9
+ import android.view.animation.PathInterpolator
10
+ import android.widget.TextView
11
+ import androidx.dynamicanimation.animation.DynamicAnimation
12
+ import androidx.dynamicanimation.animation.FlingAnimation
13
+ import androidx.dynamicanimation.animation.FloatPropertyCompat
14
+ import androidx.dynamicanimation.animation.SpringAnimation
15
+ import androidx.dynamicanimation.animation.SpringForce
16
+ import com.pythonnative.runtime.PNBridge
17
+ import com.pythonnative.runtime.bridge.JsonUtil
18
+ import com.pythonnative.runtime.bridge.PNLog
19
+ import com.pythonnative.runtime.bridge.ViewRecord
20
+ import com.pythonnative.runtime.components.PNColor
21
+ import com.pythonnative.runtime.components.ViewStyler
22
+ import org.json.JSONObject
23
+
24
+ /**
25
+ * Native driver for `animate` requests on the animatable props
26
+ * (`opacity`, `background_color`, `translate_x`, `translate_y`,
27
+ * `scale`, `scale_x`, `scale_y`, `rotate`, plus `color` for text).
28
+ *
29
+ * `timing` runs on a `ValueAnimator`, `spring` on a `SpringAnimation`,
30
+ * and `decay` on a `FlingAnimation`. Completion is reported with
31
+ * `callback("animation", 0, "", {"id": n, "finished": bool})`.
32
+ */
33
+ object PNAnimator {
34
+ private class Running(val view: View, val prop: String, val cancel: () -> Unit)
35
+
36
+ private val running = HashMap<Long, Running>()
37
+
38
+ /** Handle one request object; returns the JSON reply string per the spec. */
39
+ fun handle(record: ViewRecord, request: JSONObject): String? {
40
+ val view = record.view
41
+ return when (request.optString("op")) {
42
+ "graph" -> { AnimationGraph.install(request.getJSONObject("graph")); null }
43
+ "set" -> {
44
+ record.manager.setAnimatedProperty(view, request.optString("prop"), request.opt("value"))
45
+ null
46
+ }
47
+ "start" -> {
48
+ val id = request.optLong("id")
49
+ val spec = request.optJSONObject("spec") ?: JSONObject()
50
+ val ok = record.manager.startAnimation(view, id, request.optString("prop"), spec)
51
+ JSONObject().put("ok", ok).toString()
52
+ }
53
+ "cancel" -> {
54
+ val value = record.manager.cancelAnimation(view, request.optLong("id"))
55
+ if (value == null) null else JSONObject().put("value", JsonUtil.wrap(value)).toString()
56
+ }
57
+ else -> null
58
+ }
59
+ }
60
+
61
+ // ------------------------------------------------------------------
62
+ // Property access
63
+ // ------------------------------------------------------------------
64
+
65
+ /** Apply one animation frame to `view`. Unknown props are ignored. */
66
+ fun setProperty(view: View, prop: String, value: Any?) {
67
+ if (JsonUtil.isNull(value)) return
68
+ if (prop.startsWith("_pn_graph:")) {
69
+ AnimationGraph.set(prop.substringAfter(":").toLong(), JsonUtil.toDouble(value))
70
+ return
71
+ }
72
+ try {
73
+ when (prop) {
74
+ "opacity" -> view.alpha = JsonUtil.toDouble(value).toFloat()
75
+ "translate_x" -> view.translationX = px(JsonUtil.toDouble(value))
76
+ "translate_y" -> view.translationY = px(JsonUtil.toDouble(value))
77
+ "scale" -> {
78
+ val s = JsonUtil.toDouble(value).toFloat()
79
+ view.scaleX = s
80
+ view.scaleY = s
81
+ }
82
+ "scale_x" -> view.scaleX = JsonUtil.toDouble(value).toFloat()
83
+ "scale_y" -> view.scaleY = JsonUtil.toDouble(value).toFloat()
84
+ "rotate" -> view.rotation = ViewStyler.angleDegrees(value)
85
+ "background_color" -> ViewStyler.setAnimatedBackground(view, value)
86
+ "color" -> (view as? TextView)?.setTextColor(PNColor.parseOr(value, 0xFF000000.toInt()))
87
+ }
88
+ } catch (e: Exception) {
89
+ PNLog.swallowed("PNAnimator.setProperty", e)
90
+ }
91
+ }
92
+
93
+ /** Read the current (presentation) value of an animatable prop, or `null`. */
94
+ fun readProperty(view: View, prop: String): Any? = if (prop.startsWith("_pn_graph:")) AnimationGraph.value(prop.substringAfter(":").toLong()) else when (prop) {
95
+ "opacity" -> view.alpha.toDouble()
96
+ "translate_x" -> view.translationX / PNBridge.density().toDouble()
97
+ "translate_y" -> view.translationY / PNBridge.density().toDouble()
98
+ "scale", "scale_x" -> view.scaleX.toDouble()
99
+ "scale_y" -> view.scaleY.toDouble()
100
+ "rotate" -> view.rotation.toDouble()
101
+ else -> null
102
+ }
103
+
104
+ // ------------------------------------------------------------------
105
+ // Start / cancel
106
+ // ------------------------------------------------------------------
107
+
108
+ /** Start a native animation; `false` means Python should tick it instead. */
109
+ fun start(view: View, id: Long, prop: String, spec: JSONObject): Boolean {
110
+ cancelQuietly(id)
111
+ return try {
112
+ when (AnimationSpecs.kind(spec)) {
113
+ "timing" -> startTiming(view, id, prop, spec)
114
+ "spring" -> startSpring(view, id, prop, spec)
115
+ "decay" -> startDecay(view, id, prop, spec)
116
+ else -> false
117
+ }
118
+ } catch (e: Exception) {
119
+ PNLog.rateLimited("anim-start", "native animation failed for '$prop'", e)
120
+ running.remove(id)
121
+ false
122
+ }
123
+ }
124
+
125
+ /** Cancel `id` and return the presentation value of its prop, if readable. */
126
+ fun cancel(id: Long): Any? {
127
+ val entry = running.remove(id) ?: return null
128
+ try {
129
+ entry.cancel()
130
+ } catch (e: Exception) {
131
+ PNLog.swallowed("PNAnimator.cancel", e)
132
+ }
133
+ return readProperty(entry.view, entry.prop)
134
+ }
135
+
136
+ private fun cancelQuietly(id: Long) {
137
+ running.remove(id)?.let { runCatching { it.cancel() } }
138
+ }
139
+
140
+ private fun complete(id: Long, finished: Boolean) {
141
+ if (running.remove(id) == null) return
142
+ PNBridge.callPython("animation", 0, "", JSONObject().put("id", id).put("finished", finished).toString())
143
+ }
144
+
145
+ private fun startTiming(view: View, id: Long, prop: String, spec: JSONObject): Boolean {
146
+ val timing = AnimationSpecs.timing(spec)
147
+ val animator: ValueAnimator
148
+ if (prop == "background_color") {
149
+ val from = PNColor.parse(spec.opt("from")) ?: return false
150
+ val to = PNColor.parse(spec.opt("to")) ?: return false
151
+ animator = ValueAnimator.ofObject(ArgbEvaluator(), from, to)
152
+ animator.addUpdateListener { ViewStyler.setAnimatedBackground(view, it.animatedValue as Int) }
153
+ } else if (prop == "color") {
154
+ val from = PNColor.parse(spec.opt("from")) ?: return false
155
+ val to = PNColor.parse(spec.opt("to")) ?: return false
156
+ animator = ValueAnimator.ofObject(ArgbEvaluator(), from, to)
157
+ animator.addUpdateListener { (view as? TextView)?.setTextColor(it.animatedValue as Int) }
158
+ } else {
159
+ if (!isFloatProp(prop)) return false
160
+ animator = ValueAnimator.ofFloat(timing.from.toFloat(), timing.to.toFloat())
161
+ animator.addUpdateListener { setProperty(view, prop, it.animatedValue as Float) }
162
+ }
163
+ animator.duration = timing.durationMs
164
+ animator.interpolator = interpolator(timing.easing)
165
+ var cancelled = false
166
+ animator.addListener(object : AnimatorListenerAdapter() {
167
+ override fun onAnimationCancel(animation: Animator) {
168
+ cancelled = true
169
+ }
170
+
171
+ override fun onAnimationEnd(animation: Animator) {
172
+ complete(id, !cancelled)
173
+ }
174
+ })
175
+ running[id] = Running(view, prop) { animator.cancel() }
176
+ animator.start()
177
+ return true
178
+ }
179
+
180
+ private fun startSpring(view: View, id: Long, prop: String, spec: JSONObject): Boolean {
181
+ val params = AnimationSpecs.spring(spec)
182
+ val property = floatProperty(prop) ?: return false
183
+ val scale = unitScale(prop)
184
+ val anim = SpringAnimation(view, property, (params.to * scale).toFloat())
185
+ anim.spring = SpringForce((params.to * scale).toFloat())
186
+ .setStiffness(params.stiffness.toFloat())
187
+ .setDampingRatio(params.dampingRatio.toFloat())
188
+ anim.setStartValue((params.from * scale).toFloat())
189
+ anim.setStartVelocity((params.initialVelocity * scale).toFloat())
190
+ anim.addEndListener { _, canceled, _, _ -> complete(id, !canceled) }
191
+ running[id] = Running(view, prop) { anim.cancel() }
192
+ anim.start()
193
+ return true
194
+ }
195
+
196
+ private fun startDecay(view: View, id: Long, prop: String, spec: JSONObject): Boolean {
197
+ val params = AnimationSpecs.decay(spec)
198
+ val property = floatProperty(prop) ?: return false
199
+ val scale = unitScale(prop)
200
+ val anim = FlingAnimation(view, property)
201
+ anim.setStartValue((params.from * scale).toFloat())
202
+ anim.setStartVelocity((params.startVelocity * scale).toFloat())
203
+ anim.friction = params.friction.toFloat()
204
+ anim.addEndListener { _, canceled, _, _ -> complete(id, !canceled) }
205
+ running[id] = Running(view, prop) { anim.cancel() }
206
+ anim.start()
207
+ return true
208
+ }
209
+
210
+ // ------------------------------------------------------------------
211
+ // Helpers
212
+ // ------------------------------------------------------------------
213
+
214
+ private fun px(dp: Double): Float = (dp * PNBridge.density()).toFloat()
215
+
216
+ private fun isFloatProp(prop: String): Boolean =
217
+ prop.startsWith("_pn_graph:") || prop in setOf("opacity", "translate_x", "translate_y", "scale", "scale_x", "scale_y", "rotate")
218
+
219
+ /** Multiplier from spec units to native units (dp to px for translations). */
220
+ private fun unitScale(prop: String): Double =
221
+ if (prop == "translate_x" || prop == "translate_y") PNBridge.density().toDouble() else 1.0
222
+
223
+ /** A `FloatPropertyCompat` for physics animations; `null` for unsupported props. */
224
+ private fun floatProperty(prop: String): FloatPropertyCompat<View>? = if (prop.startsWith("_pn_graph:")) object : FloatPropertyCompat<View>(prop) {
225
+ override fun getValue(view: View): Float = AnimationGraph.value(prop.substringAfter(":").toLong()).toFloat()
226
+ override fun setValue(view: View, value: Float) { AnimationGraph.set(prop.substringAfter(":").toLong(), value.toDouble()) }
227
+ } else when (prop) {
228
+ "opacity" -> DynamicAnimation.ALPHA
229
+ "translate_x" -> DynamicAnimation.TRANSLATION_X
230
+ "translate_y" -> DynamicAnimation.TRANSLATION_Y
231
+ "scale_x" -> DynamicAnimation.SCALE_X
232
+ "scale_y" -> DynamicAnimation.SCALE_Y
233
+ "rotate" -> DynamicAnimation.ROTATION
234
+ "scale" -> object : FloatPropertyCompat<View>("pnScale") {
235
+ override fun getValue(v: View): Float = v.scaleX
236
+ override fun setValue(v: View, value: Float) {
237
+ v.scaleX = value
238
+ v.scaleY = value
239
+ }
240
+ }
241
+ // Color props are not floats; physics specs on them fall back to the Python ticker.
242
+ else -> null
243
+ }
244
+
245
+ private fun interpolator(easing: Any?): TimeInterpolator {
246
+ return when (val resolved = AnimationSpecs.resolveEasing(easing)) {
247
+ is DoubleArray -> PathInterpolator(
248
+ resolved[0].toFloat(), resolved[1].toFloat(), resolved[2].toFloat(), resolved[3].toFloat(),
249
+ )
250
+ else -> {
251
+ @Suppress("UNCHECKED_CAST")
252
+ val fn = resolved as (Float) -> Float
253
+ TimeInterpolator { t -> fn(t) }
254
+ }
255
+ }
256
+ }
257
+ }
@@ -0,0 +1,106 @@
1
+ package com.pythonnative.runtime.bridge
2
+
3
+ import org.json.JSONArray
4
+ import org.json.JSONObject
5
+
6
+ /** Revision and structural validation before native mutation. */
7
+ class CommitState {
8
+ private var application = ""
9
+ private var surface = 0
10
+ private var revision = 0
11
+ private var live = mutableSetOf<Long>()
12
+ private var parents = mutableMapOf<Long, Long>()
13
+ private var types = mutableMapOf<Long, String>()
14
+ private var failed = false
15
+
16
+ private var sequence = 0L
17
+ @Synchronized fun event(args: JSONArray, editRevision: Long = 0): String = JSONObject()
18
+ .put("application", application).put("surface", surface).put("revision", revision)
19
+ .put("sequence", ++sequence).put("args", args).put("edit_revision", editRevision).toString()
20
+
21
+ fun apply(json: String, applier: TransactionApplier): String {
22
+ try {
23
+ val envelope = JSONObject(json)
24
+ val app = envelope.getString("application")
25
+ val target = envelope.getInt("surface")
26
+ val next = envelope.getInt("revision")
27
+ require(envelope.getInt("version") == 2 && app.isNotEmpty() && target > 0) { "invalid v2 envelope" }
28
+ val replacing = app != application
29
+ require(next == (if (replacing) 1 else revision + 1)) { "stale revision" }
30
+ require(replacing || (!failed && target == surface)) { "failed or foreign surface" }
31
+ val tags = if (replacing) mutableSetOf() else live.toMutableSet()
32
+ val links = if (replacing) mutableMapOf() else parents.toMutableMap()
33
+ val names = if (replacing) mutableMapOf() else types.toMutableMap()
34
+ val raw = envelope.getJSONArray("ops")
35
+ val ops = ArrayList<Op>()
36
+ for (i in 0 until raw.length()) {
37
+ val parts = raw.getJSONArray(i)
38
+ val code = parts.getString(0)
39
+ require(parts.length() == mapOf("c" to 4, "u" to 3, "i" to 4, "d" to 2, "f" to 6)[code]) { "invalid operation" }
40
+ val tag = parts.getLong(1)
41
+ require(tag > 0 && parts.getDouble(1) == tag.toDouble()) { "invalid tag" }
42
+ if (code == "c") {
43
+ require(tags.add(tag) && parts.getString(2).isNotEmpty()) { "duplicate create" }
44
+ parts.getJSONObject(3)
45
+ require(PNRegistry.managerFor(parts.getString(2)) != null) { "unknown component" }
46
+ require(com.pythonnative.generated.PNContracts.validate(parts.getString(2), parts.getJSONObject(3))) { "invalid typed props" }
47
+ names[tag] = parts.getString(2)
48
+ } else {
49
+ require(tag in tags) { "unknown tag" }
50
+ when (code) {
51
+ "u" -> {
52
+ val props = parts.getJSONObject(2)
53
+ val type = names[tag]
54
+ require(type == null || com.pythonnative.generated.PNContracts.validate(type, props, true)) { "invalid typed update" }
55
+ }
56
+ "i" -> {
57
+ val child = parts.getLong(2)
58
+ require(child in tags && parts.getInt(3) >= 0) { "invalid insertion" }
59
+ var ancestor: Long? = tag
60
+ while (ancestor != null) {
61
+ require(ancestor != child) { "cycle" }
62
+ ancestor = links[ancestor]
63
+ }
64
+ require(parts.getInt(3) <= links.count { (key, value) -> value == tag && key != child }) { "insertion index exceeds child count" }
65
+ links[child] = tag
66
+ }
67
+ "d" -> {
68
+ require(tag !in links.values) { "destroy children first" }
69
+ tags.remove(tag)
70
+ names.remove(tag)
71
+ links.remove(tag)
72
+ }
73
+ "f" -> {
74
+ for (j in 2..5) require(parts.getDouble(j).isFinite()) { "invalid frame" }
75
+ require(parts.getDouble(4) >= 0 && parts.getDouble(5) >= 0) { "negative size" }
76
+ }
77
+ }
78
+ }
79
+ ops.add(PNTransaction.decodeOp(parts))
80
+ }
81
+ try {
82
+ if (replacing) {
83
+ for (tag in live) applier.applyOp(Op.Destroy(tag))
84
+ com.pythonnative.runtime.layout.NativeLayout.reset()
85
+ }
86
+ for (op in ops) applier.applyOp(op)
87
+ com.pythonnative.runtime.layout.NativeLayout.observe(ops)
88
+ } catch (error: Exception) {
89
+ failed = true
90
+ for (tag in tags) runCatching { applier.applyOp(Op.Destroy(tag)) }
91
+ throw error
92
+ }
93
+ application = app
94
+ surface = target
95
+ revision = next
96
+ live = tags
97
+ parents = links
98
+ types = names
99
+ failed = false
100
+ return JSONObject().put("ok", true).put("application", app)
101
+ .put("surface", target).put("revision", next).toString()
102
+ } catch (error: Exception) {
103
+ return JSONObject().put("ok", false).put("error", error.message).toString()
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,175 @@
1
+ package com.pythonnative.runtime.bridge
2
+
3
+ import org.json.JSONArray
4
+ import org.json.JSONObject
5
+
6
+ /**
7
+ * Helpers for the JSON shapes the bridge exchanges with Python.
8
+ *
9
+ * Python normalizes values before encoding: `math.inf` arrives as the
10
+ * string `"inf"`, removed props arrive as JSON `null`, and tuples and
11
+ * frozensets arrive as arrays. These helpers hide those conventions.
12
+ */
13
+ object JsonUtil {
14
+ /** Whether `value` is absent or an explicit JSON null. */
15
+ fun isNull(value: Any?): Boolean = value == null || value === JSONObject.NULL
16
+
17
+ /** Coerce a JSON value to a double; `"inf"` / `"-inf"` become infinities. */
18
+ fun toDoubleOrNull(value: Any?): Double? {
19
+ return when (value) {
20
+ null, JSONObject.NULL -> null
21
+ is Number -> value.toDouble()
22
+ is Boolean -> if (value) 1.0 else 0.0
23
+ is String -> {
24
+ val s = value.trim()
25
+ when (s.lowercase()) {
26
+ "inf", "+inf", "infinity", "+infinity" -> Double.POSITIVE_INFINITY
27
+ "-inf", "-infinity" -> Double.NEGATIVE_INFINITY
28
+ "nan" -> Double.NaN
29
+ else -> s.toDoubleOrNull()
30
+ }
31
+ }
32
+ else -> null
33
+ }
34
+ }
35
+
36
+ /** Coerce a JSON value to a double with `default` for missing or unparseable input. */
37
+ fun toDouble(value: Any?, default: Double = 0.0): Double = toDoubleOrNull(value) ?: default
38
+
39
+ /** Coerce a JSON value to an int (truncating), with `default` for bad input. */
40
+ fun toInt(value: Any?, default: Int = 0): Int {
41
+ val d = toDoubleOrNull(value) ?: return default
42
+ if (d.isNaN() || d.isInfinite()) return default
43
+ return d.toInt()
44
+ }
45
+
46
+ /** Coerce a JSON value to a long (truncating), with `default` for bad input. */
47
+ fun toLong(value: Any?, default: Long = 0L): Long {
48
+ return when (value) {
49
+ is Number -> value.toLong()
50
+ else -> {
51
+ val d = toDoubleOrNull(value) ?: return default
52
+ if (d.isNaN() || d.isInfinite()) default else d.toLong()
53
+ }
54
+ }
55
+ }
56
+
57
+ /** Python-style truthiness for JSON values. */
58
+ fun truthy(value: Any?): Boolean {
59
+ return when (value) {
60
+ null, JSONObject.NULL -> false
61
+ is Boolean -> value
62
+ is Number -> value.toDouble() != 0.0
63
+ is String -> value.isNotEmpty()
64
+ is JSONArray -> value.length() > 0
65
+ is JSONObject -> value.length() > 0
66
+ else -> true
67
+ }
68
+ }
69
+
70
+ /** `value` as a string, or `null` when absent or JSON null. */
71
+ fun stringOrNull(value: Any?): String? = if (isNull(value)) null else value.toString()
72
+
73
+ /** Copy `changed` into `target`, keeping explicit nulls as [JSONObject.NULL]. */
74
+ fun merge(target: JSONObject, changed: JSONObject) {
75
+ val keys = changed.keys()
76
+ while (keys.hasNext()) {
77
+ val key = keys.next()
78
+ target.put(key, changed.opt(key) ?: JSONObject.NULL)
79
+ }
80
+ }
81
+
82
+ /** Convert a [JSONArray] to a Kotlin list (JSON nulls become `null`). */
83
+ fun toList(array: JSONArray?): List<Any?> {
84
+ if (array == null) return emptyList()
85
+ val out = ArrayList<Any?>(array.length())
86
+ for (i in 0 until array.length()) {
87
+ val v = array.opt(i)
88
+ out.add(if (v === JSONObject.NULL) null else v)
89
+ }
90
+ return out
91
+ }
92
+
93
+ /** Convert a [JSONObject] to a Kotlin map (JSON nulls become `null`). */
94
+ fun toMap(obj: JSONObject?): Map<String, Any?> {
95
+ if (obj == null) return emptyMap()
96
+ val out = LinkedHashMap<String, Any?>()
97
+ val keys = obj.keys()
98
+ while (keys.hasNext()) {
99
+ val key = keys.next()
100
+ val v = obj.opt(key)
101
+ out[key] = if (v === JSONObject.NULL) null else v
102
+ }
103
+ return out
104
+ }
105
+
106
+ /** Wrap a Kotlin value into something `org.json` can hold (maps, lists, nulls). */
107
+ fun wrap(value: Any?): Any {
108
+ return when (value) {
109
+ null -> JSONObject.NULL
110
+ is JSONObject, is JSONArray, is String, is Boolean -> value
111
+ is Float -> if (value.isFinite()) value.toDouble() else JSONObject.NULL
112
+ is Double -> if (value.isFinite()) value else JSONObject.NULL
113
+ is Number -> value
114
+ is Map<*, *> -> {
115
+ val obj = JSONObject()
116
+ for ((k, v) in value) obj.put(k.toString(), wrap(v))
117
+ obj
118
+ }
119
+ is Iterable<*> -> {
120
+ val arr = JSONArray()
121
+ for (v in value) arr.put(wrap(v))
122
+ arr
123
+ }
124
+ is Array<*> -> wrap(value.asList())
125
+ is DoubleArray -> wrap(value.asList())
126
+ is FloatArray -> wrap(value.asList())
127
+ is IntArray -> wrap(value.asList())
128
+ else -> value.toString()
129
+ }
130
+ }
131
+
132
+ /** Build a JSON array of positional arguments. */
133
+ fun args(vararg values: Any?): JSONArray {
134
+ val arr = JSONArray()
135
+ for (v in values) arr.put(wrap(v))
136
+ return arr
137
+ }
138
+
139
+ /** Encode a command or module result as a JSON string; `null` stays `null`. */
140
+ fun encode(value: Any?): String? {
141
+ if (value == null || value === JSONObject.NULL) return null
142
+ return when (val wrapped = wrap(value)) {
143
+ is JSONObject, is JSONArray -> wrapped.toString()
144
+ is String -> JSONObject.quote(wrapped)
145
+ else -> wrapped.toString()
146
+ }
147
+ }
148
+ }
149
+
150
+ /** The value under `key`, or `null` for missing keys and JSON nulls. */
151
+ fun JSONObject.value(key: String): Any? {
152
+ val v = opt(key) ?: return null
153
+ return if (v === JSONObject.NULL) null else v
154
+ }
155
+
156
+ /** String prop or `null`. */
157
+ fun JSONObject.str(key: String): String? = JsonUtil.stringOrNull(opt(key))
158
+
159
+ /** Numeric prop (accepting `"inf"`) or `null`. */
160
+ fun JSONObject.num(key: String): Double? = JsonUtil.toDoubleOrNull(opt(key))
161
+
162
+ /** Boolean prop using Python truthiness, or `null` when absent. */
163
+ fun JSONObject.bool(key: String): Boolean? {
164
+ val v = value(key) ?: return null
165
+ return JsonUtil.truthy(v)
166
+ }
167
+
168
+ /** Object prop or `null`. */
169
+ fun JSONObject.obj(key: String): JSONObject? = value(key) as? JSONObject
170
+
171
+ /** Array prop or `null`. */
172
+ fun JSONObject.arr(key: String): JSONArray? = value(key) as? JSONArray
173
+
174
+ /** Whether the prop is present with a non-null value. */
175
+ fun JSONObject.present(key: String): Boolean = value(key) != null
@@ -0,0 +1,40 @@
1
+ package com.pythonnative.runtime.bridge
2
+
3
+ import android.os.Handler
4
+ import android.os.Looper
5
+
6
+ /** Main-looper helpers shared by the bridge, modules, and managers. */
7
+ object MainThread {
8
+ private val handler: Handler by lazy { Handler(Looper.getMainLooper()) }
9
+
10
+ /** Run UI work synchronously from the application worker. */
11
+ fun <T> call(body: () -> T): T {
12
+ if (isMain()) return body()
13
+ val task = java.util.concurrent.FutureTask<T> { body() }
14
+ handler.post(task)
15
+ return task.get()
16
+ }
17
+
18
+ /** Whether the current thread is the main thread. */
19
+ fun isMain(): Boolean = Looper.myLooper() == Looper.getMainLooper()
20
+
21
+ /** Post `runnable` to the main looper. */
22
+ fun post(runnable: Runnable) {
23
+ handler.post(runnable)
24
+ }
25
+
26
+ /** Post `runnable` to the main looper after `delayMs`. */
27
+ fun postDelayed(runnable: Runnable, delayMs: Long) {
28
+ handler.postDelayed(runnable, delayMs)
29
+ }
30
+
31
+ /** Remove a pending `runnable`. */
32
+ fun remove(runnable: Runnable) {
33
+ handler.removeCallbacks(runnable)
34
+ }
35
+
36
+ /** Run `runnable` inline when already on the main thread, otherwise post it. */
37
+ fun runOnMain(runnable: Runnable) {
38
+ if (isMain()) runnable.run() else post(runnable)
39
+ }
40
+ }
@@ -0,0 +1,33 @@
1
+ package com.pythonnative.runtime.bridge
2
+
3
+ import android.util.Log
4
+
5
+ /** Rate-limited logging so a hot failing op cannot flood logcat. */
6
+ object PNLog {
7
+ const val TAG = "PythonNative"
8
+
9
+ private const val BURST = 5
10
+ private const val EVERY = 100
11
+ private val counts = HashMap<String, Int>()
12
+ private val once = HashSet<String>()
13
+
14
+ /** Log `message` for `key`, letting the first few through and then every 100th. */
15
+ fun rateLimited(key: String, message: String, error: Throwable? = null) {
16
+ val n = (counts[key] ?: 0) + 1
17
+ counts[key] = n
18
+ if (n <= BURST || n % EVERY == 0) {
19
+ val suffix = if (n > BURST) " (x$n)" else ""
20
+ if (error != null) Log.e(TAG, message + suffix, error) else Log.e(TAG, message + suffix)
21
+ }
22
+ }
23
+
24
+ /** Log `message` at most once per `key`. */
25
+ fun once(key: String, message: String) {
26
+ if (once.add(key)) Log.w(TAG, message)
27
+ }
28
+
29
+ /** Log a swallowed exception at debug level. */
30
+ fun swallowed(where: String, error: Throwable) {
31
+ Log.d(TAG, "$where: ${error.javaClass.simpleName}: ${error.message}")
32
+ }
33
+ }