pythonnative 0.11.0__tar.gz → 0.13.0__tar.gz

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 (119) hide show
  1. {pythonnative-0.11.0/src/pythonnative.egg-info → pythonnative-0.13.0}/PKG-INFO +4 -3
  2. {pythonnative-0.11.0 → pythonnative-0.13.0}/README.md +3 -2
  3. {pythonnative-0.11.0 → pythonnative-0.13.0}/pyproject.toml +3 -1
  4. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/__init__.py +37 -3
  5. pythonnative-0.13.0/src/pythonnative/alerts.py +112 -0
  6. pythonnative-0.13.0/src/pythonnative/animated.py +667 -0
  7. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/cli/pn.py +34 -9
  8. pythonnative-0.13.0/src/pythonnative/components.py +1215 -0
  9. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/hooks.py +165 -18
  10. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/hot_reload.py +188 -22
  11. pythonnative-0.13.0/src/pythonnative/native_modules/camera.py +331 -0
  12. pythonnative-0.13.0/src/pythonnative/native_modules/location.py +245 -0
  13. pythonnative-0.13.0/src/pythonnative/native_views/android.py +1602 -0
  14. pythonnative-0.13.0/src/pythonnative/native_views/ios.py +2497 -0
  15. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/navigation.py +178 -35
  16. pythonnative-0.13.0/src/pythonnative/platform.py +152 -0
  17. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/platform_metrics.py +120 -10
  18. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/reconciler.py +71 -10
  19. pythonnative-0.11.0/src/pythonnative/page.py → pythonnative-0.13.0/src/pythonnative/screen.py +344 -73
  20. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/build.gradle +1 -0
  21. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +4 -4
  22. pythonnative-0.13.0/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt +43 -0
  23. pythonnative-0.13.0/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PNVirtualListView.java +129 -0
  24. pythonnative-0.11.0/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PageFragment.kt → pythonnative-0.13.0/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +23 -18
  25. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +6 -6
  26. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/ViewController.swift +50 -25
  27. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/utils.py +5 -5
  28. {pythonnative-0.11.0 → pythonnative-0.13.0/src/pythonnative.egg-info}/PKG-INFO +4 -3
  29. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative.egg-info/SOURCES.txt +13 -3
  30. pythonnative-0.13.0/tests/test_alert.py +68 -0
  31. pythonnative-0.13.0/tests/test_animated.py +168 -0
  32. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_cli.py +24 -10
  33. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_hooks.py +2 -2
  34. pythonnative-0.13.0/tests/test_hot_reload.py +303 -0
  35. pythonnative-0.13.0/tests/test_metric_hooks.py +167 -0
  36. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_navigation.py +266 -12
  37. pythonnative-0.13.0/tests/test_new_components.py +185 -0
  38. pythonnative-0.13.0/tests/test_platform.py +63 -0
  39. pythonnative-0.13.0/tests/test_platform_metrics.py +119 -0
  40. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_reconciler.py +1 -1
  41. pythonnative-0.13.0/tests/test_ref.py +130 -0
  42. pythonnative-0.11.0/tests/test_page.py → pythonnative-0.13.0/tests/test_screen.py +28 -28
  43. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_smoke.py +1 -1
  44. pythonnative-0.11.0/src/pythonnative/components.py +0 -656
  45. pythonnative-0.11.0/src/pythonnative/native_modules/camera.py +0 -121
  46. pythonnative-0.11.0/src/pythonnative/native_modules/location.py +0 -84
  47. pythonnative-0.11.0/src/pythonnative/native_views/android.py +0 -794
  48. pythonnative-0.11.0/src/pythonnative/native_views/ios.py +0 -849
  49. pythonnative-0.11.0/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt +0 -26
  50. pythonnative-0.11.0/tests/test_hot_reload.py +0 -97
  51. pythonnative-0.11.0/tests/test_platform_metrics.py +0 -148
  52. {pythonnative-0.11.0 → pythonnative-0.13.0}/LICENSE +0 -0
  53. {pythonnative-0.11.0 → pythonnative-0.13.0}/setup.cfg +0 -0
  54. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/_ios_log.py +0 -0
  55. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/cli/__init__.py +0 -0
  56. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/element.py +0 -0
  57. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/layout.py +0 -0
  58. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/native_modules/__init__.py +0 -0
  59. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/native_modules/file_system.py +0 -0
  60. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/native_modules/notifications.py +0 -0
  61. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/native_views/__init__.py +0 -0
  62. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/native_views/base.py +0 -0
  63. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/style.py +0 -0
  64. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/proguard-rules.pro +0 -0
  65. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +0 -0
  66. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +0 -0
  67. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +0 -0
  68. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +0 -0
  69. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +0 -0
  70. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +0 -0
  71. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +0 -0
  72. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  73. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  74. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  75. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  76. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  77. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  78. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  79. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  80. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  81. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  82. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/values/colors.xml +0 -0
  83. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/values/strings.xml +0 -0
  84. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/values/themes.xml +0 -0
  85. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +0 -0
  86. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +0 -0
  87. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +0 -0
  88. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +0 -0
  89. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/build.gradle +0 -0
  90. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
  91. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +0 -0
  92. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/gradle.properties +0 -0
  93. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/gradlew +0 -0
  94. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/gradlew.bat +0 -0
  95. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/android_template/settings.gradle +0 -0
  96. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/AppDelegate.swift +0 -0
  97. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +0 -0
  98. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  99. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +0 -0
  100. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +0 -0
  101. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/Base.lproj/Main.storyboard +0 -0
  102. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/Info.plist +0 -0
  103. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +0 -0
  104. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +0 -0
  105. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -0
  106. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +0 -0
  107. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +0 -0
  108. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +0 -0
  109. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative.egg-info/dependency_links.txt +0 -0
  110. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative.egg-info/entry_points.txt +0 -0
  111. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative.egg-info/requires.txt +0 -0
  112. {pythonnative-0.11.0 → pythonnative-0.13.0}/src/pythonnative.egg-info/top_level.txt +0 -0
  113. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_components.py +0 -0
  114. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_element.py +0 -0
  115. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_ios_log.py +0 -0
  116. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_layout.py +0 -0
  117. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_native_views.py +0 -0
  118. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_style.py +0 -0
  119. {pythonnative-0.11.0 → pythonnative-0.13.0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonnative
3
- Version: 0.11.0
3
+ Version: 0.13.0
4
4
  Summary: Cross-platform native UI toolkit for Android and iOS
5
5
  Author: Owen Carey
6
6
  License: MIT License
@@ -101,7 +101,8 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
101
101
  - **Virtual view tree + reconciler:** Element trees are diffed and patched with minimal native mutations, similar to React's reconciliation.
102
102
  - **Direct native bindings:** Python calls platform APIs directly through Chaquopy and rubicon-objc, with no JavaScript bridge.
103
103
  - **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app.
104
- - **Navigation:** Push and pop screens with argument passing via the `use_navigation()` hook.
104
+ - **Native-backed navigation:** Declarative `Stack`, `Tab`, and `Drawer` navigators inspired by React Navigation. The root stack drives the platform's native navigation controller (`UINavigationController` on iOS, AndroidX Navigation Component on Android), so transitions, back gestures, and the hardware back button match what users expect.
105
+ - **Fast Refresh hot reload:** `pn run --hot-reload` watches `app/` and patches edits into the running app on save, preserving component state across most changes.
105
106
  - **Bundled templates:** Android Gradle and iOS Xcode templates are included, so scaffolding requires no network access.
106
107
 
107
108
  ## Quick Start
@@ -119,7 +120,7 @@ import pythonnative as pn
119
120
 
120
121
 
121
122
  @pn.component
122
- def MainPage():
123
+ def App():
123
124
  count, set_count = pn.use_state(0)
124
125
  return pn.Column(
125
126
  pn.Text(f"Count: {count}", style={"font_size": 24}),
@@ -37,7 +37,8 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
37
37
  - **Virtual view tree + reconciler:** Element trees are diffed and patched with minimal native mutations, similar to React's reconciliation.
38
38
  - **Direct native bindings:** Python calls platform APIs directly through Chaquopy and rubicon-objc, with no JavaScript bridge.
39
39
  - **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app.
40
- - **Navigation:** Push and pop screens with argument passing via the `use_navigation()` hook.
40
+ - **Native-backed navigation:** Declarative `Stack`, `Tab`, and `Drawer` navigators inspired by React Navigation. The root stack drives the platform's native navigation controller (`UINavigationController` on iOS, AndroidX Navigation Component on Android), so transitions, back gestures, and the hardware back button match what users expect.
41
+ - **Fast Refresh hot reload:** `pn run --hot-reload` watches `app/` and patches edits into the running app on save, preserving component state across most changes.
41
42
  - **Bundled templates:** Android Gradle and iOS Xcode templates are included, so scaffolding requires no network access.
42
43
 
43
44
  ## Quick Start
@@ -55,7 +56,7 @@ import pythonnative as pn
55
56
 
56
57
 
57
58
  @pn.component
58
- def MainPage():
59
+ def App():
59
60
  count, set_count = pn.use_state(0)
60
61
  return pn.Column(
61
62
  pn.Text(f"Count: {count}", style={"font_size": 24}),
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pythonnative"
7
- version = "0.11.0"
7
+ version = "0.13.0"
8
8
  description = "Cross-platform native UI toolkit for Android and iOS"
9
9
  authors = [
10
10
  { name = "Owen Carey" }
@@ -60,6 +60,8 @@ Repository = "https://github.com/pythonnative/pythonnative"
60
60
  Issues = "https://github.com/pythonnative/pythonnative/issues"
61
61
  Documentation = "https://docs.pythonnative.com/"
62
62
 
63
+
64
+
63
65
  [tool.setuptools.packages.find]
64
66
  where = ["src"]
65
67
 
@@ -23,6 +23,8 @@ Key building blocks:
23
23
  factories.
24
24
  - **Styling** uses a single ``style`` dict per element (or a list of
25
25
  dicts), composable via [`StyleSheet`][pythonnative.StyleSheet].
26
+ - **Animations** use the ``Animated`` namespace, modeled on React
27
+ Native's animation API.
26
28
 
27
29
  Example:
28
30
  ```python
@@ -39,8 +41,10 @@ Example:
39
41
  ```
40
42
  """
41
43
 
42
- __version__ = "0.11.0"
44
+ __version__ = "0.13.0"
43
45
 
46
+ from .alerts import Alert
47
+ from .animated import Animated, AnimatedValue
44
48
  from .components import (
45
49
  ActivityIndicator,
46
50
  Button,
@@ -48,14 +52,19 @@ from .components import (
48
52
  ErrorBoundary,
49
53
  FlatList,
50
54
  Image,
55
+ KeyboardAvoidingView,
51
56
  Modal,
57
+ Picker,
52
58
  Pressable,
53
59
  ProgressBar,
60
+ RefreshControl,
54
61
  Row,
55
62
  SafeAreaView,
56
63
  ScrollView,
64
+ SectionList,
57
65
  Slider,
58
66
  Spacer,
67
+ StatusBar,
59
68
  Switch,
60
69
  Text,
61
70
  TextInput,
@@ -71,12 +80,16 @@ from .hooks import (
71
80
  use_callback,
72
81
  use_context,
73
82
  use_effect,
83
+ use_keyboard_height,
74
84
  use_memo,
75
85
  use_navigation,
76
86
  use_reducer,
77
87
  use_ref,
88
+ use_safe_area_insets,
78
89
  use_state,
90
+ use_window_dimensions,
79
91
  )
92
+ from .native_modules import Camera, FileSystem, Location, Notifications
80
93
  from .navigation import (
81
94
  NavigationContainer,
82
95
  create_drawer_navigator,
@@ -85,7 +98,8 @@ from .navigation import (
85
98
  use_focus_effect,
86
99
  use_route,
87
100
  )
88
- from .page import create_page
101
+ from .platform import Platform
102
+ from .screen import create_screen
89
103
  from .style import StyleSheet, ThemeContext
90
104
 
91
105
  __all__ = [
@@ -96,14 +110,19 @@ __all__ = [
96
110
  "ErrorBoundary",
97
111
  "FlatList",
98
112
  "Image",
113
+ "KeyboardAvoidingView",
99
114
  "Modal",
115
+ "Picker",
100
116
  "Pressable",
101
117
  "ProgressBar",
118
+ "RefreshControl",
102
119
  "Row",
103
120
  "SafeAreaView",
104
121
  "ScrollView",
122
+ "SectionList",
105
123
  "Slider",
106
124
  "Spacer",
125
+ "StatusBar",
107
126
  "Switch",
108
127
  "Text",
109
128
  "TextInput",
@@ -111,7 +130,7 @@ __all__ = [
111
130
  "WebView",
112
131
  # Core
113
132
  "Element",
114
- "create_page",
133
+ "create_screen",
115
134
  # Hooks
116
135
  "batch_updates",
117
136
  "component",
@@ -120,12 +139,15 @@ __all__ = [
120
139
  "use_context",
121
140
  "use_effect",
122
141
  "use_focus_effect",
142
+ "use_keyboard_height",
123
143
  "use_memo",
124
144
  "use_navigation",
125
145
  "use_reducer",
126
146
  "use_ref",
127
147
  "use_route",
148
+ "use_safe_area_insets",
128
149
  "use_state",
150
+ "use_window_dimensions",
129
151
  "Provider",
130
152
  # Navigation
131
153
  "NavigationContainer",
@@ -135,4 +157,16 @@ __all__ = [
135
157
  # Styling
136
158
  "StyleSheet",
137
159
  "ThemeContext",
160
+ # Animation
161
+ "Animated",
162
+ "AnimatedValue",
163
+ # Imperative
164
+ "Alert",
165
+ # Native modules
166
+ "Camera",
167
+ "FileSystem",
168
+ "Location",
169
+ "Notifications",
170
+ # Platform
171
+ "Platform",
138
172
  ]
@@ -0,0 +1,112 @@
1
+ """Imperative system alerts.
2
+
3
+ Modeled on React Native's `Alert.alert()`. Alerts are not part of
4
+ the element tree — they're imperative, fire-and-forget calls that
5
+ trigger a native dialog.
6
+
7
+ Example:
8
+ ```python
9
+ import pythonnative as pn
10
+
11
+ def confirm_delete():
12
+ pn.Alert.show(
13
+ title="Delete item?",
14
+ message="This action cannot be undone.",
15
+ buttons=[
16
+ {"label": "Cancel", "style": "cancel"},
17
+ {
18
+ "label": "Delete",
19
+ "style": "destructive",
20
+ "on_press": delete_item,
21
+ },
22
+ ],
23
+ )
24
+ ```
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ from typing import Any, Callable, Dict, List, Optional
30
+
31
+ from .platform import Platform
32
+
33
+
34
+ class Alert:
35
+ """Imperative alert / action-sheet helper.
36
+
37
+ All methods are static. Use `Alert.show()` for an alert dialog
38
+ and pass ``style="action_sheet"`` for an iOS-style action sheet.
39
+ """
40
+
41
+ @staticmethod
42
+ def show(
43
+ *,
44
+ title: str,
45
+ message: Optional[str] = None,
46
+ buttons: Optional[List[Dict[str, Any]]] = None,
47
+ style: str = "alert",
48
+ ) -> None:
49
+ """Present a native alert dialog or action sheet.
50
+
51
+ Args:
52
+ title: Dialog title (required).
53
+ message: Optional body text.
54
+ buttons: Each button is ``{"label": str, "style":
55
+ "default"|"cancel"|"destructive", "on_press": callable}``.
56
+ Defaults to a single "OK" button.
57
+ style: ``"alert"`` (default) or ``"action_sheet"``.
58
+
59
+ On iOS this uses ``UIAlertController``; on Android it uses
60
+ ``AlertDialog.Builder``. On the test backend the call is a
61
+ no-op so unit tests don't need to mock UIKit/AndroidX.
62
+ """
63
+ if Platform.is_ios:
64
+ try:
65
+ from .native_views.ios import _present_alert as _ios_present_alert
66
+
67
+ _ios_present_alert(title=title, message=message, buttons=buttons or [], style=style)
68
+ except Exception:
69
+ pass
70
+ return
71
+ if Platform.is_android:
72
+ try:
73
+ from .native_views.android import _present_alert as _android_present_alert
74
+
75
+ _android_present_alert(title=title, message=message, buttons=buttons or [], style=style)
76
+ except Exception:
77
+ pass
78
+ return
79
+ # Test environment: record the call so unit tests can assert on it.
80
+ Alert._test_log.append(
81
+ {
82
+ "title": title,
83
+ "message": message,
84
+ "buttons": list(buttons or []),
85
+ "style": style,
86
+ }
87
+ )
88
+
89
+ @staticmethod
90
+ def confirm(
91
+ *,
92
+ title: str,
93
+ message: Optional[str] = None,
94
+ confirm_label: str = "OK",
95
+ cancel_label: str = "Cancel",
96
+ on_confirm: Optional[Callable[[], None]] = None,
97
+ on_cancel: Optional[Callable[[], None]] = None,
98
+ ) -> None:
99
+ """Convenience wrapper for two-button confirm/cancel dialogs."""
100
+ Alert.show(
101
+ title=title,
102
+ message=message,
103
+ buttons=[
104
+ {"label": cancel_label, "style": "cancel", "on_press": on_cancel},
105
+ {"label": confirm_label, "style": "default", "on_press": on_confirm},
106
+ ],
107
+ )
108
+
109
+ #: Records every Alert.show call when running off-device. Tests
110
+ #: should reset this list between cases via
111
+ #: ``Alert._test_log.clear()``.
112
+ _test_log: List[Dict[str, Any]] = []