pythonnative 0.35.0__py3-none-any.whl → 0.37.0__py3-none-any.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 (176) hide show
  1. pythonnative/__init__.py +6 -4
  2. pythonnative/_ios_log.py +1 -1
  3. pythonnative/alerts.py +34 -88
  4. pythonnative/bootstrap.py +90 -0
  5. pythonnative/bridge/__init__.py +306 -0
  6. pythonnative/bridge/android.py +78 -0
  7. pythonnative/bridge/codec.py +164 -0
  8. pythonnative/bridge/fake.py +236 -0
  9. pythonnative/bridge/ios.py +138 -0
  10. pythonnative/cli/pn.py +24 -6
  11. pythonnative/components/layout.py +65 -3
  12. pythonnative/gestures.py +13 -10
  13. pythonnative/hooks.py +41 -26
  14. pythonnative/hosts/__init__.py +13 -36
  15. pythonnative/hosts/native.py +348 -0
  16. pythonnative/images.py +6 -5
  17. pythonnative/mutations.py +21 -0
  18. pythonnative/native_modules/__init__.py +30 -29
  19. pythonnative/native_modules/app_state.py +10 -6
  20. pythonnative/native_modules/battery.py +20 -84
  21. pythonnative/native_modules/biometrics.py +11 -124
  22. pythonnative/native_modules/camera.py +15 -291
  23. pythonnative/native_modules/clipboard.py +14 -109
  24. pythonnative/native_modules/desktop.py +322 -0
  25. pythonnative/native_modules/file_system.py +15 -21
  26. pythonnative/native_modules/haptics.py +19 -129
  27. pythonnative/native_modules/linking.py +24 -137
  28. pythonnative/native_modules/location.py +28 -180
  29. pythonnative/native_modules/net_info.py +25 -135
  30. pythonnative/native_modules/notifications.py +36 -257
  31. pythonnative/native_modules/permissions.py +20 -184
  32. pythonnative/native_modules/registry.py +513 -0
  33. pythonnative/native_modules/secure_store.py +18 -155
  34. pythonnative/native_modules/share.py +8 -113
  35. pythonnative/native_views/__init__.py +67 -86
  36. pythonnative/native_views/bridge_backend.py +264 -0
  37. pythonnative/platform.py +19 -15
  38. pythonnative/platform_metrics.py +3 -3
  39. pythonnative/project/android.py +0 -3
  40. pythonnative/project/builder.py +38 -16
  41. pythonnative/project/config.py +12 -2
  42. pythonnative/project/plugins.py +366 -0
  43. pythonnative/py.typed +0 -0
  44. pythonnative/runtime.py +35 -203
  45. pythonnative/sdk/__init__.py +48 -33
  46. pythonnative/sdk/_components.py +57 -76
  47. pythonnative/storage.py +18 -243
  48. pythonnative/templates/android_template/app/build.gradle +6 -9
  49. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +34 -166
  50. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -151
  51. pythonnative/templates/android_template/pythonnative/build.gradle +48 -0
  52. pythonnative/templates/android_template/pythonnative/src/main/AndroidManifest.xml +11 -0
  53. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/PNBridge.kt +214 -0
  54. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
  55. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
  56. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +249 -0
  57. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
  58. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +32 -0
  59. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
  60. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
  61. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
  62. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +115 -0
  63. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
  64. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +35 -0
  65. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +33 -0
  66. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
  67. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
  68. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
  69. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
  70. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
  71. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +156 -0
  72. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
  73. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
  74. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +87 -0
  75. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
  76. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
  77. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
  78. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
  79. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
  80. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
  81. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +245 -0
  82. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
  83. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
  84. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +179 -0
  85. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
  86. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
  87. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
  88. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
  89. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
  90. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
  91. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +97 -0
  92. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
  93. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +135 -0
  94. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
  95. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +88 -0
  96. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
  97. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
  98. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
  99. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/Navigator.kt +116 -0
  100. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +223 -0
  101. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
  102. pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNAccessibilityDelegate.kt +5 -4
  103. pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNBorderDrawable.kt +12 -3
  104. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
  105. pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNFrameLayout.kt +9 -10
  106. pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNVirtualListView.java +9 -12
  107. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
  108. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
  109. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
  110. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
  111. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PromiseTest.kt +75 -0
  112. pythonnative/templates/android_template/settings.gradle +1 -0
  113. pythonnative/templates/ios_template/PythonNativeKit/Package.swift +21 -0
  114. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Animation/PNAnimator.swift +301 -0
  115. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNBridge.swift +191 -0
  116. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNRegistry.swift +140 -0
  117. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNTransaction.swift +165 -0
  118. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
  119. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNButtonManagers.swift +206 -0
  120. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
  121. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
  122. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
  123. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
  124. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNImageManager.swift +221 -0
  125. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
  126. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
  127. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
  128. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
  129. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTextInputManager.swift +289 -0
  130. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
  131. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
  132. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
  133. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
  134. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
  135. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +257 -0
  136. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
  137. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
  138. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
  139. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/HostModule.swift +158 -0
  140. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
  141. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
  142. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/PNNativeModule.swift +125 -0
  143. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/PermissionModules.swift +251 -0
  144. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
  145. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
  146. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
  147. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Screens/PNViewController.swift +251 -0
  148. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
  149. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
  150. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
  151. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
  152. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
  153. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
  154. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNManagerTests.swift +124 -0
  155. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNModuleTests.swift +98 -0
  156. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
  157. pythonnative/templates/ios_template/ios_template/AppDelegate.swift +8 -50
  158. pythonnative/templates/ios_template/ios_template/Info.plist +4 -4
  159. pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +38 -46
  160. pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +11 -16
  161. pythonnative/templates/ios_template/ios_template/ViewController.swift +12 -142
  162. pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +47 -1
  163. pythonnative/utils.py +4 -82
  164. pythonnative/virtual_rows.py +3 -3
  165. {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/METADATA +3 -5
  166. pythonnative-0.37.0.dist-info/RECORD +263 -0
  167. pythonnative/hosts/android.py +0 -269
  168. pythonnative/hosts/ios.py +0 -404
  169. pythonnative/native_views/android.py +0 -3702
  170. pythonnative/native_views/ios.py +0 -5253
  171. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt +0 -43
  172. pythonnative-0.35.0.dist-info/RECORD +0 -155
  173. {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/WHEEL +0 -0
  174. {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/entry_points.txt +0 -0
  175. {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/licenses/LICENSE +0 -0
  176. {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/top_level.txt +0 -0
@@ -113,7 +113,16 @@ def View(
113
113
  def Column(
114
114
  *children: Element,
115
115
  style: StyleProp = None,
116
+ gestures: Optional[List[Any]] = None,
117
+ hit_slop: Optional[Union[float, Dict[str, float]]] = None,
116
118
  on_layout: Optional[Callable[[Dict[str, float]], None]] = None,
119
+ accessibility_label: Optional[str] = None,
120
+ accessibility_hint: Optional[str] = None,
121
+ accessibility_role: Optional[str] = None,
122
+ accessible: Optional[bool] = None,
123
+ accessibility_state: Optional[AccessibilityState] = None,
124
+ accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
125
+ test_id: Optional[str] = None,
117
126
  ref: Optional[Ref] = None,
118
127
  key: Optional[str] = None,
119
128
  ) -> Element:
@@ -123,12 +132,25 @@ def Column(
123
132
  ``flex_direction`` locked to ``"column"``. Use ``View`` directly if
124
133
  you need to switch between row and column at runtime.
125
134
 
135
+ Accepts every [`View`][pythonnative.View] prop (gestures, hit slop,
136
+ accessibility, ``test_id``); only ``flex_direction`` is fixed.
137
+
126
138
  Args:
127
139
  *children: Child elements stacked top to bottom.
128
140
  style: Style dict (or list of dicts).
141
+ gestures: Gesture descriptors recognized natively on this view.
142
+ hit_slop: Extra touch target beyond the bounds (see ``View``).
129
143
  on_layout: Callback invoked with
130
144
  ``{"x", "y", "width", "height"}`` after layout and on
131
145
  frame changes.
146
+ accessibility_label: Spoken description for screen readers.
147
+ accessibility_hint: Spoken extra detail (iOS only).
148
+ accessibility_role: Semantic role for assistive tech.
149
+ accessible: Override whether the element is exposed to AT.
150
+ accessibility_state: Current widget state for assistive tech.
151
+ accessibility_live_region: How AT announces dynamic changes
152
+ (Android only).
153
+ test_id: Stable identifier for UI tests.
132
154
  ref: Optional [`Ref`][pythonnative.Ref] for native-view access.
133
155
  key: Stable identity for keyed reconciliation.
134
156
 
@@ -139,9 +161,18 @@ def Column(
139
161
  "Column",
140
162
  *children,
141
163
  style=style,
142
- on_layout=on_layout,
143
164
  ref=ref,
144
165
  key=key,
166
+ gestures=gestures,
167
+ hit_slop=hit_slop,
168
+ on_layout=on_layout,
169
+ accessibility_label=accessibility_label,
170
+ accessibility_hint=accessibility_hint,
171
+ accessibility_role=accessibility_role,
172
+ accessible=accessible,
173
+ accessibility_state=accessibility_state,
174
+ accessibility_live_region=accessibility_live_region,
175
+ test_id=test_id,
145
176
  _forced={"flex_direction": "column"},
146
177
  )
147
178
 
@@ -149,7 +180,16 @@ def Column(
149
180
  def Row(
150
181
  *children: Element,
151
182
  style: StyleProp = None,
183
+ gestures: Optional[List[Any]] = None,
184
+ hit_slop: Optional[Union[float, Dict[str, float]]] = None,
152
185
  on_layout: Optional[Callable[[Dict[str, float]], None]] = None,
186
+ accessibility_label: Optional[str] = None,
187
+ accessibility_hint: Optional[str] = None,
188
+ accessibility_role: Optional[str] = None,
189
+ accessible: Optional[bool] = None,
190
+ accessibility_state: Optional[AccessibilityState] = None,
191
+ accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
192
+ test_id: Optional[str] = None,
153
193
  ref: Optional[Ref] = None,
154
194
  key: Optional[str] = None,
155
195
  ) -> Element:
@@ -159,12 +199,25 @@ def Row(
159
199
  ``flex_direction`` locked to ``"row"``. Use ``View`` directly if you
160
200
  need to switch between row and column at runtime.
161
201
 
202
+ Accepts every [`View`][pythonnative.View] prop (gestures, hit slop,
203
+ accessibility, ``test_id``); only ``flex_direction`` is fixed.
204
+
162
205
  Args:
163
206
  *children: Child elements arranged left to right.
164
207
  style: Style dict (or list of dicts).
208
+ gestures: Gesture descriptors recognized natively on this view.
209
+ hit_slop: Extra touch target beyond the bounds (see ``View``).
165
210
  on_layout: Callback invoked with
166
211
  ``{"x", "y", "width", "height"}`` after layout and on
167
212
  frame changes.
213
+ accessibility_label: Spoken description for screen readers.
214
+ accessibility_hint: Spoken extra detail (iOS only).
215
+ accessibility_role: Semantic role for assistive tech.
216
+ accessible: Override whether the element is exposed to AT.
217
+ accessibility_state: Current widget state for assistive tech.
218
+ accessibility_live_region: How AT announces dynamic changes
219
+ (Android only).
220
+ test_id: Stable identifier for UI tests.
168
221
  ref: Optional [`Ref`][pythonnative.Ref] for native-view access.
169
222
  key: Stable identity for keyed reconciliation.
170
223
 
@@ -175,9 +228,18 @@ def Row(
175
228
  "Row",
176
229
  *children,
177
230
  style=style,
178
- on_layout=on_layout,
179
231
  ref=ref,
180
232
  key=key,
233
+ gestures=gestures,
234
+ hit_slop=hit_slop,
235
+ on_layout=on_layout,
236
+ accessibility_label=accessibility_label,
237
+ accessibility_hint=accessibility_hint,
238
+ accessibility_role=accessibility_role,
239
+ accessible=accessible,
240
+ accessibility_state=accessibility_state,
241
+ accessibility_live_region=accessibility_live_region,
242
+ test_id=test_id,
181
243
  _forced={"flex_direction": "row"},
182
244
  )
183
245
 
@@ -326,7 +388,7 @@ def _SafeAreaContainer(
326
388
  for edge in _SAFE_AREA_EDGES:
327
389
  if edge not in selected:
328
390
  continue
329
- inset = float(insets.get(edge, 0.0) or 0.0)
391
+ inset = float(getattr(insets, edge, 0.0) or 0.0)
330
392
  if inset > 0:
331
393
  resolved[f"padding_{edge}"] = _numeric_edge_padding(resolved, edge) + inset
332
394
  return Element("SafeAreaView", resolved, list(children))
pythonnative/gestures.py CHANGED
@@ -34,10 +34,13 @@ configuration into plain dicts for the native handler (so prop diffing
34
34
  never compares closures) and routes the callbacks through the
35
35
  tag-based event channel. Recognition itself is native:
36
36
 
37
- - **iOS** attaches real ``UIGestureRecognizer`` instances.
38
- - **Android** feeds raw ``MotionEvent`` streams into the pure-Python
39
- [`GestureArbiter`][pythonnative.gestures.GestureArbiter] below.
40
- - **Desktop** feeds Tk pointer events into the same arbiter.
37
+ - **iOS** attaches real ``UIGestureRecognizer`` instances
38
+ (``PythonNativeKit``).
39
+ - **Android** runs an equivalent recognizer set in Kotlin (the
40
+ ``pythonnative`` Gradle module) on top of ``MotionEvent`` streams.
41
+ - **Desktop** feeds Tk pointer events into the pure-Python
42
+ [`GestureArbiter`][pythonnative.gestures.GestureArbiter] below, which
43
+ doubles as the executable specification for the native ports.
41
44
 
42
45
  Composition
43
46
  -----------
@@ -518,14 +521,14 @@ def serialize_gestures(
518
521
 
519
522
 
520
523
  # ======================================================================
521
- # Pure-Python recognition engine (Android + desktop backends)
524
+ # Pure-Python recognition engine (desktop backend + reference semantics)
522
525
  # ======================================================================
523
526
  #
524
- # iOS uses real UIGestureRecognizers. Android and the desktop preview
525
- # receive raw pointer streams instead, which this arbiter turns into
526
- # the same GestureEvent payloads. Keeping it in pure Python makes the
527
- # state machines unit-testable with scripted event sequences and
528
- # guarantees identical semantics on both backends.
527
+ # iOS and Android recognize natively. The desktop preview receives raw
528
+ # Tk pointer streams instead, which this arbiter turns into the same
529
+ # GestureEvent payloads. Keeping it in pure Python makes the state
530
+ # machines unit-testable with scripted event sequences; the Kotlin
531
+ # arbiter mirrors this file so the two stay in lockstep.
529
532
 
530
533
  EmitFn = Callable[[int, Dict[str, Any]], None]
531
534
  """``emit(gesture_index, payload)``: the arbiter's output channel."""
pythonnative/hooks.py CHANGED
@@ -67,6 +67,7 @@ from typing import (
67
67
 
68
68
  from . import diagnostics
69
69
  from .element import Element, Node
70
+ from .platform_metrics import SafeAreaInsets, WindowDimensions
70
71
  from .scheduler import TransitionQueue, in_transition, run_in_transition, schedule_trigger
71
72
  from .suspense import CoroDriver, Resource
72
73
 
@@ -1235,27 +1236,39 @@ def use_mutation(
1235
1236
  from .runtime import run_async
1236
1237
 
1237
1238
  state, set_state = use_state(lambda: MutationState[T]())
1239
+ # The trigger is identity-stable across renders (like ``set_state``)
1240
+ # so it can sit in effect deps or be passed to memoized children;
1241
+ # it always calls the latest ``mutator``.
1242
+ latest = use_ref(mutator)
1243
+ latest.current = mutator
1244
+
1245
+ def _make_mutate() -> Callable[..., MutationCall[T]]:
1246
+ def mutate(*args: Any, **kwargs: Any) -> MutationCall[T]:
1247
+ set_state(lambda s: replace(s, loading=True, error=None))
1248
+ fn = latest.current
1238
1249
 
1239
- def mutate(*args: Any, **kwargs: Any) -> MutationCall[T]:
1240
- set_state(lambda s: replace(s, loading=True, error=None))
1250
+ async def _runner() -> T:
1251
+ try:
1252
+ data = await fn(*args, **kwargs)
1253
+ set_state(lambda s: replace(s, data=data, loading=False, error=None))
1254
+ return data
1255
+ except asyncio.CancelledError:
1256
+ set_state(lambda s: replace(s, loading=False))
1257
+ raise
1258
+ except BaseException as exc:
1259
+ failure = exc
1260
+ set_state(lambda s: replace(s, loading=False, error=failure))
1261
+ raise
1241
1262
 
1242
- async def _runner() -> T:
1243
- try:
1244
- data = await mutator(*args, **kwargs)
1245
- set_state(lambda s: replace(s, data=data, loading=False, error=None))
1246
- return data
1247
- except asyncio.CancelledError:
1248
- set_state(lambda s: replace(s, loading=False))
1249
- raise
1250
- except BaseException as exc:
1251
- failure = exc
1252
- set_state(lambda s: replace(s, loading=False, error=failure))
1253
- raise
1263
+ future = run_async(_runner())
1264
+ return MutationCall[T](future)
1254
1265
 
1255
- future = run_async(_runner())
1256
- return MutationCall[T](future)
1266
+ return mutate
1257
1267
 
1258
- return state, mutate
1268
+ mutate_ref: Ref[Optional[Callable[..., MutationCall[T]]]] = use_ref(None)
1269
+ if mutate_ref.current is None:
1270
+ mutate_ref.current = _make_mutate()
1271
+ return state, mutate_ref.current
1259
1272
 
1260
1273
 
1261
1274
  # ======================================================================
@@ -1294,7 +1307,7 @@ def use_subscription(subscribe: Callable[[Callable[[], None]], Callable[[], None
1294
1307
  return get_snapshot()
1295
1308
 
1296
1309
 
1297
- def use_window_dimensions() -> Dict[str, float]:
1310
+ def use_window_dimensions() -> WindowDimensions:
1298
1311
  """Return the current viewport size and re-render when it changes.
1299
1312
 
1300
1313
  Equivalent to React Native's ``useWindowDimensions``. The values
@@ -1302,26 +1315,29 @@ def use_window_dimensions() -> Dict[str, float]:
1302
1315
  size (initial layout, rotation, multitasking split-view).
1303
1316
 
1304
1317
  Returns:
1305
- A dict with ``"width"`` and ``"height"`` floats in layout
1318
+ A [`WindowDimensions`][pythonnative.platform_metrics.WindowDimensions]
1319
+ named tuple with ``width`` and ``height`` floats in layout
1306
1320
  units (pt on iOS, dp on Android). Both are ``0.0`` until the
1307
- screen host has run its first layout pass.
1321
+ screen host has run its first layout pass. Being a tuple, it
1322
+ unpacks (``width, height = pn.use_window_dimensions()``) and
1323
+ compares by value.
1308
1324
 
1309
1325
  Raises:
1310
1326
  RuntimeError: If called outside a ``@component`` function.
1311
1327
  """
1312
1328
  from . import platform_metrics
1313
1329
 
1314
- dims = use_subscription(platform_metrics.subscribe, platform_metrics.get_window_dimensions)
1315
- return {"width": dims.width, "height": dims.height}
1330
+ return use_subscription(platform_metrics.subscribe, platform_metrics.get_window_dimensions)
1316
1331
 
1317
1332
 
1318
- def use_safe_area_insets() -> Dict[str, float]:
1333
+ def use_safe_area_insets() -> SafeAreaInsets:
1319
1334
  """Return the current safe-area insets and re-render on change.
1320
1335
 
1321
1336
  Mirrors ``react-native-safe-area-context``'s ``useSafeAreaInsets``.
1322
1337
 
1323
1338
  Returns:
1324
- A dict with ``"top"``, ``"bottom"``, ``"left"``, and ``"right"``
1339
+ A [`SafeAreaInsets`][pythonnative.platform_metrics.SafeAreaInsets]
1340
+ named tuple with ``top``, ``left``, ``bottom``, and ``right``
1325
1341
  floats in layout units (pt on iOS, dp on Android).
1326
1342
 
1327
1343
  Raises:
@@ -1329,8 +1345,7 @@ def use_safe_area_insets() -> Dict[str, float]:
1329
1345
  """
1330
1346
  from . import platform_metrics
1331
1347
 
1332
- insets = use_subscription(platform_metrics.subscribe, platform_metrics.get_safe_area_insets)
1333
- return {"top": insets.top, "bottom": insets.bottom, "left": insets.left, "right": insets.right}
1348
+ return use_subscription(platform_metrics.subscribe, platform_metrics.get_safe_area_insets)
1334
1349
 
1335
1350
 
1336
1351
  def use_keyboard_height() -> float:
@@ -1,18 +1,13 @@
1
1
  """Screen hosts: the bridge between a native screen and the reconciler.
2
2
 
3
- Native templates create one host per screen:
4
-
5
- ```python
6
- host = pythonnative.hosts.create_screen("app.main", native_instance, args_json)
7
- host.on_create()
8
- ```
9
-
10
- and forward lifecycle events to it. The concrete class depends on the
11
- runtime ([`AndroidScreenHost`][pythonnative.hosts.android.AndroidScreenHost],
12
- [`IOSScreenHost`][pythonnative.hosts.ios.IOSScreenHost],
13
- [`DesktopScreenHost`][pythonnative.hosts.desktop.DesktopScreenHost]);
14
- the headless base [`ScreenHost`][pythonnative.hosts.ScreenHost] is used
15
- in unit tests with a fake backend.
3
+ On device the native runtime creates screens through the bridge
4
+ (``callback("host", screen_id, "create", {...})``), which lands in
5
+ [`NativeScreenHost`][pythonnative.hosts.native.NativeScreenHost]. Off device,
6
+ ``pn preview`` creates a
7
+ [`DesktopScreenHost`][pythonnative.hosts.desktop.DesktopScreenHost]
8
+ through [`create_screen`][pythonnative.hosts.create_screen], and unit
9
+ tests use the headless base [`ScreenHost`][pythonnative.hosts.ScreenHost]
10
+ with a fake backend.
16
11
  """
17
12
 
18
13
  from __future__ import annotations
@@ -27,18 +22,14 @@ __all__ = ["ScreenHost", "create_screen", "host_class", "import_component"]
27
22
 
28
23
  def host_class() -> Type[ScreenHost]:
29
24
  """The host class for the current runtime."""
30
- if IS_ANDROID:
31
- from .android import AndroidScreenHost
25
+ if IS_ANDROID or IS_IOS:
26
+ from .native import NativeScreenHost
32
27
 
33
- return AndroidScreenHost
28
+ return NativeScreenHost
34
29
  if IS_DESKTOP:
35
30
  from .desktop import DesktopScreenHost
36
31
 
37
32
  return DesktopScreenHost
38
- if IS_IOS:
39
- from .ios import IOSScreenHost
40
-
41
- return IOSScreenHost
42
33
  return ScreenHost
43
34
 
44
35
 
@@ -49,8 +40,8 @@ def create_screen(component_path: str, native_instance: Any = None, args_json: O
49
40
  component_path: ``"app.main"`` (the module's ``App`` is used) or a
50
41
  dotted path like ``"app.main.RootScreen"``. Imported lazily
51
42
  so the dev server can reload it.
52
- native_instance: The platform object owning the screen
53
- (``Activity``, ``UIViewController`` pointer, ``DesktopApp``).
43
+ native_instance: The platform object owning the screen (the
44
+ integer screen id on device, ``DesktopApp`` in the preview).
54
45
  args_json: Optional JSON launch arguments (pushed screens
55
46
  receive their navigation history here).
56
47
 
@@ -64,20 +55,6 @@ def create_screen(component_path: str, native_instance: Any = None, args_json: O
64
55
  return host
65
56
 
66
57
 
67
- def drain_ios_scheduled_renders() -> None:
68
- """Drain deferred iOS renders (called by the Swift template on the main thread)."""
69
- from .ios import drain_ios_scheduled_renders as drain
70
-
71
- drain()
72
-
73
-
74
- def forward_lifecycle(native_addr: int, event: str) -> None:
75
- """Forward a Swift view-controller lifecycle event to its host."""
76
- from .ios import forward_lifecycle as forward
77
-
78
- forward(native_addr, event)
79
-
80
-
81
58
  def drain_desktop_scheduled_renders() -> None:
82
59
  """Drain deferred desktop renders (called by the preview's Tk loop)."""
83
60
  from .desktop import drain_desktop_scheduled_renders as drain