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,110 @@
1
+ package com.pythonnative.runtime.components
2
+
3
+ import android.content.Context
4
+ import android.os.Bundle
5
+ import android.view.LayoutInflater
6
+ import android.view.View
7
+ import android.view.ViewGroup
8
+ import android.widget.LinearLayout
9
+ import androidx.appcompat.widget.Toolbar
10
+ import androidx.fragment.app.Fragment
11
+ import androidx.fragment.app.FragmentActivity
12
+ import androidx.fragment.app.FragmentContainerView
13
+ import com.pythonnative.runtime.PNBridge
14
+ import org.json.JSONObject
15
+ import android.widget.FrameLayout
16
+ import com.pythonnative.runtime.layout.NativeLayout
17
+
18
+ class ScreenManager : ViewManager() {
19
+ override fun createView(context: Context, tag: Long, props: JSONObject): View =
20
+ super.createView(context, tag, props).apply {
21
+ layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
22
+ addOnLayoutChangeListener { _, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
23
+ if (right - left != oldRight - oldLeft || bottom - top != oldBottom - oldTop) NativeLayout.containerDidLayout()
24
+ }
25
+ }
26
+ override fun setFrame(view: View, x: Double, y: Double, width: Double, height: Double) {}
27
+ }
28
+
29
+ /** A native fragment displays an existing logical screen's view. */
30
+ class LogicalScreenFragment : Fragment() {
31
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, state: Bundle?): View {
32
+ val view = PNBridge.registry.get(requireArguments().getLong("tag"))?.view ?: View(requireContext())
33
+ (view.parent as? ViewGroup)?.removeView(view)
34
+ return view
35
+ }
36
+ }
37
+
38
+ /** One fragment stack whose Python providers and state remain application-owned. */
39
+ class ScreenStackManager : ComponentManager() {
40
+ private inner class Stack(context: Context) : LinearLayout(context) {
41
+ val toolbar = Toolbar(context)
42
+ val container = FragmentContainerView(context).apply { id = View.generateViewId() }
43
+ val screens = ArrayList<Long>()
44
+ val fragments = HashMap<Long, LogicalScreenFragment>()
45
+ var scheduled = false
46
+ init {
47
+ orientation = VERTICAL
48
+ addView(toolbar, LayoutParams(LayoutParams.MATCH_PARENT, (56 * PNBridge.density()).toInt()))
49
+ addView(container, LayoutParams(LayoutParams.MATCH_PARENT, 0, 1f))
50
+ toolbar.setNavigationOnClickListener { fire(this, "on_native_back", 1) }
51
+ }
52
+ override fun onAttachedToWindow() { super.onAttachedToWindow(); schedule() }
53
+ fun schedule() {
54
+ if (scheduled) return
55
+ scheduled = true
56
+ post {
57
+ scheduled = false
58
+ if (!isAttachedToWindow) return@post
59
+ val manager = (context as? FragmentActivity)?.supportFragmentManager ?: return@post
60
+ if (manager.isStateSaved) return@post
61
+ val transaction = manager.beginTransaction().setReorderingAllowed(true)
62
+ for ((tag, fragment) in fragments.toMap()) if (tag !in screens) {
63
+ transaction.remove(fragment)
64
+ fragments.remove(tag)
65
+ }
66
+ for (tag in screens) {
67
+ var fragment = fragments[tag]
68
+ if (fragment == null) {
69
+ fragment = LogicalScreenFragment().apply { arguments = Bundle().apply { putLong("tag", tag) } }
70
+ fragments[tag] = fragment
71
+ transaction.add(container.id, fragment, "pn-screen-$tag")
72
+ }
73
+ if (tag == screens.lastOrNull()) transaction.show(fragment) else transaction.hide(fragment)
74
+ }
75
+ transaction.commitNow()
76
+ val current = screens.lastOrNull()?.let { PNBridge.registry.get(it) }
77
+ toolbar.title = current?.props?.optString("title", "") ?: ""
78
+ toolbar.navigationIcon = if (screens.size > 1) context.getDrawable(android.R.drawable.ic_media_previous) else null
79
+ }
80
+ }
81
+ }
82
+ override fun createView(context: Context, tag: Long, props: JSONObject): View = Stack(context)
83
+ override fun insertChild(parent: View, child: View, index: Int) {
84
+ val stack = parent as Stack
85
+ val tag = PNBridge.registry.recordFor(child)?.tag ?: return
86
+ stack.screens.remove(tag)
87
+ stack.screens.add(index.coerceAtMost(stack.screens.size), tag)
88
+ stack.schedule()
89
+ }
90
+ override fun removeChild(parent: View, child: View) {
91
+ val stack = parent as Stack
92
+ PNBridge.registry.recordFor(child)?.let { stack.screens.remove(it.tag) }
93
+ stack.schedule()
94
+ }
95
+ override fun command(view: View, name: String, args: JSONObject): Any? {
96
+ if (name == "restore_stack") (view as Stack).schedule()
97
+ return null
98
+ }
99
+ override fun teardown(view: View) {
100
+ val stack = view as Stack
101
+ val manager = (view.context as? FragmentActivity)?.supportFragmentManager
102
+ if (manager != null && !manager.isDestroyed) {
103
+ val transaction = manager.beginTransaction()
104
+ for (fragment in stack.fragments.values) transaction.remove(fragment)
105
+ transaction.commitAllowingStateLoss()
106
+ }
107
+ stack.screens.clear()
108
+ stack.fragments.clear()
109
+ }
110
+ }
@@ -0,0 +1,214 @@
1
+ package com.pythonnative.runtime.components
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import android.view.MotionEvent
6
+ import android.view.View
7
+ import android.view.ViewGroup
8
+ import android.view.inputmethod.InputMethodManager
9
+ import android.widget.HorizontalScrollView
10
+ import androidx.core.widget.NestedScrollView
11
+ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
12
+ import com.pythonnative.runtime.bridge.JsonUtil
13
+ import com.pythonnative.runtime.bridge.MainThread
14
+ import com.pythonnative.runtime.bridge.obj
15
+ import com.pythonnative.runtime.bridge.str
16
+ import com.pythonnative.runtime.bridge.value
17
+ import org.json.JSONObject
18
+ import kotlin.math.max
19
+ import kotlin.math.roundToInt
20
+
21
+ /**
22
+ * `ScrollView` element: a `NestedScrollView` (vertical, always wrapped in
23
+ * a `SwipeRefreshLayout` that is enabled only while `refresh_control`
24
+ * is set) or a `HorizontalScrollView`.
25
+ *
26
+ * `on_scroll` carries `{x, y, extent, range}` in dp. Commands:
27
+ * `scroll_to_offset`, `scroll_to_end`, `get_scroll_offset`,
28
+ * `flash_scroll_indicators`.
29
+ */
30
+ class ScrollViewManager : ComponentManager() {
31
+ override fun createView(context: Context, tag: Long, props: JSONObject): View {
32
+ val horizontal = props.str("scroll_axis") == "horizontal" || JsonUtil.truthy(props.value("horizontal"))
33
+ return if (horizontal) {
34
+ val sv = HorizontalScrollView(context)
35
+ bindScrollListener(sv, sv, true)
36
+ bindTouch(sv, sv, true)
37
+ sv
38
+ } else {
39
+ val sv = NestedScrollView(context)
40
+ val wrapper = SwipeRefreshLayout(context)
41
+ wrapper.addView(sv, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
42
+ wrapper.isEnabled = false
43
+ wrapper.setOnRefreshListener { fire(wrapper, "on_refresh") }
44
+ bindScrollListener(wrapper, sv, false)
45
+ bindTouch(wrapper, sv, false)
46
+ wrapper
47
+ }
48
+ }
49
+
50
+ private fun inner(outer: View): ViewGroup = when (outer) {
51
+ is SwipeRefreshLayout -> outer.getChildAt(0) as ViewGroup
52
+ else -> outer as ViewGroup
53
+ }
54
+
55
+ private fun isHorizontal(outer: View): Boolean = outer is HorizontalScrollView
56
+
57
+ override fun applyProps(view: View, props: JSONObject, initial: Boolean) {
58
+ val sv = inner(view)
59
+ ViewStyler.apply(sv, props)
60
+ if (props.has("shows_scroll_indicator")) {
61
+ val show = props.value("shows_scroll_indicator") != false
62
+ sv.isVerticalScrollBarEnabled = show
63
+ sv.isHorizontalScrollBarEnabled = show
64
+ }
65
+ if (props.has("bounces")) {
66
+ sv.overScrollMode = if (props.value("bounces") == false) View.OVER_SCROLL_NEVER else View.OVER_SCROLL_IF_CONTENT_SCROLLS
67
+ }
68
+ if (props.has("scroll_enabled")) stateOf(view)["scroll_enabled"] = props.value("scroll_enabled") != false
69
+ if (props.has("refresh_control") && view is SwipeRefreshLayout) applyRefresh(view, props.obj("refresh_control"))
70
+ // paging_enabled and keyboard_dismiss_mode are read from merged props at touch time.
71
+ }
72
+
73
+ private fun applyRefresh(srl: SwipeRefreshLayout, spec: JSONObject?) {
74
+ if (spec == null) {
75
+ srl.isEnabled = false
76
+ srl.isRefreshing = false
77
+ return
78
+ }
79
+ srl.isEnabled = true
80
+ PNColor.parse(spec.value("tint_color"))?.let { srl.setColorSchemeColors(it) }
81
+ PNColor.parse(spec.value("background_color"))?.let { srl.setProgressBackgroundColorSchemeColor(it) }
82
+ srl.isRefreshing = JsonUtil.truthy(spec.value("refreshing"))
83
+ }
84
+
85
+ override fun insertChild(parent: View, child: View, index: Int) = ViewChildren.insert(inner(parent), child, index)
86
+
87
+ override fun removeChild(parent: View, child: View) {
88
+ inner(parent).removeView(child)
89
+ }
90
+
91
+ private fun bindScrollListener(outer: View, sv: View, horizontal: Boolean) {
92
+ sv.setOnScrollChangeListener { v, scrollX, scrollY, _, _ ->
93
+ if (!hasEvent(outer, "on_scroll")) return@setOnScrollChangeListener
94
+ fire(outer, "on_scroll", scrollPayload(v as ViewGroup, horizontal, scrollX, scrollY))
95
+ }
96
+ }
97
+
98
+ private fun scrollPayload(sv: ViewGroup, horizontal: Boolean, scrollX: Int, scrollY: Int): Map<String, Any?> {
99
+ val content = if (sv.childCount > 0) sv.getChildAt(0) else null
100
+ val extent = if (horizontal) sv.width else sv.height
101
+ val range = if (content == null) extent else if (horizontal) content.width else content.height
102
+ return mapOf(
103
+ "x" to dp(scrollX),
104
+ "y" to dp(scrollY),
105
+ "extent" to dp(extent),
106
+ "range" to dp(max(range, extent)),
107
+ "content_width" to dp(content?.width ?: sv.width),
108
+ "content_height" to dp(content?.height ?: sv.height),
109
+ )
110
+ }
111
+
112
+ @SuppressLint("ClickableViewAccessibility")
113
+ private fun bindTouch(outer: View, sv: ViewGroup, horizontal: Boolean) {
114
+ sv.setOnTouchListener { v, event ->
115
+ val merged = propsOf(outer)
116
+ if (stateOf(outer)["scroll_enabled"] == false) return@setOnTouchListener true
117
+ when (event.actionMasked) {
118
+ MotionEvent.ACTION_MOVE -> {
119
+ val mode = merged.str("keyboard_dismiss_mode")
120
+ if (mode == "on_drag" || mode == "interactive") dismissKeyboard(v)
121
+ }
122
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
123
+ if (JsonUtil.truthy(merged.value("paging_enabled"))) scheduleSnap(sv, horizontal)
124
+ }
125
+ }
126
+ false
127
+ }
128
+ }
129
+
130
+ private fun dismissKeyboard(view: View) {
131
+ val focused = view.rootView.findFocus() ?: return
132
+ focused.clearFocus()
133
+ (view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager)
134
+ ?.hideSoftInputFromWindow(view.windowToken, 0)
135
+ }
136
+
137
+ /** Wait for the fling to settle (two identical samples), then snap to the nearest page. */
138
+ private fun scheduleSnap(sv: ViewGroup, horizontal: Boolean) {
139
+ val state = stateOf(sv.parent as? View ?: sv)
140
+ val token = ((state["snap_token"] as? Int) ?: 0) + 1
141
+ state["snap_token"] = token
142
+ var last = -1
143
+ val poll = object : Runnable {
144
+ override fun run() {
145
+ if (state["snap_token"] != token) return
146
+ val current = if (horizontal) sv.scrollX else sv.scrollY
147
+ if (current == last) {
148
+ val page = if (horizontal) sv.width else sv.height
149
+ if (page > 0) {
150
+ val target = (current.toDouble() / page).roundToInt() * page
151
+ if (target != current) {
152
+ when (sv) {
153
+ is NestedScrollView -> sv.smoothScrollTo(0, target)
154
+ is HorizontalScrollView -> sv.smoothScrollTo(target, 0)
155
+ }
156
+ }
157
+ }
158
+ return
159
+ }
160
+ last = current
161
+ MainThread.postDelayed(this, 50)
162
+ }
163
+ }
164
+ MainThread.postDelayed(poll, 50)
165
+ }
166
+
167
+ override fun command(view: View, name: String, args: JSONObject): Any? {
168
+ val sv = inner(view)
169
+ val horizontal = isHorizontal(view)
170
+ when (name) {
171
+ "scroll_to_offset" -> {
172
+ val x = px(JsonUtil.toDouble(args.opt("x")))
173
+ val y = px(JsonUtil.toDouble(args.opt("y")))
174
+ val animated = args.value("animated") != false
175
+ when (sv) {
176
+ is NestedScrollView -> if (animated) sv.smoothScrollTo(x, y) else sv.scrollTo(x, y)
177
+ is HorizontalScrollView -> if (animated) sv.smoothScrollTo(x, y) else sv.scrollTo(x, y)
178
+ }
179
+ }
180
+ "scroll_to_end" -> {
181
+ val child = if (sv.childCount > 0) sv.getChildAt(0) else return null
182
+ val animated = args.value("animated") != false
183
+ if (horizontal) {
184
+ val target = max(0, child.width - sv.width)
185
+ if (animated) (sv as HorizontalScrollView).smoothScrollTo(target, 0) else sv.scrollTo(target, 0)
186
+ } else {
187
+ val target = max(0, child.height - sv.height)
188
+ if (animated) (sv as NestedScrollView).smoothScrollTo(0, target) else sv.scrollTo(0, target)
189
+ }
190
+ }
191
+ "get_scroll_offset" -> return mapOf("x" to dp(sv.scrollX), "y" to dp(sv.scrollY))
192
+ "flash_scroll_indicators" -> sv.awakenScrollBarsCompat()
193
+ }
194
+ return null
195
+ }
196
+
197
+ private fun View.awakenScrollBarsCompat() {
198
+ // awakenScrollBars is protected; toggling the fade re-shows the bars briefly.
199
+ isScrollbarFadingEnabled = false
200
+ MainThread.postDelayed({ isScrollbarFadingEnabled = true }, 600)
201
+ }
202
+
203
+ override fun setFrame(view: View, x: Double, y: Double, width: Double, height: Double) {
204
+ super.setFrame(view, x, y, width, height)
205
+ // The inner scroll view fills its refresh wrapper.
206
+ if (view is SwipeRefreshLayout) {
207
+ val sv = view.getChildAt(0)
208
+ val lp = sv.layoutParams
209
+ lp.width = ViewGroup.LayoutParams.MATCH_PARENT
210
+ lp.height = ViewGroup.LayoutParams.MATCH_PARENT
211
+ sv.layoutParams = lp
212
+ }
213
+ }
214
+ }
@@ -0,0 +1,113 @@
1
+ package com.pythonnative.runtime.components
2
+
3
+ import android.content.Context
4
+ import android.graphics.drawable.GradientDrawable
5
+ import android.view.View
6
+ import android.widget.Button
7
+ import android.widget.LinearLayout
8
+ import com.pythonnative.runtime.bridge.JsonUtil
9
+ import com.pythonnative.runtime.bridge.arr
10
+ import com.pythonnative.runtime.bridge.value
11
+ import org.json.JSONObject
12
+ import kotlin.math.max
13
+
14
+ /**
15
+ * `SegmentedControl` element: a horizontal `LinearLayout` of equal-width
16
+ * toggle `Button`s. The selected segment is filled with `tint_color`;
17
+ * the rest are outlined. The control owns its subviews, so child
18
+ * inserts are ignored.
19
+ */
20
+ class SegmentedControlManager : ComponentManager() {
21
+ override fun createView(context: Context, tag: Long, props: JSONObject): View {
22
+ val ll = LinearLayout(context)
23
+ ll.orientation = LinearLayout.HORIZONTAL
24
+ return ll
25
+ }
26
+
27
+ override fun insertChild(parent: View, child: View, index: Int) {}
28
+
29
+ override fun removeChild(parent: View, child: View) {}
30
+
31
+ override fun applyProps(view: View, props: JSONObject, initial: Boolean) {
32
+ val ll = view as LinearLayout
33
+ val state = stateOf(ll)
34
+ val merged = propsOf(ll)
35
+ var segmentsChanged = false
36
+ if (props.has("segments") || initial) {
37
+ val segments = JsonUtil.toList(merged.arr("segments")).map { it?.toString() ?: "" }
38
+ if (initial || segments != state["segments"]) {
39
+ state["segments"] = segments
40
+ segmentsChanged = true
41
+ }
42
+ }
43
+ props.value("selected_index")?.let { state["selected_index"] = JsonUtil.toInt(it) }
44
+ if (segmentsChanged) rebuild(ll) else restyle(ll)
45
+ ViewStyler.applyAccessibility(ll, props)
46
+ }
47
+
48
+ private fun rebuild(ll: LinearLayout) {
49
+ val state = stateOf(ll)
50
+ ll.removeAllViews()
51
+ @Suppress("UNCHECKED_CAST")
52
+ val segments = state["segments"] as? List<String> ?: emptyList()
53
+ val enabled = propsOf(ll).value("enabled") != false
54
+ segments.forEachIndexed { index, label ->
55
+ val btn = Button(ll.context)
56
+ btn.text = label
57
+ btn.isAllCaps = false
58
+ btn.layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f)
59
+ btn.isEnabled = enabled
60
+ btn.setOnClickListener {
61
+ if (propsOf(ll).value("enabled") == false) return@setOnClickListener
62
+ stateOf(ll)["selected_index"] = index
63
+ restyle(ll)
64
+ fire(ll, "on_change", index)
65
+ }
66
+ ll.addView(btn)
67
+ }
68
+ restyle(ll)
69
+ }
70
+
71
+ private fun restyle(ll: LinearLayout) {
72
+ val merged = propsOf(ll)
73
+ val accent = PNColor.parseOr(merged.value("tint_color"), DEFAULT_ACCENT)
74
+ val selected = (stateOf(ll)["selected_index"] as? Int) ?: JsonUtil.toInt(merged.value("selected_index"))
75
+ val enabled = merged.value("enabled") != false
76
+ for (i in 0 until ll.childCount) {
77
+ val btn = ll.getChildAt(i) as? Button ?: continue
78
+ val drawable = GradientDrawable()
79
+ drawable.cornerRadius = pxF(6.0)
80
+ drawable.setStroke(px(1.0), accent)
81
+ if (i == selected) {
82
+ drawable.setColor(accent)
83
+ btn.setTextColor(0xFFFFFFFF.toInt())
84
+ } else {
85
+ drawable.setColor(0x00FFFFFF)
86
+ btn.setTextColor(accent)
87
+ }
88
+ btn.background = drawable
89
+ btn.isEnabled = enabled
90
+ }
91
+ }
92
+
93
+ override fun measure(view: View, maxWidth: Double, maxHeight: Double): FloatArray {
94
+ // Weighted children measure to ~0 under an unspecified spec, so
95
+ // size to the sum of the segments' natural widths instead.
96
+ val ll = view as LinearLayout
97
+ if (ll.childCount == 0) return floatArrayOf(0f, 0f)
98
+ val spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
99
+ var totalW = 0
100
+ var maxH = 0
101
+ for (i in 0 until ll.childCount) {
102
+ val child = ll.getChildAt(i)
103
+ child.measure(spec, spec)
104
+ totalW += child.measuredWidth
105
+ maxH = max(maxH, child.measuredHeight)
106
+ }
107
+ return floatArrayOf(dp(totalW).toFloat(), dp(maxH).toFloat())
108
+ }
109
+
110
+ private companion object {
111
+ val DEFAULT_ACCENT = 0xFF007AFF.toInt()
112
+ }
113
+ }
@@ -0,0 +1,52 @@
1
+ package com.pythonnative.runtime.components
2
+
3
+ import android.app.Activity
4
+ import android.content.Context
5
+ import android.view.View
6
+ import androidx.core.view.WindowCompat
7
+ import androidx.core.view.WindowInsetsCompat
8
+ import androidx.core.view.WindowInsetsControllerCompat
9
+ import com.pythonnative.runtime.PNBridge
10
+ import com.pythonnative.runtime.bridge.JsonUtil
11
+ import com.pythonnative.runtime.bridge.PNLog
12
+ import com.pythonnative.runtime.bridge.str
13
+ import com.pythonnative.runtime.bridge.value
14
+ import org.json.JSONObject
15
+
16
+ /** `StatusBar` element: applies bar color, style, and visibility to the host window. */
17
+ class StatusBarManager : ComponentManager() {
18
+ override fun createView(context: Context, tag: Long, props: JSONObject): View {
19
+ val v = View(context)
20
+ v.visibility = View.GONE
21
+ return v
22
+ }
23
+
24
+ override fun setFrame(view: View, x: Double, y: Double, width: Double, height: Double) {}
25
+
26
+ override fun measure(view: View, maxWidth: Double, maxHeight: Double): FloatArray = floatArrayOf(0f, 0f)
27
+
28
+ override fun applyProps(view: View, props: JSONObject, initial: Boolean) {
29
+ val activity = PNBridge.activity() ?: (view.context as? Activity) ?: return
30
+ val window = activity.window ?: return
31
+ try {
32
+ PNColor.parse(props.value("background_color"))?.let { window.statusBarColor = it }
33
+ val controller: WindowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.decorView)
34
+ props.str("bar_style")?.let { style ->
35
+ // "dark" / "default" mean dark icons (light backgrounds); "light" means light icons.
36
+ controller.isAppearanceLightStatusBars = style == "dark" || style == "default" || style == "dark_content"
37
+ }
38
+ if (props.has("hidden")) {
39
+ if (JsonUtil.truthy(props.value("hidden"))) {
40
+ controller.hide(WindowInsetsCompat.Type.statusBars())
41
+ } else {
42
+ controller.show(WindowInsetsCompat.Type.statusBars())
43
+ }
44
+ }
45
+ if (props.has("translucent")) {
46
+ WindowCompat.setDecorFitsSystemWindows(window, !JsonUtil.truthy(props.value("translucent")))
47
+ }
48
+ } catch (e: Exception) {
49
+ PNLog.once("statusbar", "StatusBar: could not apply props on Android: $e")
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,131 @@
1
+ package com.pythonnative.runtime.components
2
+
3
+ import android.content.Context
4
+ import android.content.res.ColorStateList
5
+ import android.view.View
6
+ import com.google.android.material.bottomnavigation.BottomNavigationView
7
+ import com.google.android.material.navigation.NavigationBarView
8
+ import com.pythonnative.runtime.bridge.JsonUtil
9
+ import com.pythonnative.runtime.bridge.PNLog
10
+ import com.pythonnative.runtime.bridge.str
11
+ import com.pythonnative.runtime.bridge.value
12
+ import org.json.JSONArray
13
+ import org.json.JSONObject
14
+
15
+ /**
16
+ * `TabBar` element backed by Material's `BottomNavigationView`.
17
+ *
18
+ * `items` is a list of `{name, title, icon}`; `active_tab` names the
19
+ * selected item (an integer `active_index` is also accepted). Selecting
20
+ * a tab fires `on_tab_select(name)` and `on_select(index)` when wired.
21
+ */
22
+ class TabBarManager : ComponentManager() {
23
+ override fun createView(context: Context, tag: Long, props: JSONObject): View {
24
+ val bnv = BottomNavigationView(context)
25
+ bnv.setBackgroundColor(0xFFFFFFFF.toInt())
26
+ bnv.labelVisibilityMode = NavigationBarView.LABEL_VISIBILITY_LABELED
27
+ bnv.setOnItemSelectedListener { item ->
28
+ if (stateOf(bnv)["suppress"] == true) return@setOnItemSelectedListener true
29
+ val items = propsOf(bnv).value("items") as? JSONArray
30
+ val index = item.itemId
31
+ val spec = items?.optJSONObject(index)
32
+ if (spec != null) {
33
+ fire(bnv, "on_tab_select", spec.str("name") ?: "")
34
+ if (hasEvent(bnv, "on_select")) fire(bnv, "on_select", index)
35
+ }
36
+ true
37
+ }
38
+ return bnv
39
+ }
40
+
41
+ override fun applyProps(view: View, props: JSONObject, initial: Boolean) {
42
+ val bnv = view as BottomNavigationView
43
+ val merged = propsOf(bnv)
44
+ if (props.has("items")) setMenu(bnv, merged.value("items") as? JSONArray)
45
+ if (props.has("active_tab") || props.has("active_index") || props.has("items")) {
46
+ setActive(bnv, merged)
47
+ }
48
+ val active = PNColor.parse(props.value("active_tint_color") ?: props.value("tint_color"))
49
+ val inactive = PNColor.parse(props.value("inactive_tint_color"))
50
+ if (active != null || inactive != null) {
51
+ val a = active ?: PNColor.parse(merged.value("active_tint_color")) ?: 0xFF1976D2.toInt()
52
+ val i = inactive ?: PNColor.parse(merged.value("inactive_tint_color")) ?: 0xFF757575.toInt()
53
+ val list = ColorStateList(arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()), intArrayOf(a, i))
54
+ bnv.itemIconTintList = list
55
+ bnv.itemTextColor = list
56
+ }
57
+ PNColor.parse(props.value("background_color"))?.let { bnv.setBackgroundColor(it) }
58
+ if (props.has("shows_labels")) {
59
+ bnv.labelVisibilityMode = if (JsonUtil.truthy(props.value("shows_labels"))) {
60
+ NavigationBarView.LABEL_VISIBILITY_LABELED
61
+ } else {
62
+ NavigationBarView.LABEL_VISIBILITY_UNLABELED
63
+ }
64
+ }
65
+ ViewStyler.apply(bnv, JSONObject(props.toString()).apply { remove("background_color") })
66
+ }
67
+
68
+ private fun setMenu(bnv: BottomNavigationView, items: JSONArray?) {
69
+ val state = stateOf(bnv)
70
+ state["suppress"] = true
71
+ try {
72
+ val menu = bnv.menu
73
+ menu.clear()
74
+ if (items == null) return
75
+ for (i in 0 until items.length()) {
76
+ val item = items.optJSONObject(i) ?: continue
77
+ val title = item.str("title") ?: item.str("name") ?: ""
78
+ val menuItem = menu.add(0, i, i, title)
79
+ val icon = resolveIcon(bnv.context, item.value("icon"))
80
+ if (icon != 0) menuItem.setIcon(icon)
81
+ item.str("badge")?.let { badge ->
82
+ val b = bnv.getOrCreateBadge(i)
83
+ badge.toIntOrNull()?.let { b.number = it }
84
+ }
85
+ }
86
+ } catch (e: Exception) {
87
+ PNLog.swallowed("TabBarManager.setMenu", e)
88
+ } finally {
89
+ state["suppress"] = false
90
+ }
91
+ }
92
+
93
+ /** Resolve an icon spec (`"ic_menu_home"` or `{"android": ...}`) to a drawable id. */
94
+ private fun resolveIcon(context: Context, icon: Any?): Int {
95
+ val name = when (icon) {
96
+ is String -> icon
97
+ is JSONObject -> icon.str("android")
98
+ else -> null
99
+ } ?: return 0
100
+ return try {
101
+ val field = android.R.drawable::class.java.getField(name)
102
+ field.getInt(null)
103
+ } catch (e: Exception) {
104
+ context.resources.getIdentifier(name, "drawable", context.packageName)
105
+ }
106
+ }
107
+
108
+ private fun setActive(bnv: BottomNavigationView, merged: JSONObject) {
109
+ val items = merged.value("items") as? JSONArray ?: return
110
+ val active = merged.str("active_tab")
111
+ var target = -1
112
+ if (active != null) {
113
+ for (i in 0 until items.length()) {
114
+ if (items.optJSONObject(i)?.str("name") == active) {
115
+ target = i
116
+ break
117
+ }
118
+ }
119
+ }
120
+ if (target < 0) target = merged.value("active_index")?.let { JsonUtil.toInt(it, -1) } ?: -1
121
+ if (target < 0 || target >= items.length()) return
122
+ if (bnv.selectedItemId == target) return
123
+ val state = stateOf(bnv)
124
+ state["suppress"] = true
125
+ try {
126
+ bnv.selectedItemId = target
127
+ } finally {
128
+ state["suppress"] = false
129
+ }
130
+ }
131
+ }