pythonnative 0.4.0__py3-none-any.whl → 0.6.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 +94 -66
- pythonnative/cli/pn.py +153 -24
- pythonnative/components.py +563 -0
- pythonnative/element.py +53 -0
- pythonnative/hooks.py +287 -0
- pythonnative/hot_reload.py +143 -0
- pythonnative/native_modules/__init__.py +19 -0
- pythonnative/native_modules/camera.py +105 -0
- pythonnative/native_modules/file_system.py +131 -0
- pythonnative/native_modules/location.py +61 -0
- pythonnative/native_modules/notifications.py +151 -0
- pythonnative/native_views.py +1334 -0
- pythonnative/page.py +320 -247
- pythonnative/reconciler.py +262 -0
- pythonnative/style.py +115 -0
- pythonnative/templates/android_template/app/build.gradle +2 -7
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PageFragment.kt +2 -1
- pythonnative/templates/android_template/build.gradle +1 -1
- pythonnative/utils.py +21 -29
- {pythonnative-0.4.0.dist-info → pythonnative-0.6.0.dist-info}/METADATA +20 -19
- {pythonnative-0.4.0.dist-info → pythonnative-0.6.0.dist-info}/RECORD +25 -40
- pythonnative/activity_indicator_view.py +0 -71
- pythonnative/button.py +0 -113
- pythonnative/collection_view.py +0 -0
- pythonnative/date_picker.py +0 -76
- pythonnative/image_view.py +0 -78
- pythonnative/label.py +0 -133
- pythonnative/list_view.py +0 -76
- pythonnative/material_activity_indicator_view.py +0 -71
- pythonnative/material_bottom_navigation_view.py +0 -0
- pythonnative/material_button.py +0 -69
- pythonnative/material_date_picker.py +0 -87
- pythonnative/material_progress_view.py +0 -70
- pythonnative/material_search_bar.py +0 -69
- pythonnative/material_switch.py +0 -69
- pythonnative/material_time_picker.py +0 -76
- pythonnative/material_toolbar.py +0 -0
- pythonnative/picker_view.py +0 -69
- pythonnative/progress_view.py +0 -70
- pythonnative/scroll_view.py +0 -101
- pythonnative/search_bar.py +0 -69
- pythonnative/stack_view.py +0 -199
- pythonnative/switch.py +0 -68
- pythonnative/text_field.py +0 -132
- pythonnative/text_view.py +0 -135
- pythonnative/time_picker.py +0 -77
- pythonnative/view.py +0 -173
- pythonnative/web_view.py +0 -60
- {pythonnative-0.4.0.dist-info → pythonnative-0.6.0.dist-info}/WHEEL +0 -0
- {pythonnative-0.4.0.dist-info → pythonnative-0.6.0.dist-info}/entry_points.txt +0 -0
- {pythonnative-0.4.0.dist-info → pythonnative-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {pythonnative-0.4.0.dist-info → pythonnative-0.6.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Cross-platform location / GPS access.
|
|
2
|
+
|
|
3
|
+
Provides methods for requesting the current device location.
|
|
4
|
+
Uses Android's ``LocationManager`` or iOS's ``CLLocationManager``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Callable, Optional, Tuple
|
|
8
|
+
|
|
9
|
+
from ..utils import IS_ANDROID
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Location:
|
|
13
|
+
"""GPS / Location services interface."""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def get_current(
|
|
17
|
+
on_result: Optional[Callable[[Optional[Tuple[float, float]]], None]] = None,
|
|
18
|
+
**options: Any,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""Request the current location.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
on_result:
|
|
25
|
+
``((lat, lon) | None) -> None`` called with coordinates or
|
|
26
|
+
``None`` if location is unavailable.
|
|
27
|
+
"""
|
|
28
|
+
if IS_ANDROID:
|
|
29
|
+
Location._android_get(on_result, **options)
|
|
30
|
+
else:
|
|
31
|
+
Location._ios_get(on_result, **options)
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def _android_get(on_result: Optional[Callable] = None, **options: Any) -> None:
|
|
35
|
+
try:
|
|
36
|
+
from java import jclass
|
|
37
|
+
|
|
38
|
+
from ..utils import get_android_context
|
|
39
|
+
|
|
40
|
+
ctx = get_android_context()
|
|
41
|
+
lm = ctx.getSystemService(jclass("android.content.Context").LOCATION_SERVICE)
|
|
42
|
+
loc = lm.getLastKnownLocation("gps")
|
|
43
|
+
if loc and on_result:
|
|
44
|
+
on_result((loc.getLatitude(), loc.getLongitude()))
|
|
45
|
+
elif on_result:
|
|
46
|
+
on_result(None)
|
|
47
|
+
except Exception:
|
|
48
|
+
if on_result:
|
|
49
|
+
on_result(None)
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def _ios_get(on_result: Optional[Callable] = None, **options: Any) -> None:
|
|
53
|
+
try:
|
|
54
|
+
from rubicon.objc import ObjCClass
|
|
55
|
+
|
|
56
|
+
lm = ObjCClass("CLLocationManager").alloc().init()
|
|
57
|
+
lm.requestWhenInUseAuthorization()
|
|
58
|
+
lm.startUpdatingLocation()
|
|
59
|
+
except Exception:
|
|
60
|
+
if on_result:
|
|
61
|
+
on_result(None)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Cross-platform local notifications.
|
|
2
|
+
|
|
3
|
+
Provides methods for scheduling and cancelling local push notifications.
|
|
4
|
+
Uses Android's ``NotificationManager`` or iOS's ``UNUserNotificationCenter``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Callable, Optional
|
|
8
|
+
|
|
9
|
+
from ..utils import IS_ANDROID
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Notifications:
|
|
13
|
+
"""Local notification interface."""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def request_permission(on_result: Optional[Callable[[bool], None]] = None) -> None:
|
|
17
|
+
"""Request notification permission from the user.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
on_result:
|
|
22
|
+
``(granted: bool) -> None`` called with the permission result.
|
|
23
|
+
"""
|
|
24
|
+
if IS_ANDROID:
|
|
25
|
+
if on_result:
|
|
26
|
+
on_result(True)
|
|
27
|
+
else:
|
|
28
|
+
Notifications._ios_request_permission(on_result)
|
|
29
|
+
|
|
30
|
+
@staticmethod
|
|
31
|
+
def schedule(
|
|
32
|
+
title: str,
|
|
33
|
+
body: str = "",
|
|
34
|
+
delay_seconds: float = 0,
|
|
35
|
+
identifier: str = "default",
|
|
36
|
+
**options: Any,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Schedule a local notification.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
title:
|
|
43
|
+
Notification title.
|
|
44
|
+
body:
|
|
45
|
+
Notification body text.
|
|
46
|
+
delay_seconds:
|
|
47
|
+
Seconds from now until delivery (0 = immediate).
|
|
48
|
+
identifier:
|
|
49
|
+
Unique ID for this notification (for cancellation).
|
|
50
|
+
"""
|
|
51
|
+
if IS_ANDROID:
|
|
52
|
+
Notifications._android_schedule(title, body, delay_seconds, identifier, **options)
|
|
53
|
+
else:
|
|
54
|
+
Notifications._ios_schedule(title, body, delay_seconds, identifier, **options)
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def cancel(identifier: str = "default") -> None:
|
|
58
|
+
"""Cancel a pending notification by its identifier."""
|
|
59
|
+
if IS_ANDROID:
|
|
60
|
+
Notifications._android_cancel(identifier)
|
|
61
|
+
else:
|
|
62
|
+
Notifications._ios_cancel(identifier)
|
|
63
|
+
|
|
64
|
+
# -- Android ---------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
@staticmethod
|
|
67
|
+
def _android_schedule(title: str, body: str, delay_seconds: float, identifier: str, **options: Any) -> None:
|
|
68
|
+
try:
|
|
69
|
+
from java import jclass
|
|
70
|
+
|
|
71
|
+
from ..utils import get_android_context
|
|
72
|
+
|
|
73
|
+
ctx = get_android_context()
|
|
74
|
+
nm = ctx.getSystemService(jclass("android.content.Context").NOTIFICATION_SERVICE)
|
|
75
|
+
channel_id = "pn_default"
|
|
76
|
+
NotificationChannel = jclass("android.app.NotificationChannel")
|
|
77
|
+
channel = NotificationChannel(channel_id, "PythonNative", 3) # IMPORTANCE_DEFAULT
|
|
78
|
+
nm.createNotificationChannel(channel)
|
|
79
|
+
|
|
80
|
+
Builder = jclass("android.app.Notification$Builder")
|
|
81
|
+
builder = Builder(ctx, channel_id)
|
|
82
|
+
builder.setContentTitle(title)
|
|
83
|
+
builder.setContentText(body)
|
|
84
|
+
builder.setSmallIcon(jclass("android.R$drawable").ic_dialog_info)
|
|
85
|
+
nm.notify(abs(hash(identifier)) % (2**31), builder.build())
|
|
86
|
+
except Exception:
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def _android_cancel(identifier: str) -> None:
|
|
91
|
+
try:
|
|
92
|
+
from java import jclass
|
|
93
|
+
|
|
94
|
+
from ..utils import get_android_context
|
|
95
|
+
|
|
96
|
+
ctx = get_android_context()
|
|
97
|
+
nm = ctx.getSystemService(jclass("android.content.Context").NOTIFICATION_SERVICE)
|
|
98
|
+
nm.cancel(abs(hash(identifier)) % (2**31))
|
|
99
|
+
except Exception:
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
# -- iOS -------------------------------------------------------------
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def _ios_request_permission(on_result: Optional[Callable[[bool], None]] = None) -> None:
|
|
106
|
+
try:
|
|
107
|
+
from rubicon.objc import ObjCClass
|
|
108
|
+
|
|
109
|
+
center = ObjCClass("UNUserNotificationCenter").currentNotificationCenter()
|
|
110
|
+
center.requestAuthorizationWithOptions_completionHandler_(0x07, None)
|
|
111
|
+
if on_result:
|
|
112
|
+
on_result(True)
|
|
113
|
+
except Exception:
|
|
114
|
+
if on_result:
|
|
115
|
+
on_result(False)
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def _ios_schedule(title: str, body: str, delay_seconds: float, identifier: str, **options: Any) -> None:
|
|
119
|
+
try:
|
|
120
|
+
from rubicon.objc import ObjCClass
|
|
121
|
+
|
|
122
|
+
content = ObjCClass("UNMutableNotificationContent").alloc().init()
|
|
123
|
+
content.setTitle_(title)
|
|
124
|
+
content.setBody_(body)
|
|
125
|
+
|
|
126
|
+
if delay_seconds > 0:
|
|
127
|
+
trigger = ObjCClass("UNTimeIntervalNotificationTrigger").triggerWithTimeInterval_repeats_(
|
|
128
|
+
delay_seconds, False
|
|
129
|
+
)
|
|
130
|
+
else:
|
|
131
|
+
trigger = ObjCClass("UNTimeIntervalNotificationTrigger").triggerWithTimeInterval_repeats_(1, False)
|
|
132
|
+
|
|
133
|
+
request = ObjCClass("UNNotificationRequest").requestWithIdentifier_content_trigger_(
|
|
134
|
+
identifier, content, trigger
|
|
135
|
+
)
|
|
136
|
+
center = ObjCClass("UNUserNotificationCenter").currentNotificationCenter()
|
|
137
|
+
center.addNotificationRequest_withCompletionHandler_(request, None)
|
|
138
|
+
except Exception:
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
@staticmethod
|
|
142
|
+
def _ios_cancel(identifier: str) -> None:
|
|
143
|
+
try:
|
|
144
|
+
from rubicon.objc import ObjCClass
|
|
145
|
+
|
|
146
|
+
center = ObjCClass("UNUserNotificationCenter").currentNotificationCenter()
|
|
147
|
+
NSArray = ObjCClass("NSArray")
|
|
148
|
+
arr = NSArray.arrayWithObject_(identifier)
|
|
149
|
+
center.removePendingNotificationRequestsWithIdentifiers_(arr)
|
|
150
|
+
except Exception:
|
|
151
|
+
pass
|