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,557 @@
1
+ """Config-driven Android project configurator.
2
+
3
+ Turns the bundled ``android_template`` into a concrete, buildable Gradle
4
+ project for a specific [`AppConfig`][pythonnative.project.config.AppConfig]:
5
+
6
+ - **Package relocation.** The template lives under
7
+ ``com.pythonnative.android_template``; this module rewrites and moves
8
+ it to the app's own ``application_id`` so each app ships a distinct
9
+ package. The PythonNative Android runtime resolves its helper classes
10
+ (``Navigator``) via ``getPackageName()``, so the relocation needs no
11
+ runtime configuration.
12
+ - **Identity & SDKs.** ``applicationId``, ``versionCode``/``versionName``,
13
+ ``minSdk``/``targetSdk``/``compileSdk``, ABI filters, and the embedded
14
+ CPython version are written into ``app/build.gradle``.
15
+ - **Permissions.** ``<uses-permission>`` entries (derived from
16
+ ``[permissions]``) and the launch orientation are written into
17
+ ``AndroidManifest.xml``.
18
+ - **Signing.** A release ``signingConfig`` is injected when a keystore is
19
+ configured (passwords are read from the environment at build time).
20
+ - **Branding.** Launcher icons and an Android 12+ splash screen are
21
+ generated from the configured assets.
22
+ - **Python sources.** The user's ``app/`` and (in a dev checkout) the
23
+ in-repo ``pythonnative`` package are staged into Chaquopy's source set,
24
+ and ``requirements.txt`` is generated from ``[requirements].packages``.
25
+
26
+ Everything here is plain file manipulation, which keeps it fully unit
27
+ testable without an Android toolchain.
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ import os
33
+ import re
34
+ import shutil
35
+ from dataclasses import dataclass
36
+ from pathlib import Path
37
+ from typing import Callable, List, Optional
38
+
39
+ from . import icons
40
+ from .config import AppConfig
41
+
42
+ TEMPLATE_PACKAGE = "com.pythonnative.android_template"
43
+ """The fixed package the bundled Android template ships under."""
44
+
45
+ TEXT_SUFFIXES = {".kt", ".java", ".gradle", ".xml", ".pro", ".properties", ".cfg"}
46
+
47
+ _SOURCE_ROOTS = (
48
+ ("app", "src", "main", "java"),
49
+ ("app", "src", "test", "java"),
50
+ ("app", "src", "androidTest", "java"),
51
+ )
52
+
53
+ Logger = Callable[[str], None]
54
+
55
+
56
+ @dataclass
57
+ class AndroidLayout:
58
+ """Resolved paths within a configured Android project.
59
+
60
+ Attributes:
61
+ project_dir: The Gradle project root (``.../android_template``).
62
+ application_id: The final Android application id.
63
+ python_root: Chaquopy Python source root
64
+ (``app/src/main/python``).
65
+ """
66
+
67
+ project_dir: Path
68
+ application_id: str
69
+ python_root: Path
70
+
71
+
72
+ def configure(
73
+ project_dir: Path,
74
+ config: AppConfig,
75
+ *,
76
+ dev_lib_root: Optional[Path] = None,
77
+ release: bool = False,
78
+ log: Optional[Logger] = None,
79
+ ) -> AndroidLayout:
80
+ """Fully configure a staged Android template for ``config``.
81
+
82
+ Args:
83
+ project_dir: The staged ``android_template`` directory.
84
+ config: The validated app configuration.
85
+ dev_lib_root: Path to an in-repo ``pythonnative`` package to
86
+ bundle (dev checkout); ``None`` to rely on the PyPI install.
87
+ release: Ship bytecode only (Chaquopy ``pyc.src``). Debug builds
88
+ keep the ``.py`` sources in the APK so tracebacks show code
89
+ and the dev client can tell what the app already runs.
90
+ log: Optional progress logger.
91
+
92
+ Returns:
93
+ An [`AndroidLayout`][pythonnative.project.android.AndroidLayout]
94
+ describing the configured project.
95
+ """
96
+ emit: Logger = log or (lambda _message: None)
97
+ project_dir = Path(project_dir)
98
+
99
+ relocate_package(project_dir, TEMPLATE_PACKAGE, config.application_id)
100
+ configure_gradle(project_dir, config, release=release)
101
+ configure_settings_gradle(project_dir, config)
102
+ configure_strings(project_dir, config)
103
+ configure_manifest(project_dir, config)
104
+ write_requirements(project_dir, config)
105
+
106
+ _apply_branding(project_dir, config, emit)
107
+
108
+ python_root = stage_python_sources(project_dir, config, dev_lib_root=dev_lib_root)
109
+ emit(f"Configured Android project ({config.application_id}).")
110
+ return AndroidLayout(project_dir=project_dir, application_id=config.application_id, python_root=python_root)
111
+
112
+
113
+ # ======================================================================
114
+ # Package relocation
115
+ # ======================================================================
116
+
117
+
118
+ def relocate_package(project_dir: Path, old_package: str, new_package: str) -> None:
119
+ """Rewrite and move the template's Java/Kotlin package.
120
+
121
+ Replaces every occurrence of ``old_package`` with ``new_package`` in
122
+ all text sources, then moves the source directories from the old
123
+ package path to the new one. A no-op when the packages are equal.
124
+
125
+ Args:
126
+ project_dir: The staged Android project root.
127
+ old_package: The dotted package currently in the template.
128
+ new_package: The desired dotted package (the app's id).
129
+ """
130
+ if old_package == new_package:
131
+ return
132
+
133
+ _replace_in_tree(project_dir, old_package, new_package)
134
+
135
+ old_rel = old_package.replace(".", os.sep)
136
+ new_rel = new_package.replace(".", os.sep)
137
+ for parts in _SOURCE_ROOTS:
138
+ source_root = project_dir.joinpath(*parts)
139
+ old_dir = source_root / old_rel
140
+ if not old_dir.is_dir():
141
+ continue
142
+ new_dir = source_root / new_rel
143
+ new_dir.mkdir(parents=True, exist_ok=True)
144
+ for entry in old_dir.iterdir():
145
+ shutil.move(str(entry), str(new_dir / entry.name))
146
+ _prune_empty_dirs(source_root, old_rel)
147
+
148
+
149
+ def _replace_in_tree(root: Path, needle: str, replacement: str) -> None:
150
+ for path in root.rglob("*"):
151
+ if not path.is_file() or path.suffix not in TEXT_SUFFIXES:
152
+ continue
153
+ try:
154
+ text = path.read_text(encoding="utf-8")
155
+ except (UnicodeDecodeError, OSError):
156
+ continue
157
+ if needle in text:
158
+ path.write_text(text.replace(needle, replacement), encoding="utf-8")
159
+
160
+
161
+ def _prune_empty_dirs(source_root: Path, relative: str) -> None:
162
+ current = source_root / relative
163
+ while current != source_root and current.is_dir() and not any(current.iterdir()):
164
+ current.rmdir()
165
+ current = current.parent
166
+
167
+
168
+ # ======================================================================
169
+ # Gradle / manifest / resources
170
+ # ======================================================================
171
+
172
+
173
+ def configure_gradle(project_dir: Path, config: AppConfig, *, release: bool = False) -> None:
174
+ """Write identity, SDK levels, ABIs, Python version, bytecode policy, and signing.
175
+
176
+ Args:
177
+ project_dir: The staged Android project root.
178
+ config: The validated app configuration.
179
+ release: Compile app sources to bytecode and drop the ``.py``
180
+ files from the APK (Chaquopy's default). Debug builds keep
181
+ them, for tracebacks with source lines and for the dev
182
+ client's overlay seeding.
183
+ """
184
+ gradle_path = project_dir / "app" / "build.gradle"
185
+ content = gradle_path.read_text(encoding="utf-8")
186
+
187
+ content = re.sub(r"src\s+(true|false)", f"src {'true' if release else 'false'}", content, count=1)
188
+
189
+ content = re.sub(r"versionCode\s+\d+", f"versionCode {config.build}", content)
190
+ content = re.sub(r'versionName\s+"[^"]*"', f'versionName "{config.version}"', content)
191
+ content = re.sub(r"minSdk\s+\d+", f"minSdk {config.android.min_sdk}", content)
192
+ content = re.sub(r"targetSdk\s+\d+", f"targetSdk {config.android.target_sdk}", content)
193
+ content = re.sub(r"compileSdk\s+\d+", f"compileSdk {config.android.compile_sdk}", content)
194
+ content = re.sub(r'version\s+"3\.\d+"', f'version "{config.python_version}"', content)
195
+
196
+ abi_csv = ", ".join(f'"{abi}"' for abi in config.android.abi_filters)
197
+ content = re.sub(r"abiFilters[^\n]*", f"abiFilters {abi_csv}", content)
198
+
199
+ if config.extra_index_urls:
200
+ content = _inject_pip_options(content, config)
201
+
202
+ if config.android.signing.is_configured:
203
+ content = _inject_signing(content, config)
204
+
205
+ gradle_path.write_text(content, encoding="utf-8")
206
+
207
+
208
+ def _inject_pip_options(content: str, config: AppConfig) -> str:
209
+ """Add ``--extra-index-url`` pip options for ``[requirements].extra_index_urls``.
210
+
211
+ Chaquopy runs pip at Gradle build time; ``options`` lines inside the
212
+ ``pip { }`` block are passed straight through, so a private index
213
+ declared once in ``pythonnative.toml`` applies to Android too.
214
+ """
215
+ marker = ' install "-r", "requirements.txt"'
216
+ if marker not in content:
217
+ return content
218
+ lines = "".join(
219
+ f' options "--extra-index-url", "{_gradle_escape(url)}"\n' for url in config.extra_index_urls
220
+ )
221
+ return content.replace(marker, lines + marker, 1)
222
+
223
+
224
+ def _gradle_escape(value: str) -> str:
225
+ return value.replace("\\", "\\\\").replace('"', '\\"')
226
+
227
+
228
+ def _inject_signing(content: str, config: AppConfig) -> str:
229
+ signing = config.android.signing
230
+ assert signing.keystore is not None and signing.key_alias is not None
231
+ keystore_path = config.resolve_path(signing.keystore).as_posix()
232
+ block = (
233
+ " signingConfigs {\n"
234
+ " release {\n"
235
+ f" storeFile file('{keystore_path}')\n"
236
+ f' storePassword System.getenv("{signing.store_password_env}")\n'
237
+ f" keyAlias '{signing.key_alias}'\n"
238
+ f' keyPassword System.getenv("{signing.key_password_env}")\n'
239
+ " }\n"
240
+ " }\n"
241
+ )
242
+ if "signingConfigs {" not in content:
243
+ content = content.replace(" buildTypes {", block + " buildTypes {", 1)
244
+ if "signingConfig signingConfigs.release" not in content:
245
+ content = content.replace(
246
+ " release {\n minifyEnabled false",
247
+ " release {\n signingConfig signingConfigs.release\n minifyEnabled false",
248
+ 1,
249
+ )
250
+ return content
251
+
252
+
253
+ def configure_settings_gradle(project_dir: Path, config: AppConfig) -> None:
254
+ """Update ``rootProject.name`` to the configured project name.
255
+
256
+ Args:
257
+ project_dir: The staged Android project root.
258
+ config: The validated app configuration.
259
+ """
260
+ settings_path = project_dir / "settings.gradle"
261
+ if not settings_path.is_file():
262
+ return
263
+ content = settings_path.read_text(encoding="utf-8")
264
+ safe_name = re.sub(r"[^A-Za-z0-9_]", "_", config.name) or "app"
265
+ content = re.sub(r'rootProject\.name\s*=\s*"[^"]*"', f'rootProject.name = "{safe_name}"', content)
266
+ settings_path.write_text(content, encoding="utf-8")
267
+
268
+
269
+ def configure_strings(project_dir: Path, config: AppConfig) -> None:
270
+ """Set the ``app_name`` and ``pn_entry_module`` string resources.
271
+
272
+ Args:
273
+ project_dir: The staged Android project root.
274
+ config: The validated app configuration.
275
+ """
276
+ strings_path = project_dir / "app" / "src" / "main" / "res" / "values" / "strings.xml"
277
+ if not strings_path.is_file():
278
+ return
279
+ content = strings_path.read_text(encoding="utf-8")
280
+ escaped = _xml_escape(config.display_name)
281
+ content = re.sub(
282
+ r'(<string name="app_name">)(.*?)(</string>)',
283
+ rf"\g<1>{escaped}\g<3>",
284
+ content,
285
+ flags=re.DOTALL,
286
+ )
287
+ content = re.sub(
288
+ r'(<string name="pn_entry_module"[^>]*>)(.*?)(</string>)',
289
+ rf"\g<1>{_xml_escape(config.entry_module)}\g<3>",
290
+ content,
291
+ flags=re.DOTALL,
292
+ )
293
+ strings_path.write_text(content, encoding="utf-8")
294
+
295
+
296
+ def configure_manifest(project_dir: Path, config: AppConfig) -> None:
297
+ """Inject permissions, the launch orientation, and deep-link filters.
298
+
299
+ Args:
300
+ project_dir: The staged Android project root.
301
+ config: The validated app configuration.
302
+ """
303
+ manifest_path = project_dir / "app" / "src" / "main" / "AndroidManifest.xml"
304
+ content = manifest_path.read_text(encoding="utf-8")
305
+
306
+ permissions = config.resolved_permissions().android_permissions
307
+ if permissions:
308
+ lines = "".join(f' <uses-permission android:name="{name}" />\n' for name in permissions)
309
+ content = content.replace(" <application", f"{lines}\n <application", 1)
310
+
311
+ orientation_attr = _ANDROID_ORIENTATION.get(config.orientation)
312
+ if orientation_attr:
313
+ content = content.replace(
314
+ ' android:exported="true"',
315
+ f' android:exported="true"\n android:screenOrientation="{orientation_attr}"',
316
+ 1,
317
+ )
318
+
319
+ if config.url_schemes:
320
+ schemes = "".join(f' <data android:scheme="{scheme}" />\n' for scheme in config.url_schemes)
321
+ deep_link_filter = (
322
+ " <intent-filter>\n"
323
+ ' <action android:name="android.intent.action.VIEW" />\n'
324
+ ' <category android:name="android.intent.category.DEFAULT" />\n'
325
+ ' <category android:name="android.intent.category.BROWSABLE" />\n'
326
+ f"{schemes}"
327
+ " </intent-filter>\n"
328
+ )
329
+ content = content.replace(" </activity>", f"{deep_link_filter} </activity>", 1)
330
+
331
+ manifest_path.write_text(content, encoding="utf-8")
332
+
333
+
334
+ _ANDROID_ORIENTATION = {
335
+ "portrait": "portrait",
336
+ "landscape": "sensorLandscape",
337
+ }
338
+
339
+
340
+ def write_requirements(project_dir: Path, config: AppConfig) -> None:
341
+ """Generate ``app/requirements.txt`` from ``[requirements].packages``.
342
+
343
+ Chaquopy installs from this file (referenced by ``build.gradle``).
344
+
345
+ Args:
346
+ project_dir: The staged Android project root.
347
+ config: The validated app configuration.
348
+ """
349
+ requirements_path = project_dir / "app" / "requirements.txt"
350
+ from .deps import android_targets
351
+ from .lockfile import requirements
352
+
353
+ body = requirements(config, android_targets(config))
354
+ if body is None:
355
+ body = "\n".join(config.requirements)
356
+ requirements_path.write_text(body + ("\n" if body else ""), encoding="utf-8")
357
+
358
+
359
+ # ======================================================================
360
+ # Branding (icons + splash)
361
+ # ======================================================================
362
+
363
+
364
+ def _apply_branding(project_dir: Path, config: AppConfig, emit: Logger) -> None:
365
+ res_dir = project_dir / "app" / "src" / "main" / "res"
366
+ icon_path = config.resolve_path(config.icon) if config.icon else None
367
+ splash_path = config.resolve_path(config.splash) if config.splash else None
368
+
369
+ if icon_path and icons.has_source(icon_path):
370
+ if icons.generate_android_icons(icon_path, res_dir):
371
+ emit("Generated Android launcher icons.")
372
+ else:
373
+ emit("Skipping Android icons: Pillow not installed (pip install 'pythonnative[build]').")
374
+
375
+ if splash_path and icons.has_source(splash_path):
376
+ if icons.pillow_available():
377
+ configure_splash(project_dir, config, splash_path)
378
+ emit("Configured Android splash screen.")
379
+ else:
380
+ emit("Skipping Android splash: Pillow not installed (pip install 'pythonnative[build]').")
381
+
382
+
383
+ def configure_splash(project_dir: Path, config: AppConfig, splash_path: Path) -> None:
384
+ """Wire up an Android 12+ splash screen from the splash asset.
385
+
386
+ Adds the ``androidx.core:core-splashscreen`` dependency, a
387
+ ``Theme.App.Starting`` splash theme (with the splash background color
388
+ and centered icon), installs the splash in ``MainActivity``, and
389
+ points the launcher activity at the splash theme.
390
+
391
+ Args:
392
+ project_dir: The staged Android project root.
393
+ config: The validated app configuration.
394
+ splash_path: Path to the source splash image.
395
+ """
396
+ res_dir = project_dir / "app" / "src" / "main" / "res"
397
+ background = icons.dominant_background_color(splash_path) or "#FFFFFF"
398
+
399
+ icons.generate_android_splash_icon(splash_path, res_dir / "drawable-xxxhdpi" / "pn_splash_icon.png")
400
+
401
+ _upsert_color(res_dir / "values" / "colors.xml", "pn_splash_background", background)
402
+
403
+ splash_style = (
404
+ ' <style name="Theme.App.Starting" parent="Theme.SplashScreen">\n'
405
+ ' <item name="windowSplashScreenBackground">@color/pn_splash_background</item>\n'
406
+ ' <item name="windowSplashScreenAnimatedIcon">@drawable/pn_splash_icon</item>\n'
407
+ ' <item name="postSplashScreenTheme">@style/Theme.Android_template</item>\n'
408
+ " </style>\n"
409
+ )
410
+ for themes in (res_dir / "values" / "themes.xml", res_dir / "values-night" / "themes.xml"):
411
+ _insert_style(themes, splash_style)
412
+
413
+ _add_gradle_dependency(
414
+ project_dir / "app" / "build.gradle",
415
+ "implementation 'androidx.core:core-splashscreen:1.0.1'",
416
+ )
417
+ _install_splash_in_activity(project_dir, config)
418
+
419
+ # Point the app theme at the splash theme; ``installSplashScreen()`` swaps
420
+ # to ``postSplashScreenTheme`` (the original theme) right after launch.
421
+ manifest_path = project_dir / "app" / "src" / "main" / "AndroidManifest.xml"
422
+ manifest = manifest_path.read_text(encoding="utf-8")
423
+ manifest = manifest.replace(
424
+ 'android:theme="@style/Theme.Android_template"',
425
+ 'android:theme="@style/Theme.App.Starting"',
426
+ 1,
427
+ )
428
+ manifest_path.write_text(manifest, encoding="utf-8")
429
+
430
+
431
+ def _install_splash_in_activity(project_dir: Path, config: AppConfig) -> None:
432
+ activity = project_dir / "app" / "src" / "main" / "java" / config.android_package_path / "MainActivity.kt"
433
+ if not activity.is_file():
434
+ return
435
+ content = activity.read_text(encoding="utf-8")
436
+ if "installSplashScreen" in content:
437
+ return
438
+ content = content.replace(
439
+ "import androidx.appcompat.app.AppCompatActivity",
440
+ "import androidx.appcompat.app.AppCompatActivity\n"
441
+ "import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen",
442
+ 1,
443
+ )
444
+ content = content.replace(
445
+ " super.onCreate(savedInstanceState)",
446
+ " installSplashScreen()\n super.onCreate(savedInstanceState)",
447
+ 1,
448
+ )
449
+ activity.write_text(content, encoding="utf-8")
450
+
451
+
452
+ # ======================================================================
453
+ # Python source staging
454
+ # ======================================================================
455
+
456
+
457
+ def stage_python_sources(
458
+ project_dir: Path,
459
+ config: AppConfig,
460
+ *,
461
+ dev_lib_root: Optional[Path] = None,
462
+ ) -> Path:
463
+ """Copy the user's ``app/`` and (optionally) the in-repo library.
464
+
465
+ Args:
466
+ project_dir: The staged Android project root.
467
+ config: The validated app configuration.
468
+ dev_lib_root: Path to an in-repo ``pythonnative`` package to
469
+ bundle, or ``None``.
470
+
471
+ Returns:
472
+ The Chaquopy Python source root (``app/src/main/python``).
473
+ """
474
+ python_root = project_dir / "app" / "src" / "main" / "python"
475
+ python_root.mkdir(parents=True, exist_ok=True)
476
+
477
+ app_src = config.project_root / "app"
478
+ if app_src.is_dir():
479
+ shutil.copytree(app_src, python_root / "app", dirs_exist_ok=True)
480
+
481
+ if dev_lib_root and dev_lib_root.is_dir():
482
+ shutil.copytree(
483
+ dev_lib_root,
484
+ python_root / "pythonnative",
485
+ dirs_exist_ok=True,
486
+ ignore=LIB_IGNORE,
487
+ )
488
+
489
+ return python_root
490
+
491
+
492
+ LIB_IGNORE = shutil.ignore_patterns("templates", "native", "*.so", "__pycache__", "*.pyc", "*.pyo")
493
+ """Ignore rules for bundling the ``pythonnative`` package (skips templates)."""
494
+
495
+
496
+ # ======================================================================
497
+ # Small XML/text helpers
498
+ # ======================================================================
499
+
500
+
501
+ def _xml_escape(value: str) -> str:
502
+ return value.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
503
+
504
+
505
+ def _upsert_color(colors_path: Path, name: str, value: str) -> None:
506
+ if not colors_path.is_file():
507
+ colors_path.parent.mkdir(parents=True, exist_ok=True)
508
+ colors_path.write_text(
509
+ '<?xml version="1.0" encoding="utf-8"?>\n<resources>\n</resources>\n',
510
+ encoding="utf-8",
511
+ )
512
+ content = colors_path.read_text(encoding="utf-8")
513
+ entry = f' <color name="{name}">{value}</color>\n'
514
+ if f'name="{name}"' in content:
515
+ content = re.sub(
516
+ rf'(<color name="{re.escape(name)}">)(.*?)(</color>)',
517
+ rf"\g<1>{value}\g<3>",
518
+ content,
519
+ )
520
+ else:
521
+ content = content.replace("</resources>", f"{entry}</resources>", 1)
522
+ colors_path.write_text(content, encoding="utf-8")
523
+
524
+
525
+ def _insert_style(themes_path: Path, style_block: str) -> None:
526
+ if not themes_path.is_file():
527
+ return
528
+ content = themes_path.read_text(encoding="utf-8")
529
+ if "Theme.App.Starting" in content:
530
+ return
531
+ content = content.replace("</resources>", f"{style_block}</resources>", 1)
532
+ themes_path.write_text(content, encoding="utf-8")
533
+
534
+
535
+ def _add_gradle_dependency(gradle_path: Path, dependency: str) -> None:
536
+ content = gradle_path.read_text(encoding="utf-8")
537
+ if dependency in content:
538
+ return
539
+ content = content.replace("dependencies {\n", f"dependencies {{\n {dependency}\n", 1)
540
+ gradle_path.write_text(content, encoding="utf-8")
541
+
542
+
543
+ def collect_logcat_filters() -> List[str]:
544
+ """Return the logcat tag filters used when streaming device logs.
545
+
546
+ Returns:
547
+ A list of ``tag:level`` filter specs ending with ``*:S`` to
548
+ silence everything else.
549
+ """
550
+ return [
551
+ "python.stdout:V",
552
+ "python.stderr:V",
553
+ "PythonNative:V",
554
+ "AndroidRuntime:E",
555
+ "System.err:W",
556
+ "*:S",
557
+ ]