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,197 @@
1
+ package com.pythonnative.runtime
2
+
3
+ import com.pythonnative.runtime.gestures.GestureArbiter
4
+ import com.pythonnative.runtime.gestures.GestureConfig
5
+ import org.json.JSONArray
6
+ import org.junit.Assert.assertEquals
7
+ import org.junit.Assert.assertFalse
8
+ import org.junit.Assert.assertTrue
9
+ import org.junit.Test
10
+
11
+ class GestureArbiterTest {
12
+ private class Recorder {
13
+ val events = ArrayList<Pair<Int, Map<String, Any?>>>()
14
+ fun emit(index: Int, payload: Map<String, Any?>) {
15
+ events.add(index to payload)
16
+ }
17
+ fun states(index: Int) = events.filter { it.first == index }.map { it.second["state"] }
18
+ }
19
+
20
+ private fun tap(nTaps: Int = 1, sim: Set<Int>? = null, waitFor: Set<Int> = emptySet()) =
21
+ GestureConfig(kind = "tap", nTaps = nTaps, simultaneous = sim, waitFor = waitFor)
22
+
23
+ @Test
24
+ fun singleTapEmitsEnded() {
25
+ val rec = Recorder()
26
+ val arbiter = GestureArbiter(listOf(tap()), rec::emit)
27
+ arbiter.pointerDown(0, 10.0, 10.0, 0.0)
28
+ arbiter.pointerUp(0, 11.0, 10.0, 0.1)
29
+ assertEquals(listOf<Any?>("ended"), rec.states(0))
30
+ assertEquals(11.0, rec.events[0].second["x"])
31
+ }
32
+
33
+ @Test
34
+ fun tapFailsWhenPointerTravels() {
35
+ val rec = Recorder()
36
+ val arbiter = GestureArbiter(listOf(tap()), rec::emit)
37
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
38
+ arbiter.pointerMove(0, 50.0, 0.0, 0.05)
39
+ arbiter.pointerUp(0, 50.0, 0.0, 0.1)
40
+ assertTrue(rec.events.isEmpty())
41
+ }
42
+
43
+ @Test
44
+ fun doubleTapNeedsTwoTapsInsideTheWindow() {
45
+ val rec = Recorder()
46
+ val arbiter = GestureArbiter(listOf(tap(nTaps = 2)), rec::emit)
47
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
48
+ arbiter.pointerUp(0, 0.0, 0.0, 0.05)
49
+ assertTrue(rec.events.isEmpty())
50
+ arbiter.pointerDown(0, 0.0, 0.0, 0.2)
51
+ arbiter.pointerUp(0, 0.0, 0.0, 0.25)
52
+ assertEquals(listOf<Any?>("ended"), rec.states(0))
53
+ }
54
+
55
+ @Test
56
+ fun exclusiveSingleTapWaitsForDoubleTapWindow() {
57
+ // Exclusive(double_tap, single_tap): index 1 waits for index 0.
58
+ val rec = Recorder()
59
+ val specs = listOf(
60
+ tap(nTaps = 2, sim = emptySet()),
61
+ tap(nTaps = 1, sim = emptySet(), waitFor = setOf(0)),
62
+ )
63
+ val arbiter = GestureArbiter(specs, rec::emit)
64
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
65
+ arbiter.pointerUp(0, 0.0, 0.0, 0.05)
66
+ // Single tap is buffered until the double-tap gap expires.
67
+ assertTrue(rec.events.isEmpty())
68
+ val deadline = arbiter.nextDeadline()
69
+ assertTrue(deadline != null && deadline > 0.05)
70
+ arbiter.poll(deadline!! + 0.001)
71
+ assertEquals(listOf<Any?>("ended"), rec.states(1))
72
+ assertTrue(rec.states(0).isEmpty())
73
+ }
74
+
75
+ @Test
76
+ fun exclusiveDoubleTapSuppressesSingleTap() {
77
+ val rec = Recorder()
78
+ val specs = listOf(
79
+ tap(nTaps = 2, sim = emptySet()),
80
+ tap(nTaps = 1, sim = emptySet(), waitFor = setOf(0)),
81
+ )
82
+ val arbiter = GestureArbiter(specs, rec::emit)
83
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
84
+ arbiter.pointerUp(0, 0.0, 0.0, 0.05)
85
+ arbiter.pointerDown(0, 0.0, 0.0, 0.15)
86
+ arbiter.pointerUp(0, 0.0, 0.0, 0.2)
87
+ assertEquals(listOf<Any?>("ended"), rec.states(0))
88
+ assertTrue(rec.states(1).isEmpty())
89
+ }
90
+
91
+ @Test
92
+ fun longPressActivatesOnPollAndEndsOnRelease() {
93
+ val rec = Recorder()
94
+ val arbiter = GestureArbiter(listOf(GestureConfig(kind = "long_press", minDurationMs = 500.0)), rec::emit)
95
+ arbiter.pointerDown(0, 5.0, 5.0, 0.0)
96
+ assertEquals(0.5, arbiter.nextDeadline()!!, 1e-9)
97
+ arbiter.poll(0.3)
98
+ assertTrue(rec.events.isEmpty())
99
+ arbiter.poll(0.5)
100
+ assertEquals(listOf<Any?>("began"), rec.states(0))
101
+ arbiter.pointerUp(0, 5.0, 5.0, 0.7)
102
+ assertEquals(listOf<Any?>("began", "ended"), rec.states(0))
103
+ }
104
+
105
+ @Test
106
+ fun panReportsTranslationAndVelocity() {
107
+ val rec = Recorder()
108
+ val arbiter = GestureArbiter(listOf(GestureConfig(kind = "pan", minDistance = 10.0)), rec::emit)
109
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
110
+ arbiter.pointerMove(0, 5.0, 0.0, 0.01)
111
+ assertTrue(rec.events.isEmpty())
112
+ arbiter.pointerMove(0, 20.0, 0.0, 0.02)
113
+ assertEquals(listOf<Any?>("began"), rec.states(0))
114
+ assertTrue(arbiter.hasActivePan())
115
+ arbiter.pointerMove(0, 30.0, 5.0, 0.03)
116
+ val changed = rec.events.last().second
117
+ assertEquals("changed", changed["state"])
118
+ assertEquals(10.0, changed["translation_x"] as Double, 1e-9)
119
+ assertEquals(5.0, changed["translation_y"] as Double, 1e-9)
120
+ assertTrue((changed["velocity_x"] as Double) > 0)
121
+ arbiter.pointerUp(0, 40.0, 5.0, 0.04)
122
+ val ended = rec.events.last().second
123
+ assertEquals("ended", ended["state"])
124
+ assertEquals(20.0, ended["translation_x"] as Double, 1e-9)
125
+ assertFalse(arbiter.hasActivePan())
126
+ }
127
+
128
+ @Test
129
+ fun raceLetsFirstActivationWin() {
130
+ // Pan and long press not simultaneous: the pan activates first, long press never fires.
131
+ val rec = Recorder()
132
+ val specs = listOf(
133
+ GestureConfig(kind = "pan", minDistance = 10.0, simultaneous = emptySet()),
134
+ GestureConfig(kind = "long_press", minDurationMs = 500.0, simultaneous = emptySet()),
135
+ )
136
+ val arbiter = GestureArbiter(specs, rec::emit)
137
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
138
+ arbiter.pointerMove(0, 3.0, 0.0, 0.05)
139
+ arbiter.pointerMove(0, 6.0, 0.0, 0.1)
140
+ arbiter.pointerMove(0, 20.0, 0.0, 0.15)
141
+ assertEquals(listOf<Any?>("began"), rec.states(0))
142
+ arbiter.poll(0.6)
143
+ assertTrue(rec.states(1).isEmpty())
144
+ }
145
+
146
+ @Test
147
+ fun simultaneousGesturesBothRun() {
148
+ val rec = Recorder()
149
+ val specs = listOf(
150
+ GestureConfig(kind = "pan", minDistance = 5.0, simultaneous = setOf(1)),
151
+ GestureConfig(kind = "pinch", simultaneous = setOf(0)),
152
+ )
153
+ val arbiter = GestureArbiter(specs, rec::emit)
154
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
155
+ arbiter.pointerDown(1, 100.0, 0.0, 0.01)
156
+ assertEquals(listOf<Any?>("began"), rec.states(1))
157
+ arbiter.pointerMove(1, 120.0, 0.0, 0.02)
158
+ assertEquals(listOf<Any?>("began"), rec.states(0))
159
+ assertEquals(listOf<Any?>("began", "changed"), rec.states(1))
160
+ assertEquals(1.2, rec.events.last().second["scale"] as Double, 1e-9)
161
+ }
162
+
163
+ @Test
164
+ fun swipeResolvesDirectionAndVelocity() {
165
+ val rec = Recorder()
166
+ val arbiter = GestureArbiter(listOf(GestureConfig(kind = "swipe", direction = "right", minVelocity = 300.0)), rec::emit)
167
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
168
+ arbiter.pointerMove(0, 50.0, 0.0, 0.05)
169
+ arbiter.pointerUp(0, 100.0, 0.0, 0.1)
170
+ val ended = rec.events.single().second
171
+ assertEquals("ended", ended["state"])
172
+ assertEquals("right", ended["direction"])
173
+ assertEquals(1000.0, ended["velocity_x"] as Double, 1e-6)
174
+ }
175
+
176
+ @Test
177
+ fun cancelAbortsActiveGestures() {
178
+ val rec = Recorder()
179
+ val arbiter = GestureArbiter(listOf(GestureConfig(kind = "pan", minDistance = 1.0)), rec::emit)
180
+ arbiter.pointerDown(0, 0.0, 0.0, 0.0)
181
+ arbiter.pointerMove(0, 10.0, 0.0, 0.01)
182
+ arbiter.cancel(0.02)
183
+ assertEquals(listOf<Any?>("began", "cancelled"), rec.states(0))
184
+ }
185
+
186
+ @Test
187
+ fun decodesSerializedSpecs() {
188
+ val specs = GestureArbiter.decodeSpecs(
189
+ JSONArray("""[{"kind":"tap","n_taps":2,"simultaneous":[1],"wait_for":[]},{"kind":"pan","min_distance":4}]"""),
190
+ )
191
+ assertEquals(2, specs.size)
192
+ assertEquals(2, specs[0].nTaps)
193
+ assertEquals(setOf(1), specs[0].simultaneous)
194
+ assertEquals(4.0, specs[1].minDistance, 0.0)
195
+ assertEquals(null, specs[1].simultaneous)
196
+ }
197
+ }
@@ -0,0 +1,47 @@
1
+ package com.pythonnative.runtime
2
+
3
+ import com.pythonnative.runtime.components.PNColor
4
+ import org.json.JSONArray
5
+ import org.junit.Assert.assertEquals
6
+ import org.junit.Assert.assertNull
7
+ import org.junit.Test
8
+
9
+ class PNColorTest {
10
+ private fun hex(v: Int?): String = if (v == null) "null" else String.format("%08X", v)
11
+
12
+ @Test
13
+ fun parsesHexForms() {
14
+ assertEquals("FFFF0000", hex(PNColor.parse("#f00")))
15
+ assertEquals("FF112233", hex(PNColor.parse("#112233")))
16
+ assertEquals("80112233", hex(PNColor.parse("#80112233")))
17
+ assertEquals("FF112233", hex(PNColor.parse("112233")))
18
+ }
19
+
20
+ @Test
21
+ fun parsesFunctionalForms() {
22
+ assertEquals("FF0A141E", hex(PNColor.parse("rgb(10, 20, 30)")))
23
+ assertEquals("800A141E", hex(PNColor.parse("rgba(10, 20, 30, 0.5)")))
24
+ }
25
+
26
+ @Test
27
+ fun parsesNamedColors() {
28
+ assertEquals("FF000000", hex(PNColor.parse("black")))
29
+ assertEquals("FFFFFFFF", hex(PNColor.parse("White")))
30
+ assertEquals("00000000", hex(PNColor.parse("transparent")))
31
+ }
32
+
33
+ @Test
34
+ fun parsesIntegersAndArrays() {
35
+ assertEquals("FF112233", hex(PNColor.parse(0x112233)))
36
+ assertEquals("80112233", hex(PNColor.parse(0x80112233L)))
37
+ assertEquals("FF0A141E", hex(PNColor.parse(JSONArray("[10, 20, 30]"))))
38
+ assertEquals("800A141E", hex(PNColor.parse(JSONArray("[10, 20, 30, 0.5]"))))
39
+ }
40
+
41
+ @Test
42
+ fun rejectsGarbage() {
43
+ assertNull(PNColor.parse("not a color"))
44
+ assertNull(PNColor.parse(null))
45
+ assertEquals(7, PNColor.parseOr("nope", 7))
46
+ }
47
+ }
@@ -0,0 +1,78 @@
1
+ package com.pythonnative.runtime
2
+
3
+ import com.pythonnative.runtime.bridge.JsonUtil
4
+ import com.pythonnative.runtime.bridge.Op
5
+ import com.pythonnative.runtime.bridge.PNTransaction
6
+ import com.pythonnative.runtime.bridge.value
7
+ import org.json.JSONObject
8
+ import org.junit.Assert.assertEquals
9
+ import org.junit.Assert.assertNull
10
+ import org.junit.Assert.assertTrue
11
+ import org.junit.Test
12
+
13
+ class PNTransactionTest {
14
+ @Test
15
+ fun decodesEveryOpcode() {
16
+ val json = """
17
+ [
18
+ ["c", 1, "View", {"background_color": "#fff"}],
19
+ ["u", 1, {"opacity": 0.5, "background_color": null}],
20
+ ["i", 1, 2, 0],
21
+ ["f", 2, 10, 20.5, 100, 40],
22
+ ["d", 2]
23
+ ]
24
+ """.trimIndent()
25
+ val ops = PNTransaction.decode(json)
26
+ assertEquals(5, ops.size)
27
+ val create = ops[0] as Op.Create
28
+ assertEquals(1L, create.tag)
29
+ assertEquals("View", create.typeName)
30
+ assertEquals("#fff", create.props.getString("background_color"))
31
+ val update = ops[1] as Op.Update
32
+ assertEquals(0.5, update.changed.getDouble("opacity"), 1e-9)
33
+ assertTrue(update.changed.isNull("background_color"))
34
+ assertEquals(Op.Insert(1, 2, 0), ops[2])
35
+ assertEquals(Op.Frame(2, 10.0, 20.5, 100.0, 40.0), ops[3])
36
+ assertEquals(Op.Destroy(2), ops[4])
37
+ }
38
+
39
+ @Test
40
+ fun infinityStringsBecomeInfinity() {
41
+ val ops = PNTransaction.decode("""[["f", 1, 0, 0, "inf", "-inf"]]""")
42
+ val frame = ops[0] as Op.Frame
43
+ assertEquals(Double.POSITIVE_INFINITY, frame.width, 0.0)
44
+ assertEquals(Double.NEGATIVE_INFINITY, frame.height, 0.0)
45
+ assertEquals(Double.POSITIVE_INFINITY, JsonUtil.toDouble("Infinity"), 0.0)
46
+ }
47
+
48
+ @Test
49
+ fun malformedOpsAreIsolated() {
50
+ val errors = ArrayList<Int>()
51
+ val ops = PNTransaction.decode(
52
+ """[["c", 1, "View", {}], ["zz", 1], "not-an-array", ["i"], ["d", 1]]""",
53
+ ) { index, _ -> errors.add(index) }
54
+ assertEquals(listOf(1, 2, 3), errors)
55
+ assertEquals(2, ops.size)
56
+ assertTrue(ops[0] is Op.Create)
57
+ assertEquals(Op.Destroy(1), ops[1])
58
+ }
59
+
60
+ @Test
61
+ fun mergeKeepsExplicitNulls() {
62
+ val target = JSONObject("""{"a": 1, "b": 2}""")
63
+ JsonUtil.merge(target, JSONObject("""{"b": null, "c": "x"}"""))
64
+ assertEquals(1, target.getInt("a"))
65
+ assertTrue(target.isNull("b"))
66
+ assertNull(target.value("b"))
67
+ assertEquals("x", target.getString("c"))
68
+ }
69
+
70
+ @Test
71
+ fun encodesResultsAsJson() {
72
+ assertNull(JsonUtil.encode(null))
73
+ assertEquals("\"hi\"", JsonUtil.encode("hi"))
74
+ assertEquals("true", JsonUtil.encode(true))
75
+ assertEquals("""{"x":1.5}""", JsonUtil.encode(mapOf("x" to 1.5)))
76
+ assertEquals("[1,2]", JsonUtil.encode(listOf(1, 2)))
77
+ }
78
+ }
@@ -0,0 +1,89 @@
1
+ package com.pythonnative.runtime
2
+
3
+ import com.pythonnative.runtime.modules.ModuleEnvelope
4
+ import com.pythonnative.runtime.modules.Promise
5
+ import org.json.JSONObject
6
+ import org.junit.Assert.assertEquals
7
+ import org.junit.Assert.assertFalse
8
+ import org.junit.Assert.assertTrue
9
+ import org.junit.Test
10
+
11
+ class PromiseTest {
12
+ @Test
13
+ fun cancellationReleasesWorkAndIgnoresLateCompletion() {
14
+ val posted = ArrayList<Runnable>()
15
+ val promise = Promise(42, "Test") { posted.add(it) }
16
+ promise.markReturned()
17
+ var cancelled = 0
18
+ promise.onCancel { cancelled++ }
19
+ promise.cancel()
20
+ promise.cancel()
21
+ promise.resolve("late")
22
+ assertTrue(promise.isCancelled)
23
+ assertEquals(1, cancelled)
24
+ assertTrue(posted.isEmpty())
25
+ }
26
+ @Test
27
+ fun decodesCallEnvelope() {
28
+ val (callId, args) = ModuleEnvelope.decodeCall("""{"call_id": 7, "args": {"url": "x"}}""")
29
+ assertEquals(7L, callId)
30
+ assertEquals("x", args.getString("url"))
31
+ val (emptyId, emptyArgs) = ModuleEnvelope.decodeCall("")
32
+ assertEquals(0L, emptyId)
33
+ assertEquals(0, emptyArgs.length())
34
+ }
35
+
36
+ @Test
37
+ fun encodesResultEnvelopes() {
38
+ assertEquals("""{"ok":true,"value":3}""", ModuleEnvelope.ok(3))
39
+ val err = JSONObject(ModuleEnvelope.error("boom", "code_x"))
40
+ assertFalse(err.getBoolean("ok"))
41
+ assertEquals("boom", err.getString("error"))
42
+ assertEquals("code_x", err.getString("code"))
43
+ assertEquals("""{"pending":true}""", ModuleEnvelope.pending())
44
+ val event = JSONObject(ModuleEnvelope.event("change", mapOf("state" to "active")))
45
+ assertEquals("change", event.getString("event"))
46
+ assertEquals("active", event.getJSONObject("payload").getString("state"))
47
+ }
48
+
49
+ @Test
50
+ fun synchronousSettlementIsReturnedInline() {
51
+ val posted = ArrayList<Runnable>()
52
+ val promise = Promise(1, "Test") { posted.add(it) }
53
+ promise.resolve(mapOf("a" to 1))
54
+ assertTrue(promise.isSettled)
55
+ assertEquals("""{"ok":true,"value":{"a":1}}""", promise.markReturned())
56
+ assertTrue(posted.isEmpty())
57
+ }
58
+
59
+ @Test
60
+ fun asynchronousSettlementIsPosted() {
61
+ val posted = ArrayList<Runnable>()
62
+ val promise = Promise(9, "Test") { posted.add(it) }
63
+ assertEquals("""{"pending":true}""", promise.markReturned())
64
+ promise.resolve("later")
65
+ assertEquals(1, posted.size)
66
+ // Second settlement is ignored.
67
+ promise.reject("nope")
68
+ assertEquals(1, posted.size)
69
+ }
70
+
71
+ @Test
72
+ fun rejectionEnvelopeCarriesCode() {
73
+ val promise = Promise(2, "Test") { }
74
+ promise.reject("bad", "bad_request")
75
+ val obj = JSONObject(promise.markReturned())
76
+ assertFalse(obj.getBoolean("ok"))
77
+ assertEquals("bad_request", obj.getString("code"))
78
+ }
79
+
80
+ @Test
81
+ fun settledEnvelopesCarryCallId() {
82
+ val ok = JSONObject(ModuleEnvelope.settled(5, true))
83
+ assertEquals(5L, ok.getLong("call_id"))
84
+ assertTrue(ok.getBoolean("ok"))
85
+ val err = JSONObject(ModuleEnvelope.settledError(6, "x", null))
86
+ assertEquals(6L, err.getLong("call_id"))
87
+ assertFalse(err.has("code"))
88
+ }
89
+ }
@@ -0,0 +1,23 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "PythonNativeKit",
6
+ platforms: [.iOS(.v13)],
7
+ products: [
8
+ .library(name: "PythonNativeKit", targets: ["PythonNativeKit"]),
9
+ ],
10
+ dependencies: [.package(path: "../yoga")],
11
+ targets: [
12
+ .target(
13
+ name: "PythonNativeKit",
14
+ dependencies: [.product(name: "YogaCore", package: "yoga")],
15
+ path: "Sources/PythonNativeKit"
16
+ ),
17
+ .testTarget(
18
+ name: "PythonNativeKitTests",
19
+ dependencies: ["PythonNativeKit"],
20
+ path: "Tests/PythonNativeKitTests"
21
+ ),
22
+ ]
23
+ )
@@ -0,0 +1,199 @@
1
+ import UIKit
2
+
3
+ /// UI-thread expression evaluation, input bindings, and graph animation drivers.
4
+ enum PNAnimationGraph {
5
+ struct Graph { var nodes: [[String: Any]]; var bindings: [[Any]] }
6
+ static var graphs: [Int64: Graph] = [:]
7
+ static var values: [Int64: Double] = [:]
8
+ static var previous: [Int64: Double] = [:]
9
+ static var outputs: [Int64: Any] = [:]
10
+ static var drivers: [Int64: PNGraphDriver] = [:]
11
+
12
+ static func number(_ value: Any?) -> Double { (value as? NSNumber)?.doubleValue ?? 0 }
13
+ static func identity(_ value: Any?) -> Int64 { (value as? NSNumber)?.int64Value ?? 0 }
14
+ static func install(_ spec: [String: Any]) {
15
+ let id = identity(spec["id"])
16
+ let bindings = spec["bindings"] as? [[Any]] ?? []
17
+ let nodes = spec["nodes"] as? [[String: Any]] ?? []
18
+ let ids = Set(nodes.map { identity($0["id"]) })
19
+ for (key, graph) in graphs where graph.nodes.contains(where: { ids.contains(identity($0["id"])) }) { graphs.removeValue(forKey: key) }
20
+ if !bindings.isEmpty {
21
+ for node in nodes {
22
+ let key = identity(node["id"])
23
+ if values[key] == nil { values[key] = number(node["value"]) }
24
+ if previous[key] == nil { previous[key] = number(node["previous"]) }
25
+ }
26
+ graphs[id] = Graph(nodes: nodes, bindings: bindings)
27
+ }
28
+ collect()
29
+ evaluate()
30
+ }
31
+ static func set(_ id: Int64, _ value: Double) {
32
+ guard value.isFinite else { return }
33
+ values[id] = value
34
+ evaluate()
35
+ }
36
+ static func event(_ tag: Int64, _ name: String, _ args: [Any?]) {
37
+ guard let view = PNViewRegistry.shared.view(for: tag), let props = PNViewState.existing(for: view)?.props,
38
+ let payload = args.first as? [String: Any] else { return }
39
+ var fields: [String: Any]?
40
+ if name.hasPrefix("gesture:"), let index = Int(name.dropFirst(8)),
41
+ let gestures = props["gestures"] as? [[String: Any]], gestures.indices.contains(index),
42
+ let events = gestures[index]["animated_events"] as? [String: [String: Any]] {
43
+ fields = events[payload["state"] as? String ?? ""]
44
+ } else { fields = (props["_pn_animated_events"] as? [String: [String: Any]])?[name] }
45
+ guard let fields = fields else { return }
46
+ for (field, node) in fields { if let value = payload[field] as? NSNumber { values[identity(node)] = value.doubleValue } }
47
+ evaluate()
48
+ }
49
+ static func forget(_ tag: Int64) {
50
+ for (id, var graph) in graphs {
51
+ graph.bindings.removeAll { identity($0[0]) == tag }
52
+ if graph.bindings.isEmpty { graphs.removeValue(forKey: id) } else { graphs[id] = graph }
53
+ }
54
+ collect()
55
+ }
56
+ static func collect() {
57
+ let live = Set(graphs.values.flatMap { $0.nodes.map { identity($0["id"]) } })
58
+ values = values.filter { live.contains($0.key) }
59
+ previous = previous.filter { live.contains($0.key) }
60
+ outputs = outputs.filter { live.contains($0.key) }
61
+ for (id, driver) in drivers where !live.contains(driver.node) {
62
+ driver.stop()
63
+ drivers.removeValue(forKey: id)
64
+ PNAnimator.reportCompletion(id: id, finished: false)
65
+ }
66
+ }
67
+ static func input(_ value: [String: Any]) -> Double {
68
+ value["node"] == nil ? number(value["constant"]) : values[identity(value["node"])] ?? 0
69
+ }
70
+ static func evaluate() {
71
+ for graph in graphs.values {
72
+ for node in graph.nodes {
73
+ let id = identity(node["id"])
74
+ let inputs = (node["inputs"] as? [[String: Any]] ?? []).map(input)
75
+ let a = inputs.first ?? 0, b = inputs.count > 1 ? inputs[1] : 0
76
+ var value: Double = 0
77
+ switch node["kind"] as? String {
78
+ case "value": value = values[id] ?? 0
79
+ case "add": value = a + b
80
+ case "subtract": value = a - b
81
+ case "multiply": value = a * b
82
+ case "divide": value = b == 0 ? 0 : a / b
83
+ case "modulo": value = b == 0 ? 0 : a.truncatingRemainder(dividingBy: b)
84
+ case "negate": value = -a
85
+ case "diff_clamp":
86
+ value = min(number(node["maximum"]), max(number(node["minimum"]), (values[id] ?? 0) + a - (previous[id] ?? a)))
87
+ previous[id] = a
88
+ case "interpolate": value = interpolate(node, a, id)
89
+ default: break
90
+ }
91
+ values[id] = value.isFinite ? value : 0
92
+ if node["color"] as? Bool != true { outputs[id] = values[id] }
93
+ }
94
+ for binding in graph.bindings {
95
+ guard binding.count == 3, let record = PNViewRegistry.shared.resolve(identity(binding[0])), let prop = binding[1] as? String else { continue }
96
+ record.manager.setAnimatedProperty(view: record.view, prop: prop, value: outputs[identity(binding[2])])
97
+ }
98
+ }
99
+ }
100
+ private static func interpolate(_ node: [String: Any], _ incoming: Double, _ id: Int64) -> Double {
101
+ guard let ranges = node["ranges"] as? [Double], ranges.count >= 2,
102
+ let outputs = node["outputs"] as? [Any], outputs.count == ranges.count else { return 0 }
103
+ var x = incoming
104
+ let mode = x < ranges[0] ? node["left"] as? String : x > ranges.last! ? node["right"] as? String : "extend"
105
+ if mode == "identity" { return x }
106
+ if mode == "clamp" { x = min(ranges.last!, max(ranges[0], x)) }
107
+ var index = 0
108
+ while index < ranges.count - 2 && x >= ranges[index + 1] { index += 1 }
109
+ let span = ranges[index + 1] - ranges[index]
110
+ let t = span == 0 ? 0 : (x - ranges[index]) / span
111
+ if node["color"] as? Bool == true, let from = outputs[index] as? [Double], let to = outputs[index + 1] as? [Double] {
112
+ self.outputs[id] = "#" + zip(from, to).map { String(format: "%02X", Int(min(255, max(0, ($0 + ($1 - $0) * min(1, max(0, t))).rounded())))) }.joined()
113
+ return 0
114
+ }
115
+ return number(outputs[index]) + (number(outputs[index + 1]) - number(outputs[index])) * t
116
+ }
117
+ static func start(_ id: Int64, node: Int64, spec: [String: Any]) -> Bool {
118
+ guard values[node] != nil, ["timing", "spring", "decay"].contains(spec["kind"] as? String ?? "") else { return false }
119
+ drivers.removeValue(forKey: id)?.stop()
120
+ let driver = PNGraphDriver(id: id, node: node, spec: spec)
121
+ drivers[id] = driver
122
+ driver.start()
123
+ return true
124
+ }
125
+ static func cancel(_ id: Int64) -> Double? {
126
+ guard let driver = drivers.removeValue(forKey: id) else { return nil }
127
+ driver.stop()
128
+ return values[driver.node]
129
+ }
130
+ }
131
+
132
+ final class PNGraphDriver: NSObject {
133
+ let id: Int64, node: Int64
134
+ let spec: [String: Any]
135
+ var link: CADisplayLink?
136
+ var elapsed = 0.0, previousTime = 0.0
137
+ var current: Double, velocity: Double
138
+ init(id: Int64, node: Int64, spec: [String: Any]) {
139
+ self.id = id; self.node = node; self.spec = spec
140
+ current = PNAnimationGraph.number(spec["from"])
141
+ velocity = PNAnimationGraph.number(spec["velocity"] ?? spec["initial_velocity"])
142
+ }
143
+ func start() {
144
+ let display = CADisplayLink(target: self, selector: #selector(tick(_:)))
145
+ link = display
146
+ display.add(to: .main, forMode: .common)
147
+ }
148
+ func stop() { link?.invalidate(); link = nil }
149
+ @objc func tick(_ display: CADisplayLink) {
150
+ let dt = previousTime == 0 ? display.duration : min(0.064, display.timestamp - previousTime)
151
+ previousTime = display.timestamp
152
+ elapsed += dt
153
+ let delay = PNAnimationGraph.number(spec["delay_ms"]) / 1000
154
+ guard elapsed >= delay else { return }
155
+ let target = PNAnimationGraph.number(spec["to"])
156
+ var done = false
157
+ switch spec["kind"] as? String {
158
+ case "spring":
159
+ let mass = max(0.001, (spec["mass"] as? Double) ?? 1)
160
+ let stiffness = (spec["stiffness"] as? Double) ?? 100
161
+ let damping = (spec["damping"] as? Double) ?? 10
162
+ let steps = max(1, Int(ceil(dt / 0.004)))
163
+ for _ in 0..<steps {
164
+ let step = dt / Double(steps)
165
+ velocity += (-stiffness * (current - target) - damping * velocity) / mass * step
166
+ current += velocity * step
167
+ }
168
+ done = abs(velocity) < ((spec["rest_speed_threshold"] as? Double) ?? 0.01) && abs(current - target) < ((spec["rest_displacement_threshold"] as? Double) ?? 0.01)
169
+ if done { current = target }
170
+ case "decay":
171
+ velocity *= pow(min(0.999999, max(0.001, (spec["deceleration"] as? Double) ?? 0.997)), dt * 1000)
172
+ current += velocity * dt
173
+ done = abs(velocity) < ((spec["rest_threshold"] as? Double) ?? 0.1)
174
+ default:
175
+ let duration = max(0.001, ((spec["duration_ms"] as? Double) ?? 300) / 1000)
176
+ let t = min(1, max(0, (elapsed - delay) / duration))
177
+ let curve = PNAnimator.curve(for: spec["easing"]) as? UICubicTimingParameters
178
+ let eased = curve.map { Self.bezier(t, $0.controlPoint1, $0.controlPoint2) } ?? t
179
+ let from = PNAnimationGraph.number(spec["from"])
180
+ current = from + (target - from) * eased
181
+ done = t >= 1
182
+ }
183
+ if UIAccessibility.isReduceMotionEnabled { current = target; done = true }
184
+ PNAnimationGraph.set(node, current)
185
+ if done {
186
+ stop(); PNAnimationGraph.drivers.removeValue(forKey: id)
187
+ PNAnimator.reportCompletion(id: id, finished: true)
188
+ }
189
+ }
190
+ static func bezier(_ t: Double, _ p1: CGPoint, _ p2: CGPoint) -> Double {
191
+ func coordinate(_ u: Double, _ a: Double, _ b: Double) -> Double { 3 * (1-u) * (1-u) * u * a + 3 * (1-u) * u * u * b + u * u * u }
192
+ var low = 0.0, high = 1.0
193
+ for _ in 0..<18 {
194
+ let mid = (low + high) / 2
195
+ if coordinate(mid, p1.x, p2.x) < t { low = mid } else { high = mid }
196
+ }
197
+ return coordinate((low + high) / 2, p1.y, p2.y)
198
+ }
199
+ }