pythonnative 0.17.1__py3-none-any.whl → 0.19.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.
- pythonnative/__init__.py +53 -2
- pythonnative/cli/pn.py +107 -1
- pythonnative/components.py +547 -10
- pythonnative/native_modules/__init__.py +62 -8
- pythonnative/native_modules/app_state.py +94 -0
- pythonnative/native_modules/battery.py +139 -0
- pythonnative/native_modules/biometrics.py +156 -0
- pythonnative/native_modules/clipboard.py +142 -0
- pythonnative/native_modules/haptics.py +180 -0
- pythonnative/native_modules/linking.py +179 -0
- pythonnative/native_modules/net_info.py +151 -0
- pythonnative/native_modules/permissions.py +200 -0
- pythonnative/native_modules/secure_store.py +193 -0
- pythonnative/native_modules/share.py +155 -0
- pythonnative/native_views/__init__.py +18 -5
- pythonnative/native_views/android.py +974 -23
- pythonnative/native_views/desktop.py +1489 -0
- pythonnative/native_views/ios.py +952 -27
- pythonnative/platform.py +17 -8
- pythonnative/preview.py +471 -0
- pythonnative/runtime.py +26 -1
- pythonnative/screen.py +184 -4
- pythonnative/utils.py +38 -2
- {pythonnative-0.17.1.dist-info → pythonnative-0.19.0.dist-info}/METADATA +4 -1
- {pythonnative-0.17.1.dist-info → pythonnative-0.19.0.dist-info}/RECORD +29 -17
- {pythonnative-0.17.1.dist-info → pythonnative-0.19.0.dist-info}/WHEEL +0 -0
- {pythonnative-0.17.1.dist-info → pythonnative-0.19.0.dist-info}/entry_points.txt +0 -0
- {pythonnative-0.17.1.dist-info → pythonnative-0.19.0.dist-info}/licenses/LICENSE +0 -0
- {pythonnative-0.17.1.dist-info → pythonnative-0.19.0.dist-info}/top_level.txt +0 -0
pythonnative/components.py
CHANGED
|
@@ -151,6 +151,12 @@ class TextInputProps(Props):
|
|
|
151
151
|
return_key_type: Optional[ReturnKeyType] = None
|
|
152
152
|
max_length: Optional[int] = None
|
|
153
153
|
placeholder_color: Optional[Color] = None
|
|
154
|
+
editable: bool = True
|
|
155
|
+
clear_button: bool = False
|
|
156
|
+
on_focus: Optional[Callable[[], None]] = None
|
|
157
|
+
on_blur: Optional[Callable[[], None]] = None
|
|
158
|
+
selection_color: Optional[Color] = None
|
|
159
|
+
text_content_type: Optional[str] = None
|
|
154
160
|
accessibility_label: Optional[str] = None
|
|
155
161
|
accessibility_hint: Optional[str] = None
|
|
156
162
|
accessible: Optional[bool] = None
|
|
@@ -181,6 +187,9 @@ class ProgressBarProps(Props):
|
|
|
181
187
|
"""Props for [`ProgressBar`][pythonnative.ProgressBar]."""
|
|
182
188
|
|
|
183
189
|
value: float = 0.0
|
|
190
|
+
color: Optional[Color] = None
|
|
191
|
+
track_color: Optional[Color] = None
|
|
192
|
+
indeterminate: bool = False
|
|
184
193
|
|
|
185
194
|
|
|
186
195
|
@dataclass(frozen=True)
|
|
@@ -188,6 +197,8 @@ class ActivityIndicatorProps(Props):
|
|
|
188
197
|
"""Props for [`ActivityIndicator`][pythonnative.ActivityIndicator]."""
|
|
189
198
|
|
|
190
199
|
animating: bool = True
|
|
200
|
+
color: Optional[Color] = None
|
|
201
|
+
size: Literal["small", "large"] = "small"
|
|
191
202
|
|
|
192
203
|
|
|
193
204
|
@dataclass(frozen=True)
|
|
@@ -195,6 +206,12 @@ class WebViewProps(Props):
|
|
|
195
206
|
"""Props for [`WebView`][pythonnative.WebView]."""
|
|
196
207
|
|
|
197
208
|
url: Optional[str] = None
|
|
209
|
+
html: Optional[str] = None
|
|
210
|
+
on_load: Optional[Callable[[str], None]] = None
|
|
211
|
+
on_message: Optional[Callable[[str], None]] = None
|
|
212
|
+
on_navigation_state_change: Optional[Callable[[str], None]] = None
|
|
213
|
+
inject_javascript: Optional[str] = None
|
|
214
|
+
scroll_enabled: bool = True
|
|
198
215
|
|
|
199
216
|
|
|
200
217
|
@dataclass(frozen=True)
|
|
@@ -231,6 +248,12 @@ class ScrollViewProps(Props):
|
|
|
231
248
|
|
|
232
249
|
refresh_control: Optional[Dict[str, Any]] = None
|
|
233
250
|
scroll_axis: Optional[Literal["vertical", "horizontal"]] = None
|
|
251
|
+
on_scroll: Optional[Callable[[float, float], None]] = None
|
|
252
|
+
shows_scroll_indicator: bool = True
|
|
253
|
+
paging_enabled: bool = False
|
|
254
|
+
bounces: bool = True
|
|
255
|
+
content_container_style: StyleProp = None
|
|
256
|
+
keyboard_dismiss_mode: Optional[Literal["none", "on_drag", "interactive"]] = None
|
|
234
257
|
|
|
235
258
|
|
|
236
259
|
@dataclass(frozen=True)
|
|
@@ -244,9 +267,12 @@ class ModalProps(Props):
|
|
|
244
267
|
|
|
245
268
|
visible: bool = False
|
|
246
269
|
on_dismiss: Optional[Callable[[], None]] = None
|
|
270
|
+
on_show: Optional[Callable[[], None]] = None
|
|
247
271
|
title: Optional[str] = None
|
|
248
272
|
animation_type: Literal["slide", "fade", "none"] = "slide"
|
|
249
273
|
transparent: bool = False
|
|
274
|
+
presentation_style: Literal["page_sheet", "form_sheet", "full_screen", "overlay"] = "page_sheet"
|
|
275
|
+
dismiss_on_backdrop: bool = True
|
|
250
276
|
|
|
251
277
|
|
|
252
278
|
@dataclass(frozen=True)
|
|
@@ -296,6 +322,77 @@ class PickerProps(Props):
|
|
|
296
322
|
accessible: Optional[bool] = None
|
|
297
323
|
|
|
298
324
|
|
|
325
|
+
@dataclass(frozen=True)
|
|
326
|
+
class TouchableOpacityProps(Props):
|
|
327
|
+
"""Props for [`TouchableOpacity`][pythonnative.TouchableOpacity]."""
|
|
328
|
+
|
|
329
|
+
on_press: Optional[Callable[[], None]] = None
|
|
330
|
+
on_long_press: Optional[Callable[[], None]] = None
|
|
331
|
+
active_opacity: float = 0.2
|
|
332
|
+
disabled: bool = False
|
|
333
|
+
accessibility_label: Optional[str] = None
|
|
334
|
+
accessibility_hint: Optional[str] = None
|
|
335
|
+
accessibility_role: Optional[str] = None
|
|
336
|
+
accessible: Optional[bool] = None
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
@dataclass(frozen=True)
|
|
340
|
+
class ImageBackgroundProps(Props):
|
|
341
|
+
"""Props for [`ImageBackground`][pythonnative.ImageBackground]."""
|
|
342
|
+
|
|
343
|
+
source: Optional[str] = None
|
|
344
|
+
scale_type: Optional[ScaleType] = None
|
|
345
|
+
accessibility_label: Optional[str] = None
|
|
346
|
+
accessible: Optional[bool] = None
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@dataclass(frozen=True)
|
|
350
|
+
class CheckboxProps(Props):
|
|
351
|
+
"""Props for [`Checkbox`][pythonnative.Checkbox]."""
|
|
352
|
+
|
|
353
|
+
value: bool = False
|
|
354
|
+
on_change: Optional[Callable[[bool], None]] = None
|
|
355
|
+
label: Optional[str] = None
|
|
356
|
+
disabled: bool = False
|
|
357
|
+
color: Optional[Color] = None
|
|
358
|
+
accessibility_label: Optional[str] = None
|
|
359
|
+
accessibility_hint: Optional[str] = None
|
|
360
|
+
accessible: Optional[bool] = None
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@dataclass(frozen=True)
|
|
364
|
+
class SegmentedControlProps(Props):
|
|
365
|
+
"""Props for [`SegmentedControl`][pythonnative.SegmentedControl]."""
|
|
366
|
+
|
|
367
|
+
segments: List[str] = field(default_factory=list)
|
|
368
|
+
selected_index: int = 0
|
|
369
|
+
on_change: Optional[Callable[[int], None]] = None
|
|
370
|
+
enabled: bool = True
|
|
371
|
+
tint_color: Optional[Color] = None
|
|
372
|
+
accessibility_label: Optional[str] = None
|
|
373
|
+
accessible: Optional[bool] = None
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
@dataclass(frozen=True)
|
|
377
|
+
class DatePickerProps(Props):
|
|
378
|
+
"""Props for [`DatePicker`][pythonnative.DatePicker].
|
|
379
|
+
|
|
380
|
+
``value`` and the value passed to ``on_change`` are ISO-8601
|
|
381
|
+
strings (``"2026-05-31"`` for ``mode="date"``, ``"14:30"`` for
|
|
382
|
+
``mode="time"``, ``"2026-05-31T14:30"`` for ``mode="datetime"``),
|
|
383
|
+
so the schema stays JSON-serializable and platform-agnostic.
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
value: Optional[str] = None
|
|
387
|
+
mode: Literal["date", "time", "datetime"] = "date"
|
|
388
|
+
on_change: Optional[Callable[[str], None]] = None
|
|
389
|
+
minimum: Optional[str] = None
|
|
390
|
+
maximum: Optional[str] = None
|
|
391
|
+
enabled: bool = True
|
|
392
|
+
accessibility_label: Optional[str] = None
|
|
393
|
+
accessible: Optional[bool] = None
|
|
394
|
+
|
|
395
|
+
|
|
299
396
|
# ======================================================================
|
|
300
397
|
# Leaf factories
|
|
301
398
|
# ======================================================================
|
|
@@ -416,6 +513,12 @@ def TextInput(
|
|
|
416
513
|
return_key_type: Optional[ReturnKeyType] = None,
|
|
417
514
|
max_length: Optional[int] = None,
|
|
418
515
|
placeholder_color: Optional[Color] = None,
|
|
516
|
+
editable: bool = True,
|
|
517
|
+
clear_button: bool = False,
|
|
518
|
+
on_focus: Optional[Callable[[], None]] = None,
|
|
519
|
+
on_blur: Optional[Callable[[], None]] = None,
|
|
520
|
+
selection_color: Optional[Color] = None,
|
|
521
|
+
text_content_type: Optional[str] = None,
|
|
419
522
|
style: StyleProp = None,
|
|
420
523
|
accessibility_label: Optional[str] = None,
|
|
421
524
|
accessibility_hint: Optional[str] = None,
|
|
@@ -446,6 +549,16 @@ def TextInput(
|
|
|
446
549
|
``"next"``, ``"send"``, ``"search"``.
|
|
447
550
|
max_length: Maximum number of characters allowed.
|
|
448
551
|
placeholder_color: Color used for the placeholder string.
|
|
552
|
+
editable: When ``False``, the field is read-only (still
|
|
553
|
+
selectable).
|
|
554
|
+
clear_button: When ``True``, shows a clear ("x") button while
|
|
555
|
+
editing (iOS ``clearButtonMode``; an inline button on
|
|
556
|
+
Android).
|
|
557
|
+
on_focus: Callback invoked when the field gains focus.
|
|
558
|
+
on_blur: Callback invoked when the field loses focus.
|
|
559
|
+
selection_color: Cursor / selection highlight color.
|
|
560
|
+
text_content_type: Semantic content hint for autofill (e.g.
|
|
561
|
+
``"username"``, ``"password"``, ``"one_time_code"``).
|
|
449
562
|
style: Style dict (or list of dicts).
|
|
450
563
|
accessibility_label: Spoken description for screen readers.
|
|
451
564
|
accessibility_hint: Spoken extra detail (iOS only).
|
|
@@ -474,6 +587,12 @@ def TextInput(
|
|
|
474
587
|
return_key_type=return_key_type,
|
|
475
588
|
max_length=max_length,
|
|
476
589
|
placeholder_color=placeholder_color,
|
|
590
|
+
editable=False if editable is False else None,
|
|
591
|
+
clear_button=clear_button or None,
|
|
592
|
+
on_focus=on_focus,
|
|
593
|
+
on_blur=on_blur,
|
|
594
|
+
selection_color=selection_color,
|
|
595
|
+
text_content_type=text_content_type,
|
|
477
596
|
accessibility_label=accessibility_label,
|
|
478
597
|
accessibility_hint=accessibility_hint,
|
|
479
598
|
accessible=accessible,
|
|
@@ -563,17 +682,25 @@ def Switch(
|
|
|
563
682
|
def ProgressBar(
|
|
564
683
|
*,
|
|
565
684
|
value: float = 0.0,
|
|
685
|
+
color: Optional[Color] = None,
|
|
686
|
+
track_color: Optional[Color] = None,
|
|
687
|
+
indeterminate: bool = False,
|
|
566
688
|
style: StyleProp = None,
|
|
567
689
|
key: Optional[str] = None,
|
|
568
690
|
) -> Element:
|
|
569
691
|
"""Show determinate progress as a value between ``0.0`` and ``1.0``.
|
|
570
692
|
|
|
571
|
-
For
|
|
572
|
-
[`ActivityIndicator`][pythonnative.ActivityIndicator]
|
|
693
|
+
For a spinner instead of a bar, use
|
|
694
|
+
[`ActivityIndicator`][pythonnative.ActivityIndicator]; for an
|
|
695
|
+
indeterminate *bar* pass ``indeterminate=True``.
|
|
573
696
|
|
|
574
697
|
Args:
|
|
575
698
|
value: Fraction complete (clamped to ``[0.0, 1.0]`` by the
|
|
576
699
|
platform handler).
|
|
700
|
+
color: Color of the filled portion of the bar.
|
|
701
|
+
track_color: Color of the unfilled track behind the fill.
|
|
702
|
+
indeterminate: When ``True``, the bar animates continuously and
|
|
703
|
+
``value`` is ignored.
|
|
577
704
|
style: Style dict (or list of dicts).
|
|
578
705
|
key: Stable identity for keyed reconciliation.
|
|
579
706
|
|
|
@@ -585,12 +712,17 @@ def ProgressBar(
|
|
|
585
712
|
style=style,
|
|
586
713
|
key=key,
|
|
587
714
|
value=value,
|
|
715
|
+
color=color,
|
|
716
|
+
track_color=track_color,
|
|
717
|
+
indeterminate=indeterminate or None,
|
|
588
718
|
)
|
|
589
719
|
|
|
590
720
|
|
|
591
721
|
def ActivityIndicator(
|
|
592
722
|
*,
|
|
593
723
|
animating: bool = True,
|
|
724
|
+
color: Optional[Color] = None,
|
|
725
|
+
size: Literal["small", "large"] = "small",
|
|
594
726
|
style: StyleProp = None,
|
|
595
727
|
key: Optional[str] = None,
|
|
596
728
|
) -> Element:
|
|
@@ -598,6 +730,8 @@ def ActivityIndicator(
|
|
|
598
730
|
|
|
599
731
|
Args:
|
|
600
732
|
animating: When ``False``, the spinner is hidden.
|
|
733
|
+
color: Spinner color.
|
|
734
|
+
size: ``"small"`` (default) or ``"large"``.
|
|
601
735
|
style: Style dict (or list of dicts).
|
|
602
736
|
key: Stable identity for keyed reconciliation.
|
|
603
737
|
|
|
@@ -610,19 +744,40 @@ def ActivityIndicator(
|
|
|
610
744
|
style=style,
|
|
611
745
|
key=key,
|
|
612
746
|
animating=animating,
|
|
747
|
+
color=color,
|
|
748
|
+
size=size,
|
|
613
749
|
)
|
|
614
750
|
|
|
615
751
|
|
|
616
752
|
def WebView(
|
|
617
753
|
*,
|
|
618
754
|
url: str = "",
|
|
755
|
+
html: Optional[str] = None,
|
|
756
|
+
on_load: Optional[Callable[[str], None]] = None,
|
|
757
|
+
on_message: Optional[Callable[[str], None]] = None,
|
|
758
|
+
on_navigation_state_change: Optional[Callable[[str], None]] = None,
|
|
759
|
+
inject_javascript: Optional[str] = None,
|
|
760
|
+
scroll_enabled: bool = True,
|
|
619
761
|
style: StyleProp = None,
|
|
620
762
|
key: Optional[str] = None,
|
|
621
763
|
) -> Element:
|
|
622
|
-
"""Embed web content from a URL.
|
|
764
|
+
"""Embed web content from a URL or an inline HTML string.
|
|
623
765
|
|
|
624
766
|
Args:
|
|
625
|
-
url: HTTP(S) URL to load.
|
|
767
|
+
url: HTTP(S) URL to load. Ignored when ``html`` is given.
|
|
768
|
+
html: Inline HTML markup to render instead of loading a URL.
|
|
769
|
+
on_load: Callback invoked with the final URL once a page
|
|
770
|
+
finishes loading.
|
|
771
|
+
on_message: Callback invoked with the string payload whenever
|
|
772
|
+
page JavaScript calls
|
|
773
|
+
``window.pythonnative.postMessage(...)``.
|
|
774
|
+
on_navigation_state_change: Callback invoked with the URL each
|
|
775
|
+
time the top-level document begins navigating.
|
|
776
|
+
inject_javascript: JavaScript evaluated after each page load
|
|
777
|
+
(useful for installing the ``postMessage`` bridge or
|
|
778
|
+
tweaking the DOM).
|
|
779
|
+
scroll_enabled: When ``False``, disables scrolling inside the
|
|
780
|
+
web content.
|
|
626
781
|
style: Style dict (or list of dicts).
|
|
627
782
|
key: Stable identity for keyed reconciliation.
|
|
628
783
|
|
|
@@ -634,6 +789,12 @@ def WebView(
|
|
|
634
789
|
style=style,
|
|
635
790
|
key=key,
|
|
636
791
|
url=url or None,
|
|
792
|
+
html=html,
|
|
793
|
+
on_load=on_load,
|
|
794
|
+
on_message=on_message,
|
|
795
|
+
on_navigation_state_change=on_navigation_state_change,
|
|
796
|
+
inject_javascript=inject_javascript,
|
|
797
|
+
scroll_enabled=False if scroll_enabled is False else None,
|
|
637
798
|
)
|
|
638
799
|
|
|
639
800
|
|
|
@@ -833,6 +994,12 @@ def ScrollView(
|
|
|
833
994
|
*children: Element,
|
|
834
995
|
refresh_control: Optional[Dict[str, Any]] = None,
|
|
835
996
|
scroll_axis: Optional[Literal["vertical", "horizontal"]] = None,
|
|
997
|
+
on_scroll: Optional[Callable[[float, float], None]] = None,
|
|
998
|
+
shows_scroll_indicator: bool = True,
|
|
999
|
+
paging_enabled: bool = False,
|
|
1000
|
+
bounces: bool = True,
|
|
1001
|
+
content_container_style: StyleProp = None,
|
|
1002
|
+
keyboard_dismiss_mode: Optional[Literal["none", "on_drag", "interactive"]] = None,
|
|
836
1003
|
style: StyleProp = None,
|
|
837
1004
|
ref: Optional[Dict[str, Any]] = None,
|
|
838
1005
|
key: Optional[str] = None,
|
|
@@ -852,6 +1019,18 @@ def ScrollView(
|
|
|
852
1019
|
must have ``refreshing`` (bool) and ``on_refresh``
|
|
853
1020
|
(callable).
|
|
854
1021
|
scroll_axis: ``"vertical"`` (default) or ``"horizontal"``.
|
|
1022
|
+
on_scroll: Callback invoked with ``(x, y)`` content offsets as
|
|
1023
|
+
the user scrolls.
|
|
1024
|
+
shows_scroll_indicator: When ``False``, hides the scroll bar.
|
|
1025
|
+
paging_enabled: When ``True``, the scroll view snaps to
|
|
1026
|
+
multiples of its own size (carousel behavior).
|
|
1027
|
+
bounces: When ``False``, disables the iOS rubber-band overscroll.
|
|
1028
|
+
content_container_style: Style applied to the inner content
|
|
1029
|
+
wrapper (padding, alignment, spacing of the scrollable
|
|
1030
|
+
content), distinct from ``style`` (the scroll view frame).
|
|
1031
|
+
keyboard_dismiss_mode: ``"none"`` (default), ``"on_drag"``, or
|
|
1032
|
+
``"interactive"`` — controls whether scrolling dismisses
|
|
1033
|
+
the keyboard.
|
|
855
1034
|
style: Style dict (or list of dicts).
|
|
856
1035
|
ref: Optional ``use_ref()`` dict.
|
|
857
1036
|
key: Stable identity for keyed reconciliation.
|
|
@@ -867,6 +1046,12 @@ def ScrollView(
|
|
|
867
1046
|
key=key,
|
|
868
1047
|
refresh_control=refresh_control,
|
|
869
1048
|
scroll_axis=scroll_axis,
|
|
1049
|
+
on_scroll=on_scroll,
|
|
1050
|
+
shows_scroll_indicator=False if shows_scroll_indicator is False else None,
|
|
1051
|
+
paging_enabled=paging_enabled or None,
|
|
1052
|
+
bounces=False if bounces is False else None,
|
|
1053
|
+
content_container_style=resolve_style(content_container_style) or None,
|
|
1054
|
+
keyboard_dismiss_mode=keyboard_dismiss_mode,
|
|
870
1055
|
)
|
|
871
1056
|
|
|
872
1057
|
|
|
@@ -897,9 +1082,12 @@ def Modal(
|
|
|
897
1082
|
*children: Element,
|
|
898
1083
|
visible: bool = False,
|
|
899
1084
|
on_dismiss: Optional[Callable[[], None]] = None,
|
|
1085
|
+
on_show: Optional[Callable[[], None]] = None,
|
|
900
1086
|
title: Optional[str] = None,
|
|
901
1087
|
animation_type: Literal["slide", "fade", "none"] = "slide",
|
|
902
1088
|
transparent: bool = False,
|
|
1089
|
+
presentation_style: Literal["page_sheet", "form_sheet", "full_screen", "overlay"] = "page_sheet",
|
|
1090
|
+
dismiss_on_backdrop: bool = True,
|
|
903
1091
|
style: StyleProp = None,
|
|
904
1092
|
key: Optional[str] = None,
|
|
905
1093
|
) -> Element:
|
|
@@ -919,10 +1107,20 @@ def Modal(
|
|
|
919
1107
|
visible: Controls whether the modal is presented.
|
|
920
1108
|
on_dismiss: Callback invoked when the user dismisses the modal
|
|
921
1109
|
via system gesture.
|
|
1110
|
+
on_show: Callback invoked once the modal has finished
|
|
1111
|
+
presenting.
|
|
922
1112
|
title: Optional title-bar text.
|
|
923
1113
|
animation_type: ``"slide"`` (default), ``"fade"``, or ``"none"``.
|
|
924
1114
|
transparent: When ``True``, the underlying view is dimmed
|
|
925
1115
|
instead of fully covered.
|
|
1116
|
+
presentation_style: iOS presentation style —
|
|
1117
|
+
``"page_sheet"`` (default), ``"form_sheet"``,
|
|
1118
|
+
``"full_screen"``, or ``"overlay"`` (custom dimmed
|
|
1119
|
+
overlay). On Android, ``"overlay"`` keeps the dialog
|
|
1120
|
+
non-fullscreen.
|
|
1121
|
+
dismiss_on_backdrop: When ``True`` (default) and
|
|
1122
|
+
``transparent`` / ``"overlay"``, tapping the dimmed
|
|
1123
|
+
backdrop dismisses the modal.
|
|
926
1124
|
style: Style dict (or list of dicts).
|
|
927
1125
|
key: Stable identity for keyed reconciliation.
|
|
928
1126
|
|
|
@@ -937,7 +1135,10 @@ def Modal(
|
|
|
937
1135
|
visible=visible,
|
|
938
1136
|
animation_type=animation_type,
|
|
939
1137
|
transparent=transparent,
|
|
1138
|
+
presentation_style=presentation_style,
|
|
1139
|
+
dismiss_on_backdrop=False if dismiss_on_backdrop is False else None,
|
|
940
1140
|
on_dismiss=on_dismiss,
|
|
1141
|
+
on_show=on_show,
|
|
941
1142
|
title=title,
|
|
942
1143
|
)
|
|
943
1144
|
|
|
@@ -994,6 +1195,264 @@ def Pressable(
|
|
|
994
1195
|
)
|
|
995
1196
|
|
|
996
1197
|
|
|
1198
|
+
# ======================================================================
|
|
1199
|
+
# Touchables & controls
|
|
1200
|
+
# ======================================================================
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
def TouchableOpacity(
|
|
1204
|
+
*children: Element,
|
|
1205
|
+
on_press: Optional[Callable[[], None]] = None,
|
|
1206
|
+
on_long_press: Optional[Callable[[], None]] = None,
|
|
1207
|
+
active_opacity: float = 0.2,
|
|
1208
|
+
disabled: bool = False,
|
|
1209
|
+
style: StyleProp = None,
|
|
1210
|
+
accessibility_label: Optional[str] = None,
|
|
1211
|
+
accessibility_hint: Optional[str] = None,
|
|
1212
|
+
accessibility_role: Optional[str] = None,
|
|
1213
|
+
accessible: Optional[bool] = None,
|
|
1214
|
+
key: Optional[str] = None,
|
|
1215
|
+
) -> Element:
|
|
1216
|
+
"""Wrap children so they fade to ``active_opacity`` while pressed.
|
|
1217
|
+
|
|
1218
|
+
A thin ergonomic alias over [`Pressable`][pythonnative.Pressable]
|
|
1219
|
+
that mirrors React Native's ``TouchableOpacity``: the only visual
|
|
1220
|
+
feedback is an opacity dip on touch-down. When ``disabled`` is set,
|
|
1221
|
+
the press callbacks are dropped so the wrapper is inert.
|
|
1222
|
+
|
|
1223
|
+
Args:
|
|
1224
|
+
*children: Elements to make tappable.
|
|
1225
|
+
on_press: Callback invoked on a normal tap.
|
|
1226
|
+
on_long_press: Callback invoked on a sustained press.
|
|
1227
|
+
active_opacity: Opacity (0–1) applied while the finger is down.
|
|
1228
|
+
disabled: When ``True``, ignores presses and renders at reduced
|
|
1229
|
+
opacity.
|
|
1230
|
+
style: Style dict applied to the wrapper.
|
|
1231
|
+
accessibility_label: Spoken description for screen readers.
|
|
1232
|
+
accessibility_hint: Spoken extra detail (iOS only).
|
|
1233
|
+
accessibility_role: Override the default ``"button"`` role.
|
|
1234
|
+
accessible: Override whether the element is exposed to AT.
|
|
1235
|
+
key: Stable identity for keyed reconciliation.
|
|
1236
|
+
|
|
1237
|
+
Returns:
|
|
1238
|
+
An [`Element`][pythonnative.Element] of type ``"Pressable"``.
|
|
1239
|
+
"""
|
|
1240
|
+
merged_style: StyleProp
|
|
1241
|
+
if disabled:
|
|
1242
|
+
base = resolve_style(style)
|
|
1243
|
+
base.setdefault("opacity", 0.4)
|
|
1244
|
+
merged_style = base
|
|
1245
|
+
else:
|
|
1246
|
+
merged_style = style
|
|
1247
|
+
return Pressable(
|
|
1248
|
+
*children,
|
|
1249
|
+
on_press=None if disabled else on_press,
|
|
1250
|
+
on_long_press=None if disabled else on_long_press,
|
|
1251
|
+
pressed_opacity=active_opacity,
|
|
1252
|
+
style=merged_style,
|
|
1253
|
+
accessibility_label=accessibility_label,
|
|
1254
|
+
accessibility_hint=accessibility_hint,
|
|
1255
|
+
accessibility_role=accessibility_role,
|
|
1256
|
+
accessible=accessible,
|
|
1257
|
+
key=key,
|
|
1258
|
+
)
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
def ImageBackground(
|
|
1262
|
+
*children: Element,
|
|
1263
|
+
source: str = "",
|
|
1264
|
+
scale_type: Optional[ScaleType] = None,
|
|
1265
|
+
style: StyleProp = None,
|
|
1266
|
+
accessibility_label: Optional[str] = None,
|
|
1267
|
+
accessible: Optional[bool] = None,
|
|
1268
|
+
key: Optional[str] = None,
|
|
1269
|
+
) -> Element:
|
|
1270
|
+
"""Render ``children`` layered on top of a background image.
|
|
1271
|
+
|
|
1272
|
+
Composed entirely from existing primitives: an absolutely-filled
|
|
1273
|
+
[`Image`][pythonnative.Image] sits behind a content
|
|
1274
|
+
[`View`][pythonnative.View] holding ``children``. The container's
|
|
1275
|
+
``style`` controls sizing/padding; the image stretches to fill it
|
|
1276
|
+
via ``position: "absolute"`` and zeroed insets.
|
|
1277
|
+
|
|
1278
|
+
Args:
|
|
1279
|
+
*children: Foreground content drawn over the image.
|
|
1280
|
+
source: Image resource name or URL.
|
|
1281
|
+
scale_type: Background fit mode (``"cover"`` is the most common
|
|
1282
|
+
for backgrounds).
|
|
1283
|
+
style: Style dict for the container (size, padding, alignment).
|
|
1284
|
+
accessibility_label: Spoken description of the background image.
|
|
1285
|
+
accessible: Override whether the image is exposed to AT.
|
|
1286
|
+
key: Stable identity for keyed reconciliation.
|
|
1287
|
+
|
|
1288
|
+
Returns:
|
|
1289
|
+
An [`Element`][pythonnative.Element] of type ``"View"`` wrapping
|
|
1290
|
+
the background image and foreground content.
|
|
1291
|
+
"""
|
|
1292
|
+
fill = {"position": "absolute", "top": 0, "left": 0, "right": 0, "bottom": 0}
|
|
1293
|
+
background = Image(
|
|
1294
|
+
source,
|
|
1295
|
+
scale_type=scale_type or "cover",
|
|
1296
|
+
style=fill,
|
|
1297
|
+
accessibility_label=accessibility_label,
|
|
1298
|
+
accessible=accessible,
|
|
1299
|
+
)
|
|
1300
|
+
content = View(*children, style={"flex": 1})
|
|
1301
|
+
return View(
|
|
1302
|
+
background,
|
|
1303
|
+
content,
|
|
1304
|
+
style=[{"overflow": "hidden"}, resolve_style(style)],
|
|
1305
|
+
key=key,
|
|
1306
|
+
)
|
|
1307
|
+
|
|
1308
|
+
|
|
1309
|
+
def Checkbox(
|
|
1310
|
+
*,
|
|
1311
|
+
value: bool = False,
|
|
1312
|
+
on_change: Optional[Callable[[bool], None]] = None,
|
|
1313
|
+
label: Optional[str] = None,
|
|
1314
|
+
disabled: bool = False,
|
|
1315
|
+
color: Optional[Color] = None,
|
|
1316
|
+
style: StyleProp = None,
|
|
1317
|
+
accessibility_label: Optional[str] = None,
|
|
1318
|
+
accessibility_hint: Optional[str] = None,
|
|
1319
|
+
accessible: Optional[bool] = None,
|
|
1320
|
+
key: Optional[str] = None,
|
|
1321
|
+
) -> Element:
|
|
1322
|
+
"""A boolean checkbox with an optional inline label.
|
|
1323
|
+
|
|
1324
|
+
Backed by ``android.widget.CheckBox`` on Android and a checkmark
|
|
1325
|
+
``UIButton`` on iOS. Tapping the control (or its label) toggles the
|
|
1326
|
+
value and fires ``on_change(new_value)``.
|
|
1327
|
+
|
|
1328
|
+
Args:
|
|
1329
|
+
value: Current checked state.
|
|
1330
|
+
on_change: Callback invoked with the new boolean state.
|
|
1331
|
+
label: Optional text shown beside the box (also tappable).
|
|
1332
|
+
disabled: When ``True``, the control is greyed out and inert.
|
|
1333
|
+
color: Tint applied to the checked box.
|
|
1334
|
+
style: Style dict (or list of dicts).
|
|
1335
|
+
accessibility_label: Spoken description for screen readers.
|
|
1336
|
+
accessibility_hint: Spoken extra detail (iOS only).
|
|
1337
|
+
accessible: Override whether the element is exposed to AT.
|
|
1338
|
+
key: Stable identity for keyed reconciliation.
|
|
1339
|
+
|
|
1340
|
+
Returns:
|
|
1341
|
+
An [`Element`][pythonnative.Element] of type ``"Checkbox"``.
|
|
1342
|
+
"""
|
|
1343
|
+
return _make_element(
|
|
1344
|
+
"Checkbox",
|
|
1345
|
+
style=style,
|
|
1346
|
+
key=key,
|
|
1347
|
+
value=value,
|
|
1348
|
+
on_change=on_change,
|
|
1349
|
+
label=label,
|
|
1350
|
+
disabled=disabled or None,
|
|
1351
|
+
color=color,
|
|
1352
|
+
accessibility_label=accessibility_label,
|
|
1353
|
+
accessibility_hint=accessibility_hint,
|
|
1354
|
+
accessible=accessible,
|
|
1355
|
+
_defaults={"accessibility_role": "checkbox"},
|
|
1356
|
+
)
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
def SegmentedControl(
|
|
1360
|
+
*,
|
|
1361
|
+
segments: Optional[List[str]] = None,
|
|
1362
|
+
selected_index: int = 0,
|
|
1363
|
+
on_change: Optional[Callable[[int], None]] = None,
|
|
1364
|
+
enabled: bool = True,
|
|
1365
|
+
tint_color: Optional[Color] = None,
|
|
1366
|
+
style: StyleProp = None,
|
|
1367
|
+
accessibility_label: Optional[str] = None,
|
|
1368
|
+
accessible: Optional[bool] = None,
|
|
1369
|
+
key: Optional[str] = None,
|
|
1370
|
+
) -> Element:
|
|
1371
|
+
"""A horizontal multi-choice control (one selected segment at a time).
|
|
1372
|
+
|
|
1373
|
+
Backed by ``UISegmentedControl`` on iOS and a styled toggle row on
|
|
1374
|
+
Android. Selecting a segment fires ``on_change(index)``.
|
|
1375
|
+
|
|
1376
|
+
Args:
|
|
1377
|
+
segments: Ordered list of segment labels.
|
|
1378
|
+
selected_index: Index of the currently selected segment.
|
|
1379
|
+
on_change: Callback invoked with the newly selected index.
|
|
1380
|
+
enabled: When ``False``, the control is disabled.
|
|
1381
|
+
tint_color: Accent color for the selected segment.
|
|
1382
|
+
style: Style dict (or list of dicts).
|
|
1383
|
+
accessibility_label: Spoken description for screen readers.
|
|
1384
|
+
accessible: Override whether the element is exposed to AT.
|
|
1385
|
+
key: Stable identity for keyed reconciliation.
|
|
1386
|
+
|
|
1387
|
+
Returns:
|
|
1388
|
+
An [`Element`][pythonnative.Element] of type
|
|
1389
|
+
``"SegmentedControl"``.
|
|
1390
|
+
"""
|
|
1391
|
+
return _make_element(
|
|
1392
|
+
"SegmentedControl",
|
|
1393
|
+
style=style,
|
|
1394
|
+
key=key,
|
|
1395
|
+
segments=list(segments) if segments is not None else [],
|
|
1396
|
+
selected_index=selected_index,
|
|
1397
|
+
on_change=on_change,
|
|
1398
|
+
enabled=False if enabled is False else None,
|
|
1399
|
+
tint_color=tint_color,
|
|
1400
|
+
accessibility_label=accessibility_label,
|
|
1401
|
+
accessible=accessible,
|
|
1402
|
+
)
|
|
1403
|
+
|
|
1404
|
+
|
|
1405
|
+
def DatePicker(
|
|
1406
|
+
*,
|
|
1407
|
+
value: Optional[str] = None,
|
|
1408
|
+
mode: Literal["date", "time", "datetime"] = "date",
|
|
1409
|
+
on_change: Optional[Callable[[str], None]] = None,
|
|
1410
|
+
minimum: Optional[str] = None,
|
|
1411
|
+
maximum: Optional[str] = None,
|
|
1412
|
+
enabled: bool = True,
|
|
1413
|
+
style: StyleProp = None,
|
|
1414
|
+
accessibility_label: Optional[str] = None,
|
|
1415
|
+
accessible: Optional[bool] = None,
|
|
1416
|
+
key: Optional[str] = None,
|
|
1417
|
+
) -> Element:
|
|
1418
|
+
"""A native date / time picker.
|
|
1419
|
+
|
|
1420
|
+
Backed by ``UIDatePicker`` on iOS and a trigger button that opens
|
|
1421
|
+
the platform ``DatePickerDialog`` / ``TimePickerDialog`` on
|
|
1422
|
+
Android. ``value`` and the value reported to ``on_change`` are
|
|
1423
|
+
ISO-8601 strings (see [`DatePickerProps`][pythonnative.DatePickerProps]).
|
|
1424
|
+
|
|
1425
|
+
Args:
|
|
1426
|
+
value: Currently selected value as an ISO-8601 string.
|
|
1427
|
+
mode: ``"date"`` (default), ``"time"``, or ``"datetime"``.
|
|
1428
|
+
on_change: Callback invoked with the new ISO-8601 string.
|
|
1429
|
+
minimum: Earliest selectable value (ISO-8601), if any.
|
|
1430
|
+
maximum: Latest selectable value (ISO-8601), if any.
|
|
1431
|
+
enabled: When ``False``, the picker is disabled.
|
|
1432
|
+
style: Style dict (or list of dicts).
|
|
1433
|
+
accessibility_label: Spoken description for screen readers.
|
|
1434
|
+
accessible: Override whether the element is exposed to AT.
|
|
1435
|
+
key: Stable identity for keyed reconciliation.
|
|
1436
|
+
|
|
1437
|
+
Returns:
|
|
1438
|
+
An [`Element`][pythonnative.Element] of type ``"DatePicker"``.
|
|
1439
|
+
"""
|
|
1440
|
+
return _make_element(
|
|
1441
|
+
"DatePicker",
|
|
1442
|
+
style=style,
|
|
1443
|
+
key=key,
|
|
1444
|
+
value=value,
|
|
1445
|
+
mode=mode,
|
|
1446
|
+
on_change=on_change,
|
|
1447
|
+
minimum=minimum,
|
|
1448
|
+
maximum=maximum,
|
|
1449
|
+
enabled=False if enabled is False else None,
|
|
1450
|
+
accessibility_label=accessibility_label,
|
|
1451
|
+
accessible=accessible,
|
|
1452
|
+
_defaults={"accessibility_role": "button"},
|
|
1453
|
+
)
|
|
1454
|
+
|
|
1455
|
+
|
|
997
1456
|
# ======================================================================
|
|
998
1457
|
# Fragment
|
|
999
1458
|
# ======================================================================
|
|
@@ -1108,6 +1567,14 @@ def FlatList(
|
|
|
1108
1567
|
separator_height: float = 0,
|
|
1109
1568
|
refresh_control: Optional[Dict[str, Any]] = None,
|
|
1110
1569
|
on_item_press: Optional[Callable[[int], None]] = None,
|
|
1570
|
+
horizontal: bool = False,
|
|
1571
|
+
num_columns: int = 1,
|
|
1572
|
+
list_header: Optional[Element] = None,
|
|
1573
|
+
list_footer: Optional[Element] = None,
|
|
1574
|
+
list_empty: Optional[Element] = None,
|
|
1575
|
+
on_end_reached: Optional[Callable[[], None]] = None,
|
|
1576
|
+
on_end_reached_threshold: float = 0.5,
|
|
1577
|
+
content_container_style: StyleProp = None,
|
|
1111
1578
|
style: StyleProp = None,
|
|
1112
1579
|
key: Optional[str] = None,
|
|
1113
1580
|
) -> Element:
|
|
@@ -1141,6 +1608,20 @@ def FlatList(
|
|
|
1141
1608
|
[`RefreshControl`][pythonnative.RefreshControl].
|
|
1142
1609
|
on_item_press: Callback invoked with the row index when the
|
|
1143
1610
|
user taps a row (virtualized backend only).
|
|
1611
|
+
horizontal: Lay rows out left-to-right instead of top-to-bottom
|
|
1612
|
+
(forces the eager backend).
|
|
1613
|
+
num_columns: Render items in a grid of this many columns
|
|
1614
|
+
(forces the eager backend). ``1`` (default) is a plain list.
|
|
1615
|
+
list_header: Optional element rendered once above all rows.
|
|
1616
|
+
list_footer: Optional element rendered once below all rows.
|
|
1617
|
+
list_empty: Optional element rendered when ``data`` is empty.
|
|
1618
|
+
on_end_reached: Callback invoked when the user scrolls within
|
|
1619
|
+
``on_end_reached_threshold`` of the end (virtualized
|
|
1620
|
+
backend).
|
|
1621
|
+
on_end_reached_threshold: Fraction of the viewport from the end
|
|
1622
|
+
at which ``on_end_reached`` fires.
|
|
1623
|
+
content_container_style: Style applied to the inner content
|
|
1624
|
+
wrapper (forces the eager backend).
|
|
1144
1625
|
style: Style dict (or list of dicts).
|
|
1145
1626
|
key: Stable identity for keyed reconciliation of the list
|
|
1146
1627
|
itself.
|
|
@@ -1165,16 +1646,70 @@ def FlatList(
|
|
|
1165
1646
|
"""
|
|
1166
1647
|
items_list = list(data or [])
|
|
1167
1648
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1649
|
+
has_ornaments = (
|
|
1650
|
+
num_columns > 1
|
|
1651
|
+
or horizontal
|
|
1652
|
+
or list_header is not None
|
|
1653
|
+
or list_footer is not None
|
|
1654
|
+
or content_container_style is not None
|
|
1655
|
+
or (not items_list and list_empty is not None)
|
|
1656
|
+
)
|
|
1657
|
+
|
|
1658
|
+
if item_height is None or has_ornaments:
|
|
1659
|
+
# Eager fallback for short lists, grids, and lists with
|
|
1660
|
+
# header/footer/empty ornaments (which the fixed-height
|
|
1661
|
+
# virtualizer can't express).
|
|
1662
|
+
rendered: List[Element] = []
|
|
1171
1663
|
for i, item in enumerate(items_list):
|
|
1172
1664
|
el = render_item(item, i) if render_item else Text(str(item))
|
|
1173
1665
|
if key_extractor is not None:
|
|
1174
1666
|
el = Element(el.type, el.props, el.children, key=key_extractor(item, i))
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1667
|
+
rendered.append(el)
|
|
1668
|
+
|
|
1669
|
+
sep = separator_height or None
|
|
1670
|
+
|
|
1671
|
+
if not has_ornaments:
|
|
1672
|
+
# Backward-compatible shape: ScrollView wrapping a single
|
|
1673
|
+
# Column of the rendered rows.
|
|
1674
|
+
inner = Column(*rendered, style={"spacing": sep} if sep else None)
|
|
1675
|
+
return ScrollView(inner, refresh_control=refresh_control, style=style, key=key)
|
|
1676
|
+
|
|
1677
|
+
if not rendered and list_empty is not None:
|
|
1678
|
+
content: List[Element] = [list_empty]
|
|
1679
|
+
elif num_columns > 1:
|
|
1680
|
+
rows: List[Element] = []
|
|
1681
|
+
for start in range(0, len(rendered), num_columns):
|
|
1682
|
+
chunk = rendered[start : start + num_columns]
|
|
1683
|
+
rows.append(
|
|
1684
|
+
Row(
|
|
1685
|
+
*chunk,
|
|
1686
|
+
style={"spacing": separator_height, "flex": 1} if separator_height else {"flex": 1},
|
|
1687
|
+
key=f"row-{start}",
|
|
1688
|
+
)
|
|
1689
|
+
)
|
|
1690
|
+
content = rows
|
|
1691
|
+
elif horizontal:
|
|
1692
|
+
content = [Row(*rendered, style={"spacing": sep} if sep else None)]
|
|
1693
|
+
else:
|
|
1694
|
+
content = [Column(*rendered, style={"spacing": sep} if sep else None)]
|
|
1695
|
+
|
|
1696
|
+
body: List[Element] = []
|
|
1697
|
+
if list_header is not None:
|
|
1698
|
+
body.append(list_header)
|
|
1699
|
+
body.extend(content)
|
|
1700
|
+
if list_footer is not None:
|
|
1701
|
+
body.append(list_footer)
|
|
1702
|
+
|
|
1703
|
+
axis: Literal["vertical", "horizontal"] = "horizontal" if horizontal else "vertical"
|
|
1704
|
+
wrapper = Row if horizontal else Column
|
|
1705
|
+
inner = wrapper(*body, style=content_container_style)
|
|
1706
|
+
return ScrollView(
|
|
1707
|
+
inner,
|
|
1708
|
+
refresh_control=refresh_control,
|
|
1709
|
+
scroll_axis=axis,
|
|
1710
|
+
style=style,
|
|
1711
|
+
key=key,
|
|
1712
|
+
)
|
|
1178
1713
|
|
|
1179
1714
|
# Virtualized path: render_item is invoked lazily by the native
|
|
1180
1715
|
# cell mount callback when each row scrolls into view.
|
|
@@ -1223,6 +1758,8 @@ def FlatList(
|
|
|
1223
1758
|
row_height=row_h,
|
|
1224
1759
|
mount_row=_mount_row,
|
|
1225
1760
|
on_row_press=on_item_press,
|
|
1761
|
+
on_end_reached=on_end_reached,
|
|
1762
|
+
on_end_reached_threshold=on_end_reached_threshold,
|
|
1226
1763
|
refresh_control=refresh_control,
|
|
1227
1764
|
)
|
|
1228
1765
|
|