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,171 @@
1
+ """Native build fingerprints: know when ``pn run`` can skip the toolchain.
2
+
3
+ A debug build only has to be rebuilt when one of its *native inputs*
4
+ changes: ``pythonnative.toml``, the bundled native template, the
5
+ ``pythonnative`` package itself, project-local native plugins, or the
6
+ build flavor (platform, SDK, release). Edits under ``app/`` don't count;
7
+ the dev server syncs those into the running app and Fast Refresh applies
8
+ them, exactly as Metro does for a React Native debug build.
9
+
10
+ [`compute`][pythonnative.project.fingerprint.compute] hashes those
11
+ inputs into one hex digest. ``pn run`` writes it next to the build
12
+ after a successful toolchain run (see
13
+ [`write_stamp`][pythonnative.project.fingerprint.write_stamp]) and, when
14
+ the digest is unchanged and a dev server is running to deliver the
15
+ latest sources, reinstalls the previous artifact instead of staging and
16
+ compiling again.
17
+
18
+ The hash covers file *contents*, not mtimes, so touching a file or
19
+ re-cloning the repository doesn't invalidate a build.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import hashlib
25
+ import json
26
+ import os
27
+ import sys
28
+ from pathlib import Path
29
+ from typing import Dict, Iterable, Optional, Sequence
30
+
31
+ from .config import CONFIG_FILENAME, AppConfig
32
+
33
+ __all__ = ["STAMP_NAME", "compute", "hash_tree", "read_stamp", "write_stamp"]
34
+
35
+ STAMP_NAME = ".pn-native-fingerprint.json"
36
+ """File written into ``build/<platform>/`` after a successful native build."""
37
+
38
+ _IGNORED_DIRS = {
39
+ "__pycache__",
40
+ ".git",
41
+ ".gradle",
42
+ ".build",
43
+ ".swiftpm",
44
+ "build",
45
+ "DerivedData",
46
+ "xcuserdata",
47
+ "node_modules",
48
+ ".venv",
49
+ }
50
+ _IGNORED_SUFFIXES = (".pyc", ".pyo", ".DS_Store")
51
+
52
+
53
+ def hash_tree(root: Path, *, into: Optional["hashlib._Hash"] = None) -> str:
54
+ """Hash every file under ``root`` (relative path + contents), deterministically.
55
+
56
+ Build outputs, caches, and bytecode are skipped so a checkout that
57
+ has been built hashes the same as a fresh one.
58
+
59
+ Args:
60
+ root: Directory (or single file) to hash. A missing path hashes
61
+ as the empty tree.
62
+ into: An existing hasher to feed instead of creating one.
63
+
64
+ Returns:
65
+ The hex digest (of ``into`` when given).
66
+ """
67
+ hasher = into or hashlib.sha256()
68
+ if root.is_file():
69
+ _feed_file(hasher, root.name, root)
70
+ return hasher.hexdigest()
71
+ if not root.is_dir():
72
+ return hasher.hexdigest()
73
+ for dirpath, dirnames, filenames in os.walk(root):
74
+ dirnames[:] = sorted(d for d in dirnames if d not in _IGNORED_DIRS and not d.startswith("."))
75
+ for name in sorted(filenames):
76
+ if name.endswith(_IGNORED_SUFFIXES):
77
+ continue
78
+ path = Path(dirpath) / name
79
+ if path.is_symlink() and not path.exists():
80
+ continue
81
+ _feed_file(hasher, str(path.relative_to(root)).replace(os.sep, "/"), path)
82
+ return hasher.hexdigest()
83
+
84
+
85
+ def _feed_file(hasher: "hashlib._Hash", rel: str, path: Path) -> None:
86
+ hasher.update(rel.encode("utf-8"))
87
+ hasher.update(b"\0")
88
+ try:
89
+ with open(path, "rb") as handle:
90
+ for chunk in iter(lambda: handle.read(1 << 16), b""):
91
+ hasher.update(chunk)
92
+ except OSError:
93
+ hasher.update(b"<unreadable>")
94
+ hasher.update(b"\0")
95
+
96
+
97
+ def compute(
98
+ config: AppConfig,
99
+ platform: str,
100
+ *,
101
+ template_root: Path,
102
+ lib_root: Path,
103
+ release: bool = False,
104
+ ios_sdks: Sequence[str] = (),
105
+ extra: Optional[Dict[str, str]] = None,
106
+ ) -> str:
107
+ """Digest every native input of a build.
108
+
109
+ Args:
110
+ config: The loaded project configuration (its file is hashed).
111
+ platform: ``"android"`` or ``"ios"``.
112
+ template_root: The bundled native template directory.
113
+ lib_root: The ``pythonnative`` package directory that gets bundled.
114
+ release: Release builds are distinct from debug builds.
115
+ ios_sdks: The iOS SDK slices being staged.
116
+ extra: Additional key/value inputs (host arch, tool versions).
117
+
118
+ Returns:
119
+ A hex SHA-256 digest.
120
+ """
121
+ hasher = hashlib.sha256()
122
+ header = {
123
+ "platform": platform,
124
+ "release": bool(release),
125
+ "ios_sdks": sorted(ios_sdks),
126
+ "python": f"{sys.version_info[0]}.{sys.version_info[1]}",
127
+ "extra": dict(sorted((extra or {}).items())),
128
+ }
129
+ hasher.update(json.dumps(header, sort_keys=True).encode("utf-8"))
130
+ hasher.update(b"\0config\0")
131
+ hash_tree(config.project_root / CONFIG_FILENAME, into=hasher)
132
+ hasher.update(b"\0template\0")
133
+ hash_tree(template_root, into=hasher)
134
+ hasher.update(b"\0lib\0")
135
+ hash_tree(lib_root, into=hasher)
136
+ hash_tree(config.project_root / "pn.lock", into=hasher)
137
+ for plugin_path in _plugin_paths(config):
138
+ hasher.update(b"\0plugin:" + str(plugin_path).encode("utf-8") + b"\0")
139
+ hash_tree(plugin_path, into=hasher)
140
+ return hasher.hexdigest()
141
+
142
+
143
+ def _plugin_paths(config: AppConfig) -> Iterable[Path]:
144
+ for raw in getattr(config, "plugin_paths", ()) or ():
145
+ try:
146
+ yield config.resolve_path(raw)
147
+ except Exception:
148
+ continue
149
+
150
+
151
+ def read_stamp(build_dir: Path) -> Optional[Dict[str, str]]:
152
+ """Return the stamp written by the last successful build, or ``None``."""
153
+ path = build_dir / STAMP_NAME
154
+ try:
155
+ with open(path, "r", encoding="utf-8") as handle:
156
+ data = json.load(handle)
157
+ except (OSError, ValueError):
158
+ return None
159
+ if not isinstance(data, dict) or "fingerprint" not in data:
160
+ return None
161
+ return {str(k): str(v) for k, v in data.items()}
162
+
163
+
164
+ def write_stamp(build_dir: Path, fingerprint: str, *, artifact: Optional[Path] = None) -> None:
165
+ """Record ``fingerprint`` (and the artifact it produced) for the next ``pn run``."""
166
+ build_dir.mkdir(parents=True, exist_ok=True)
167
+ payload: Dict[str, str] = {"fingerprint": fingerprint}
168
+ if artifact is not None:
169
+ payload["artifact"] = str(artifact)
170
+ with open(build_dir / STAMP_NAME, "w", encoding="utf-8") as handle:
171
+ json.dump(payload, handle, indent=2)
@@ -0,0 +1,247 @@
1
+ """App icon and splash image generation.
2
+
3
+ Given a single high-resolution source image per asset (a 1024x1024 icon
4
+ and an optional splash image), this module renders the per-platform,
5
+ per-density variants each toolchain expects:
6
+
7
+ - iOS: a single-size ``AppIcon.appiconset`` (Xcode resizes at build time)
8
+ and a ``Splash`` image set referenced by the generated launch screen.
9
+ - Android: ``mipmap-*`` launcher PNGs at every density (mdpi…xxxhdpi),
10
+ a circular round-icon variant, and a centered splash icon used by the
11
+ Android 12+ splash screen.
12
+
13
+ Image resizing uses [Pillow](https://python-pillow.org/), declared as the
14
+ ``[build]`` optional dependency. When Pillow isn't installed every
15
+ function degrades gracefully: it returns ``False`` (and the caller keeps
16
+ the template's default assets) so a missing optional dependency never
17
+ breaks a build. ``pn doctor`` reports whether Pillow is available.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import os
24
+ import shutil
25
+ from pathlib import Path
26
+ from typing import Dict, List, Optional, Tuple
27
+
28
+ # Android launcher icon sizes (px) per density bucket.
29
+ ANDROID_LAUNCHER_DENSITIES: Dict[str, int] = {
30
+ "mdpi": 48,
31
+ "hdpi": 72,
32
+ "xhdpi": 96,
33
+ "xxhdpi": 144,
34
+ "xxxhdpi": 192,
35
+ }
36
+
37
+
38
+ def pillow_available() -> bool:
39
+ """Return whether Pillow can be imported.
40
+
41
+ Returns:
42
+ ``True`` if ``PIL.Image`` imports, else ``False``.
43
+ """
44
+ try:
45
+ import PIL.Image # noqa: F401
46
+ except Exception:
47
+ return False
48
+ return True
49
+
50
+
51
+ def _open_rgba(source: Path) -> "object":
52
+ from PIL import Image
53
+
54
+ img = Image.open(source).convert("RGBA")
55
+ return img
56
+
57
+
58
+ def _resized(img: "object", size: int) -> "object":
59
+ from PIL import Image
60
+
61
+ return img.resize((size, size), Image.LANCZOS)
62
+
63
+
64
+ def _circular(img: "object") -> "object":
65
+ """Return a copy of a square image masked to a circle."""
66
+ from PIL import Image, ImageDraw
67
+
68
+ size = img.size[0]
69
+ mask = Image.new("L", (size, size), 0)
70
+ draw = ImageDraw.Draw(mask)
71
+ draw.ellipse((0, 0, size, size), fill=255)
72
+ out = Image.new("RGBA", (size, size), (0, 0, 0, 0))
73
+ out.paste(img, (0, 0), mask) # type: ignore[arg-type]
74
+ return out
75
+
76
+
77
+ def generate_ios_icons(source: Path, appiconset_dir: Path) -> bool:
78
+ """Generate a single-size iOS ``AppIcon.appiconset``.
79
+
80
+ Writes ``icon-1024.png`` (a flattened, opaque 1024x1024 image; the
81
+ App Store rejects icons with alpha) and a ``Contents.json`` that
82
+ declares it as the universal iOS app icon. Xcode derives every other
83
+ size at build time.
84
+
85
+ Args:
86
+ source: Path to the source icon image.
87
+ appiconset_dir: The ``AppIcon.appiconset`` directory to populate.
88
+
89
+ Returns:
90
+ ``True`` if icons were written, ``False`` if Pillow is missing.
91
+ """
92
+ if not pillow_available():
93
+ return False
94
+ from PIL import Image
95
+
96
+ appiconset_dir.mkdir(parents=True, exist_ok=True)
97
+ img = _open_rgba(source)
98
+ icon = _resized(img, 1024)
99
+ flattened = Image.new("RGB", (1024, 1024), (255, 255, 255))
100
+ flattened.paste(icon, (0, 0), icon) # type: ignore[arg-type]
101
+ flattened.save(appiconset_dir / "icon-1024.png", format="PNG")
102
+
103
+ contents = {
104
+ "images": [
105
+ {
106
+ "idiom": "universal",
107
+ "platform": "ios",
108
+ "size": "1024x1024",
109
+ "filename": "icon-1024.png",
110
+ }
111
+ ],
112
+ "info": {"author": "pythonnative", "version": 1},
113
+ }
114
+ (appiconset_dir / "Contents.json").write_text(json.dumps(contents, indent=2) + "\n", encoding="utf-8")
115
+ return True
116
+
117
+
118
+ def generate_android_icons(source: Path, res_dir: Path) -> bool:
119
+ """Generate Android launcher icons at every density.
120
+
121
+ Writes ``mipmap-<density>/ic_launcher.png`` and a circular
122
+ ``ic_launcher_round.png`` for each density bucket, and removes the
123
+ adaptive ``mipmap-anydpi-v26`` definitions so the generated PNGs are
124
+ used directly (otherwise the template's vector adaptive icon would
125
+ win on API 26+).
126
+
127
+ Args:
128
+ source: Path to the source icon image.
129
+ res_dir: The Android ``res`` directory.
130
+
131
+ Returns:
132
+ ``True`` if icons were written, ``False`` if Pillow is missing.
133
+ """
134
+ if not pillow_available():
135
+ return False
136
+
137
+ img = _open_rgba(source)
138
+ for density, size in ANDROID_LAUNCHER_DENSITIES.items():
139
+ mip_dir = res_dir / f"mipmap-{density}"
140
+ mip_dir.mkdir(parents=True, exist_ok=True)
141
+ square = _resized(img, size)
142
+ square.save(mip_dir / "ic_launcher.png", format="PNG")
143
+ round_icon = _circular(square)
144
+ round_icon.save(mip_dir / "ic_launcher_round.png", format="PNG")
145
+
146
+ # Drop adaptive XML icons so the raster mipmaps above are authoritative.
147
+ anydpi = res_dir / "mipmap-anydpi-v26"
148
+ if anydpi.is_dir():
149
+ shutil.rmtree(anydpi, ignore_errors=True)
150
+ return True
151
+
152
+
153
+ def generate_ios_splash(source: Path, imageset_dir: Path) -> bool:
154
+ """Generate an iOS ``Splash`` image set from a source image.
155
+
156
+ Args:
157
+ source: Path to the splash image.
158
+ imageset_dir: The ``Splash.imageset`` directory to populate.
159
+
160
+ Returns:
161
+ ``True`` if the image set was written, ``False`` if Pillow is
162
+ missing.
163
+ """
164
+ if not pillow_available():
165
+ return False
166
+
167
+ imageset_dir.mkdir(parents=True, exist_ok=True)
168
+ img = _open_rgba(source)
169
+ img.save(imageset_dir / "splash.png", format="PNG")
170
+ contents = {
171
+ "images": [{"idiom": "universal", "filename": "splash.png"}],
172
+ "info": {"author": "pythonnative", "version": 1},
173
+ }
174
+ (imageset_dir / "Contents.json").write_text(json.dumps(contents, indent=2) + "\n", encoding="utf-8")
175
+ return True
176
+
177
+
178
+ def generate_android_splash_icon(source: Path, dest: Path, size: int = 288) -> bool:
179
+ """Render the centered icon used by the Android 12+ splash screen.
180
+
181
+ The Android splash screen draws this image centered on the splash
182
+ background color. A transparent square is recommended; the default
183
+ size (288 dp at xxxhdpi → ~864 px) matches Google's guidance.
184
+
185
+ Args:
186
+ source: Path to the source splash (or icon) image.
187
+ dest: Destination PNG path.
188
+ size: Output edge length in pixels.
189
+
190
+ Returns:
191
+ ``True`` if the image was written, ``False`` if Pillow is missing.
192
+ """
193
+ if not pillow_available():
194
+ return False
195
+
196
+ dest.parent.mkdir(parents=True, exist_ok=True)
197
+ img = _open_rgba(source)
198
+ _resized(img, size).save(dest, format="PNG")
199
+ return True
200
+
201
+
202
+ def dominant_background_color(source: Path) -> Optional[str]:
203
+ """Best-effort estimate of a splash background color from an image.
204
+
205
+ Samples the image's corner pixels and returns the most common one as
206
+ a ``#RRGGBB`` hex string. Used as a default splash background when the
207
+ config doesn't specify one.
208
+
209
+ Args:
210
+ source: Path to the splash image.
211
+
212
+ Returns:
213
+ A hex color string, or ``None`` if Pillow is missing or the
214
+ sampling fails.
215
+ """
216
+ if not pillow_available():
217
+ return None
218
+ try:
219
+ img = _open_rgba(source)
220
+ width, height = img.size
221
+ corners: List[Tuple[int, int]] = [
222
+ (0, 0),
223
+ (width - 1, 0),
224
+ (0, height - 1),
225
+ (width - 1, height - 1),
226
+ ]
227
+ counts: Dict[Tuple[int, int, int], int] = {}
228
+ for x, y in corners:
229
+ r, g, b, _a = img.getpixel((x, y))
230
+ key = (r, g, b)
231
+ counts[key] = counts.get(key, 0) + 1
232
+ r, g, b = max(counts, key=lambda k: counts[k])
233
+ return f"#{r:02X}{g:02X}{b:02X}"
234
+ except Exception:
235
+ return None
236
+
237
+
238
+ def has_source(path: Optional[Path]) -> bool:
239
+ """Return whether ``path`` is a readable existing file.
240
+
241
+ Args:
242
+ path: A candidate asset path, or ``None``.
243
+
244
+ Returns:
245
+ ``True`` when the path is a file that exists on disk.
246
+ """
247
+ return bool(path and os.path.isfile(path))