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,243 @@
1
+ import UIKit
2
+
3
+ /// `Modal`: a hidden on-tree placeholder whose children mount into a
4
+ /// presented `UIViewController` while `visible` is true.
5
+ public final class PNModalManager: PNComponentManager {
6
+ final class Presentation {
7
+ let controller: UIViewController
8
+ let content: UIView
9
+ init(controller: UIViewController, content: UIView) {
10
+ self.controller = controller
11
+ self.content = content
12
+ }
13
+ }
14
+
15
+ public override func makeView(props: [String: Any]) -> UIView {
16
+ let placeholder = UIView(frame: .zero)
17
+ placeholder.isHidden = true
18
+ return placeholder
19
+ }
20
+
21
+ public override func apply(view: UIView, props: [String: Any], initial: Bool) {
22
+ guard let state = PNViewState.existing(for: view) else { return }
23
+ let visible = PNProps.bool(PNProps.value(state.props, "visible")) ?? false
24
+ let presented = state.extras["modal"] is Presentation
25
+ if visible, !presented {
26
+ present(view, state)
27
+ } else if !visible, presented {
28
+ dismiss(view, state, emit: true)
29
+ }
30
+ }
31
+
32
+ public override func teardown(view: UIView) {
33
+ if let state = PNViewState.existing(for: view), state.extras["modal"] is Presentation {
34
+ dismiss(view, state, emit: false)
35
+ }
36
+ }
37
+
38
+ public override func childContainer(for view: UIView) -> UIView {
39
+ guard let state = PNViewState.existing(for: view), let modal = state.extras["modal"] as? Presentation else {
40
+ return view
41
+ }
42
+ return modal.content
43
+ }
44
+
45
+ public override func insertChild(parent: UIView, child: UIView, index: Int) {
46
+ if let state = PNViewState.existing(for: parent), !(state.extras["modal"] is Presentation) {
47
+ var pending = (state.extras["pending_children"] as? [UIView]) ?? []
48
+ pending.removeAll { $0 === child }
49
+ pending.insert(child, at: max(0, min(index, pending.count)))
50
+ state.extras["pending_children"] = pending
51
+ return
52
+ }
53
+ super.insertChild(parent: parent, child: child, index: index)
54
+ }
55
+
56
+ public override func removeChild(parent: UIView, child: UIView) {
57
+ super.removeChild(parent: parent, child: child)
58
+ if let state = PNViewState.existing(for: parent), var pending = state.extras["pending_children"] as? [UIView] {
59
+ pending.removeAll { $0 === child }
60
+ state.extras["pending_children"] = pending
61
+ }
62
+ }
63
+
64
+ public override func setFrame(view: UIView, x: Double, y: Double, w: Double, h: Double) {}
65
+
66
+ public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize { .zero }
67
+
68
+ private func present(_ placeholder: UIView, _ state: PNViewState) {
69
+ let props = state.props
70
+ let controller = PNModalViewController()
71
+ controller.onDismissed = { [weak placeholder] in
72
+ guard let placeholder = placeholder, let state = PNViewState.existing(for: placeholder),
73
+ state.extras["modal"] is Presentation
74
+ else { return }
75
+ state.extras.removeValue(forKey: "modal")
76
+ PNEvents.emit(placeholder, "on_dismiss")
77
+ PNEvents.emitIfWired(placeholder, "on_request_close")
78
+ }
79
+ let style = PNProps.string(PNProps.value(props, "presentation_style")) ?? "page_sheet"
80
+ let isOverlay = style == "overlay" || PNProps.bool(PNProps.value(props, "transparent")) == true
81
+ let content = UIView(frame: controller.view.bounds)
82
+ content.backgroundColor = isOverlay ? .clear : PNColor.parse(PNProps.value(props, "background_color")) ?? .systemBackground
83
+ content.autoresizingMask = [.flexibleWidth, .flexibleHeight]
84
+ controller.view.addSubview(content)
85
+ controller.view.backgroundColor = isOverlay ? UIColor.black.withAlphaComponent(0.4) : content.backgroundColor
86
+ switch isOverlay ? "overlay" : style {
87
+ case "full_screen": controller.modalPresentationStyle = .fullScreen
88
+ case "form_sheet": controller.modalPresentationStyle = .formSheet
89
+ case "overlay": controller.modalPresentationStyle = .overCurrentContext
90
+ default: controller.modalPresentationStyle = .pageSheet
91
+ }
92
+ switch PNProps.string(PNProps.value(props, "animation_type")) ?? PNProps.string(PNProps.value(props, "animation")) {
93
+ case "fade": controller.modalTransitionStyle = .crossDissolve
94
+ case "flip": controller.modalTransitionStyle = .flipHorizontal
95
+ default: controller.modalTransitionStyle = .coverVertical
96
+ }
97
+ if !isOverlay, PNProps.bool(PNProps.value(props, "dismiss_on_backdrop")) == false {
98
+ controller.isModalInPresentation = true
99
+ }
100
+ let presentation = Presentation(controller: controller, content: content)
101
+ state.extras["modal"] = presentation
102
+ for child in (state.extras.removeValue(forKey: "pending_children") as? [UIView]) ?? [] {
103
+ child.translatesAutoresizingMaskIntoConstraints = true
104
+ content.addSubview(child)
105
+ }
106
+ let animated = PNProps.string(PNProps.value(props, "animation_type")) != "none"
107
+ guard let top = PNWindow.topViewController() else {
108
+ state.extras.removeValue(forKey: "modal")
109
+ return
110
+ }
111
+ top.present(controller, animated: animated) { [weak placeholder] in
112
+ if let placeholder = placeholder { PNEvents.emit(placeholder, "on_show") }
113
+ }
114
+ }
115
+
116
+ private func dismiss(_ placeholder: UIView, _ state: PNViewState, emit: Bool) {
117
+ guard let modal = state.extras.removeValue(forKey: "modal") as? Presentation else { return }
118
+ (modal.controller as? PNModalViewController)?.onDismissed = nil
119
+ let animated = PNProps.string(PNProps.value(state.props, "animation_type")) != "none"
120
+ modal.controller.dismiss(animated: animated)
121
+ if emit { PNEvents.emit(placeholder, "on_dismiss") }
122
+ }
123
+ }
124
+
125
+ /// Reports interactive dismissal (sheet swipe) back to the manager.
126
+ final class PNModalViewController: UIViewController {
127
+ var onDismissed: (() -> Void)?
128
+
129
+ override func viewDidDisappear(_ animated: Bool) {
130
+ super.viewDidDisappear(animated)
131
+ if isBeingDismissed || presentingViewController == nil {
132
+ onDismissed?()
133
+ }
134
+ }
135
+ }
136
+
137
+ /// Overlay view that only claims touches landing on one of its subviews.
138
+ final class PNPortalView: UIView {
139
+ override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
140
+ for sub in subviews where !sub.isHidden && sub.alpha > 0.01 && sub.isUserInteractionEnabled {
141
+ if sub.frame.contains(point) { return true }
142
+ }
143
+ return false
144
+ }
145
+ }
146
+
147
+ /// `Portal`: floats children over the screen in a top-level overlay that
148
+ /// mirrors the screen host's root frame.
149
+ public final class PNPortalManager: PNComponentManager {
150
+ public override func makeView(props: [String: Any]) -> UIView {
151
+ let overlay = PNPortalView(frame: .zero)
152
+ overlay.backgroundColor = .clear
153
+ return overlay
154
+ }
155
+
156
+ public override func apply(view: UIView, props: [String: Any], initial: Bool) {
157
+ PNViewStyler.applyCommon(view, props)
158
+ if !initial { ensureAttached(view) }
159
+ }
160
+
161
+ public override func insertChild(parent: UIView, child: UIView, index: Int) {
162
+ ensureAttached(parent)
163
+ super.insertChild(parent: parent, child: child, index: index)
164
+ }
165
+
166
+ public override func setFrame(view: UIView, x: Double, y: Double, w: Double, h: Double) {}
167
+
168
+ public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize { .zero }
169
+
170
+ private func ensureAttached(_ overlay: UIView) {
171
+ guard let host = PNWindow.topViewController()?.view else { return }
172
+ if overlay.superview === host {
173
+ if host.subviews.last !== overlay {
174
+ host.bringSubviewToFront(overlay)
175
+ }
176
+ syncFrame(overlay, host: host)
177
+ return
178
+ }
179
+ overlay.removeFromSuperview()
180
+ host.addSubview(overlay)
181
+ syncFrame(overlay, host: host)
182
+ }
183
+
184
+ static func rootFrame(in host: UIView) -> CGRect {
185
+ let bounds = host.bounds
186
+ let insets = host.safeAreaInsets
187
+ let w = max(0, bounds.width - insets.left - insets.right)
188
+ let h = max(0, bounds.height - insets.top)
189
+ return CGRect(x: insets.left, y: insets.top, width: w, height: h)
190
+ }
191
+
192
+ private func syncFrame(_ overlay: UIView, host: UIView) {
193
+ overlay.frame = PNPortalManager.rootFrame(in: host)
194
+ overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
195
+ }
196
+ }
197
+
198
+ /// Process-wide status bar state consulted by `PNViewController`.
199
+ public enum PNStatusBarState {
200
+ public static var hidden = false
201
+ public static var style: UIStatusBarStyle = .default
202
+ public static var animation: UIStatusBarAnimation = .fade
203
+
204
+ static func refresh() {
205
+ var controller = PNWindow.keyWindow()?.rootViewController
206
+ if let nav = controller as? UINavigationController { controller = nav.topViewController }
207
+ controller?.setNeedsStatusBarAppearanceUpdate()
208
+ }
209
+ }
210
+
211
+ /// `StatusBar`: a global side effect (hidden / style), no on-screen view.
212
+ public final class PNStatusBarManager: PNComponentManager {
213
+ public override func makeView(props: [String: Any]) -> UIView {
214
+ let placeholder = UIView(frame: .zero)
215
+ placeholder.isHidden = true
216
+ return placeholder
217
+ }
218
+
219
+ public override func apply(view: UIView, props: [String: Any], initial: Bool) {
220
+ if let hidden = PNProps.bool(PNProps.value(props, "hidden")) {
221
+ PNStatusBarState.hidden = hidden
222
+ }
223
+ if let style = PNProps.string(PNProps.value(props, "bar_style")) {
224
+ switch style {
225
+ case "light", "light_content": PNStatusBarState.style = .lightContent
226
+ case "dark", "dark_content": PNStatusBarState.style = .darkContent
227
+ default: PNStatusBarState.style = .default
228
+ }
229
+ }
230
+ if let animation = PNProps.string(PNProps.value(props, "animation")) {
231
+ switch animation {
232
+ case "slide": PNStatusBarState.animation = .slide
233
+ case "none": PNStatusBarState.animation = .none
234
+ default: PNStatusBarState.animation = .fade
235
+ }
236
+ }
237
+ PNStatusBarState.refresh()
238
+ }
239
+
240
+ public override func setFrame(view: UIView, x: Double, y: Double, w: Double, h: Double) {}
241
+
242
+ public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize { .zero }
243
+ }
@@ -0,0 +1,114 @@
1
+ import UIKit
2
+
3
+ /// `Pressable`: a touchable container with press feedback.
4
+ ///
5
+ /// A zero-duration long-press recognizer tracks the raw touch for
6
+ /// `on_press_in` / `on_press_out` and the pressed-opacity feedback; a tap
7
+ /// recognizer fires `on_press` and a standard long press fires
8
+ /// `on_long_press`. Hit slop and pointer events come from
9
+ /// `PNContainerView`, so hit testing is entirely UIKit's.
10
+ public final class PNPressableManager: PNComponentManager {
11
+ public override func makeView(props: [String: Any]) -> UIView {
12
+ let view = PNContainerView(frame: .zero)
13
+ view.isUserInteractionEnabled = true
14
+ return view
15
+ }
16
+
17
+ public override func createView(tag: Int64, props: [String: Any]) -> UIView {
18
+ let view = super.createView(tag: tag, props: props)
19
+ let handler = PNPressHandler(view: view)
20
+ PNViewState.existing(for: view)?.retained.append(handler)
21
+ handler.install()
22
+ return view
23
+ }
24
+
25
+ public override func apply(view: UIView, props: [String: Any], initial: Bool) {
26
+ PNViewStyler.applyCommon(view, props)
27
+ if PNProps.has(props, "disabled") {
28
+ view.isUserInteractionEnabled = !(PNProps.bool(PNProps.value(props, "disabled")) ?? false)
29
+ }
30
+ if PNProps.has(props, "disabled") {
31
+ view.isUserInteractionEnabled = !(PNProps.bool(PNProps.value(props, "disabled")) ?? false)
32
+ }
33
+ if let delay = PNProps.double(PNProps.value(props, "delay_long_press")),
34
+ let handler = PNViewState.existing(for: view)?.retained.compactMap({ $0 as? PNPressHandler }).first
35
+ {
36
+ handler.longPress.minimumPressDuration = max(0.05, delay / 1000)
37
+ }
38
+ }
39
+ }
40
+
41
+ /// Owns the three press recognizers of one Pressable.
42
+ final class PNPressHandler: NSObject, UIGestureRecognizerDelegate {
43
+ private weak var view: UIView?
44
+ let tap = UITapGestureRecognizer()
45
+ let longPress = UILongPressGestureRecognizer()
46
+ let touch = UILongPressGestureRecognizer()
47
+
48
+ init(view: UIView) {
49
+ self.view = view
50
+ super.init()
51
+ }
52
+
53
+ func install() {
54
+ guard let view = view else { return }
55
+ touch.minimumPressDuration = 0
56
+ tap.addTarget(self, action: #selector(onTap(_:)))
57
+ longPress.addTarget(self, action: #selector(onLongPress(_:)))
58
+ touch.addTarget(self, action: #selector(onTouch(_:)))
59
+ for recognizer in [tap, longPress, touch] {
60
+ recognizer.cancelsTouchesInView = false
61
+ recognizer.delegate = self
62
+ view.addGestureRecognizer(recognizer)
63
+ }
64
+ }
65
+
66
+ private var merged: [String: Any] {
67
+ view.flatMap { PNViewState.existing(for: $0)?.props } ?? [:]
68
+ }
69
+
70
+ @objc private func onTap(_ recognizer: UITapGestureRecognizer) {
71
+ guard let view = view, recognizer.state == .ended else { return }
72
+ PNEvents.emit(view, "on_press")
73
+ }
74
+
75
+ @objc private func onLongPress(_ recognizer: UILongPressGestureRecognizer) {
76
+ guard let view = view, recognizer.state == .began else { return }
77
+ PNEvents.emit(view, "on_long_press")
78
+ }
79
+
80
+ @objc private func onTouch(_ recognizer: UILongPressGestureRecognizer) {
81
+ guard let view = view else { return }
82
+ switch recognizer.state {
83
+ case .began:
84
+ feedback(pressed: true)
85
+ PNEvents.emit(view, "on_press_in")
86
+ case .ended, .cancelled, .failed:
87
+ feedback(pressed: false)
88
+ PNEvents.emit(view, "on_press_out")
89
+ default:
90
+ break
91
+ }
92
+ }
93
+
94
+ private func feedback(pressed: Bool) {
95
+ guard let view = view else { return }
96
+ let props = merged
97
+ let target: CGFloat
98
+ let duration: TimeInterval
99
+ if pressed {
100
+ target = CGFloat(PNProps.double(PNProps.value(props, "pressed_opacity")) ?? 0.6)
101
+ duration = 0.05
102
+ } else {
103
+ target = CGFloat(PNProps.double(PNProps.value(props, "opacity")) ?? 1)
104
+ duration = 0.1
105
+ }
106
+ UIView.animate(withDuration: duration) { view.alpha = target }
107
+ }
108
+
109
+ // Press recognizers recognize alongside everything, including the
110
+ // declarative `gestures` recognizers and a parent scroll view's pan.
111
+ func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith other: UIGestureRecognizer) -> Bool {
112
+ true
113
+ }
114
+ }
@@ -0,0 +1,107 @@
1
+ import UIKit
2
+
3
+ private final class PNLogicalScreen: UIView {
4
+ private var lastSize = CGSize.zero
5
+ override func layoutSubviews() {
6
+ super.layoutSubviews()
7
+ if bounds.size != lastSize {
8
+ lastSize = bounds.size
9
+ PNLayout.containerDidLayout()
10
+ }
11
+ }
12
+ }
13
+
14
+ public final class PNScreenManager: PNComponentManager {
15
+ public override func makeView(props: [String: Any]) -> UIView { PNLogicalScreen(frame: .zero) }
16
+ public override func apply(view: UIView, props: [String: Any], initial: Bool) {
17
+ if let controller = view.next as? UIViewController {
18
+ HostModule.applyOptions(PNViewState.existing(for: view)?.props ?? props, to: controller)
19
+ }
20
+ }
21
+ // UIKit owns the controller's content rectangle, including its navigation bar.
22
+ public override func setFrame(view: UIView, x: Double, y: Double, w: Double, h: Double) {}
23
+ }
24
+
25
+ private final class PNLogicalStack: UIView, UINavigationControllerDelegate {
26
+ let navigation = UINavigationController()
27
+ var controllers: [Int64: UIViewController] = [:]
28
+ var order: [Int64] = []
29
+ var applying = false
30
+ var scheduled = false
31
+ override init(frame: CGRect) {
32
+ super.init(frame: frame)
33
+ navigation.delegate = self
34
+ addSubview(navigation.view)
35
+ }
36
+ required init?(coder: NSCoder) { fatalError("init(coder:) is unavailable") }
37
+ override func didMoveToWindow() {
38
+ super.didMoveToWindow()
39
+ guard window != nil, navigation.parent == nil else { return }
40
+ var responder: UIResponder? = superview
41
+ while let current = responder {
42
+ if let parent = current as? UIViewController {
43
+ parent.addChild(navigation)
44
+ navigation.didMove(toParent: parent)
45
+ parent.navigationController?.setNavigationBarHidden(true, animated: false)
46
+ break
47
+ }
48
+ responder = current.next
49
+ }
50
+ }
51
+ override func layoutSubviews() {
52
+ super.layoutSubviews()
53
+ navigation.view.frame = bounds
54
+ }
55
+ func schedule() {
56
+ guard !scheduled else { return }
57
+ scheduled = true
58
+ DispatchQueue.main.async { [weak self] in
59
+ guard let self = self else { return }
60
+ self.scheduled = false
61
+ self.applying = true
62
+ self.navigation.setViewControllers(self.order.compactMap { self.controllers[$0] }, animated: false)
63
+ if let tag = self.order.last, let state = PNViewRegistry.shared.view(for: tag).flatMap({ PNViewState.existing(for: $0) }),
64
+ let controller = self.controllers[tag] { HostModule.applyOptions(state.props, to: controller) }
65
+ self.applying = false
66
+ }
67
+ }
68
+ func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
69
+ if !applying && navigation.viewControllers.count < order.count {
70
+ PNEvents.emit(self, "on_native_back", [order.count - navigation.viewControllers.count])
71
+ }
72
+ }
73
+ }
74
+
75
+ /// Native screen presentation without importing or remounting App.
76
+ public final class PNScreenStackManager: PNComponentManager {
77
+ public override func makeView(props: [String: Any]) -> UIView { PNLogicalStack(frame: .zero) }
78
+ public override func insertChild(parent: UIView, child: UIView, index: Int) {
79
+ guard let stack = parent as? PNLogicalStack, let state = PNViewState.existing(for: child) else { return }
80
+ let controller = stack.controllers[state.tag] ?? UIViewController()
81
+ controller.edgesForExtendedLayout = []
82
+ controller.view = child
83
+ controller.title = state.props["title"] as? String
84
+ stack.controllers[state.tag] = controller
85
+ stack.order.removeAll { $0 == state.tag }
86
+ stack.order.insert(state.tag, at: min(index, stack.order.count))
87
+ stack.schedule()
88
+ }
89
+ public override func removeChild(parent: UIView, child: UIView) {
90
+ guard let stack = parent as? PNLogicalStack, let state = PNViewState.existing(for: child) else { return }
91
+ stack.order.removeAll { $0 == state.tag }
92
+ stack.controllers.removeValue(forKey: state.tag)
93
+ stack.schedule()
94
+ }
95
+ public override func command(view: UIView, name: String, args: [String: Any]) -> Any? {
96
+ if name == "restore_stack", let stack = view as? PNLogicalStack { stack.schedule() }
97
+ return nil
98
+ }
99
+ public override func teardown(view: UIView) {
100
+ guard let stack = view as? PNLogicalStack else { return }
101
+ stack.navigation.willMove(toParent: nil)
102
+ stack.navigation.view.removeFromSuperview()
103
+ stack.navigation.removeFromParent()
104
+ stack.controllers.removeAll()
105
+ stack.navigation.delegate = nil
106
+ }
107
+ }
@@ -0,0 +1,197 @@
1
+ import UIKit
2
+
3
+ /// `ScrollView`: a `UIScrollView` wrapping one layout-engine-sized child.
4
+ ///
5
+ /// Scroll offsets are reported through `on_scroll` with
6
+ /// `{"x", "y", "extent", "range", "content_width", "content_height"}`.
7
+ /// Commands: `scroll_to_offset`, `scroll_to_end`, `get_scroll_offset`,
8
+ /// `flash_scroll_indicators`.
9
+ public final class PNScrollViewManager: PNComponentManager {
10
+ public override func makeView(props: [String: Any]) -> UIView {
11
+ let scroll = UIScrollView(frame: .zero)
12
+ scroll.contentInsetAdjustmentBehavior = .never
13
+ return scroll
14
+ }
15
+
16
+ public override func createView(tag: Int64, props: [String: Any]) -> UIView {
17
+ let view = super.createView(tag: tag, props: props)
18
+ if let scroll = view as? UIScrollView {
19
+ let delegate = PNScrollDelegate()
20
+ scroll.delegate = delegate
21
+ PNViewState.existing(for: scroll)?.retained.append(delegate)
22
+ }
23
+ return view
24
+ }
25
+
26
+ public override func apply(view: UIView, props: [String: Any], initial: Bool) {
27
+ guard let scroll = view as? UIScrollView else { return }
28
+ PNViewStyler.applyCommon(scroll, props)
29
+ if PNProps.has(props, "refresh_control") {
30
+ applyRefresh(scroll, PNProps.value(props, "refresh_control"))
31
+ }
32
+ if PNProps.has(props, "shows_scroll_indicator") {
33
+ let visible = PNProps.bool(PNProps.value(props, "shows_scroll_indicator")) ?? true
34
+ scroll.showsVerticalScrollIndicator = visible
35
+ scroll.showsHorizontalScrollIndicator = visible
36
+ }
37
+ if PNProps.has(props, "paging_enabled") {
38
+ scroll.isPagingEnabled = PNProps.bool(PNProps.value(props, "paging_enabled")) ?? false
39
+ }
40
+ if PNProps.has(props, "bounces") {
41
+ scroll.bounces = PNProps.bool(PNProps.value(props, "bounces")) ?? true
42
+ }
43
+ if PNProps.has(props, "scroll_enabled") {
44
+ scroll.isScrollEnabled = PNProps.bool(PNProps.value(props, "scroll_enabled")) ?? true
45
+ }
46
+ if PNProps.has(props, "horizontal") {
47
+ let horizontal = PNProps.bool(PNProps.value(props, "horizontal")) ?? false
48
+ scroll.alwaysBounceHorizontal = horizontal
49
+ scroll.alwaysBounceVertical = !horizontal && scroll.refreshControl != nil
50
+ }
51
+ if let mode = PNProps.string(PNProps.value(props, "keyboard_dismiss_mode")) {
52
+ switch mode {
53
+ case "on_drag": scroll.keyboardDismissMode = .onDrag
54
+ case "interactive": scroll.keyboardDismissMode = .interactive
55
+ default: scroll.keyboardDismissMode = .none
56
+ }
57
+ }
58
+ if PNProps.has(props, "content_inset") {
59
+ let inset = PNProps.dict(PNProps.value(props, "content_inset")) ?? [:]
60
+ scroll.contentInset = UIEdgeInsets(
61
+ top: CGFloat(PNProps.double(inset["top"]) ?? 0), left: CGFloat(PNProps.double(inset["left"]) ?? 0),
62
+ bottom: CGFloat(PNProps.double(inset["bottom"]) ?? 0), right: CGFloat(PNProps.double(inset["right"]) ?? 0)
63
+ )
64
+ }
65
+ if PNProps.has(props, "scroll_indicator_insets") {
66
+ let inset = PNProps.dict(PNProps.value(props, "scroll_indicator_insets")) ?? [:]
67
+ let insets = UIEdgeInsets(
68
+ top: CGFloat(PNProps.double(inset["top"]) ?? 0), left: CGFloat(PNProps.double(inset["left"]) ?? 0),
69
+ bottom: CGFloat(PNProps.double(inset["bottom"]) ?? 0), right: CGFloat(PNProps.double(inset["right"]) ?? 0)
70
+ )
71
+ scroll.verticalScrollIndicatorInsets = insets
72
+ scroll.horizontalScrollIndicatorInsets = insets
73
+ }
74
+ if PNProps.has(props, "scroll_event_throttle") {
75
+ PNViewState.existing(for: scroll)?.extras["throttle"] = PNProps.double(PNProps.value(props, "scroll_event_throttle")) ?? 0
76
+ }
77
+ }
78
+
79
+ public override func command(view: UIView, name: String, args: [String: Any]) -> Any? {
80
+ guard let scroll = view as? UIScrollView else { return nil }
81
+ let animated = PNProps.bool(args["animated"]) ?? true
82
+ switch name {
83
+ case "scroll_to_offset":
84
+ let x = CGFloat(PNProps.finite(args["x"]))
85
+ let y = CGFloat(PNProps.finite(args["y"]))
86
+ scroll.setContentOffset(CGPoint(x: x, y: y), animated: animated)
87
+ case "scroll_to_end":
88
+ let content = scroll.contentSize
89
+ let bounds = scroll.bounds.size
90
+ let targetY = max(0, content.height - bounds.height)
91
+ let targetX = max(0, content.width - bounds.width)
92
+ let horizontal = content.width > bounds.width && content.height <= bounds.height
93
+ scroll.setContentOffset(horizontal ? CGPoint(x: targetX, y: 0) : CGPoint(x: 0, y: targetY), animated: animated)
94
+ case "get_scroll_offset":
95
+ return ["x": Double(scroll.contentOffset.x), "y": Double(scroll.contentOffset.y)]
96
+ case "flash_scroll_indicators":
97
+ scroll.flashScrollIndicators()
98
+ default:
99
+ break
100
+ }
101
+ return nil
102
+ }
103
+
104
+ // MARK: - Refresh control
105
+
106
+ private func applyRefresh(_ scroll: UIScrollView, _ spec: Any?) {
107
+ guard let spec = spec else {
108
+ if let existing = scroll.refreshControl {
109
+ existing.endRefreshing()
110
+ scroll.refreshControl = nil
111
+ scroll.alwaysBounceVertical = false
112
+ }
113
+ return
114
+ }
115
+ let control: UIRefreshControl
116
+ if let existing = scroll.refreshControl {
117
+ control = existing
118
+ } else {
119
+ control = UIRefreshControl()
120
+ scroll.refreshControl = control
121
+ // Content that fits its bounds never engages the pan gesture
122
+ // without this, making the refresh control unreachable.
123
+ scroll.alwaysBounceVertical = true
124
+ let target = PNActionTarget { [weak scroll] in
125
+ guard let scroll = scroll else { return }
126
+ PNEvents.emit(scroll, "on_refresh")
127
+ }
128
+ control.addTarget(target, action: #selector(PNActionTarget.fire(_:forEvent:)), for: .valueChanged)
129
+ PNViewState.existing(for: scroll)?.retained.append(target)
130
+ }
131
+ let dict = spec as? [String: Any] ?? [:]
132
+ if let color = PNColor.parse(PNProps.value(dict, "tint_color") ?? PNProps.value(dict, "color")) {
133
+ control.tintColor = color
134
+ }
135
+ if let title = PNProps.string(PNProps.value(dict, "title")) {
136
+ control.attributedTitle = NSAttributedString(string: title)
137
+ }
138
+ if PNProps.bool(dict["refreshing"]) == true {
139
+ if !control.isRefreshing { control.beginRefreshing() }
140
+ } else if control.isRefreshing {
141
+ control.endRefreshing()
142
+ }
143
+ }
144
+ }
145
+
146
+ /// Shared scroll payload builder.
147
+ enum PNScrollPayload {
148
+ static func make(_ scroll: UIScrollView) -> [String: Any] {
149
+ let offset = scroll.contentOffset
150
+ let bounds = scroll.bounds.size
151
+ let content = scroll.contentSize
152
+ let horizontal = content.width > bounds.width && content.height <= bounds.height
153
+ return [
154
+ "x": Double(offset.x),
155
+ "y": Double(offset.y),
156
+ "extent": Double(horizontal ? bounds.width : bounds.height),
157
+ "range": Double(horizontal ? content.width : content.height),
158
+ "content_width": Double(content.width),
159
+ "content_height": Double(content.height),
160
+ "width": Double(bounds.width),
161
+ "height": Double(bounds.height),
162
+ ]
163
+ }
164
+ }
165
+
166
+ /// Forwards `UIScrollViewDelegate` callbacks to Python events.
167
+ final class PNScrollDelegate: NSObject, UIScrollViewDelegate {
168
+ private var lastEmit: TimeInterval = 0
169
+
170
+ func scrollViewDidScroll(_ scrollView: UIScrollView) {
171
+ guard let state = PNViewState.existing(for: scrollView), state.hasEvent("on_scroll") else { return }
172
+ let throttle = (state.extras["throttle"] as? Double ?? 0) / 1000
173
+ let now = CACurrentMediaTime()
174
+ if throttle > 0, now - lastEmit < throttle, scrollView.isDragging || scrollView.isDecelerating { return }
175
+ lastEmit = now
176
+ PNEvents.emit(scrollView, "on_scroll", [PNScrollPayload.make(scrollView)])
177
+ }
178
+
179
+ func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
180
+ PNEvents.emitIfWired(scrollView, "on_scroll_begin_drag", [PNScrollPayload.make(scrollView)])
181
+ }
182
+
183
+ func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
184
+ PNEvents.emitIfWired(scrollView, "on_scroll_end_drag", [PNScrollPayload.make(scrollView)])
185
+ if !decelerate {
186
+ PNEvents.emitIfWired(scrollView, "on_momentum_scroll_end", [PNScrollPayload.make(scrollView)])
187
+ }
188
+ }
189
+
190
+ func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
191
+ PNEvents.emitIfWired(scrollView, "on_momentum_scroll_end", [PNScrollPayload.make(scrollView)])
192
+ }
193
+
194
+ func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
195
+ PNEvents.emitIfWired(scrollView, "on_scroll", [PNScrollPayload.make(scrollView)])
196
+ }
197
+ }