-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalerts.py
More file actions
112 lines (96 loc) · 3.5 KB
/
alerts.py
File metadata and controls
112 lines (96 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""Imperative system alerts.
Modeled on React Native's `Alert.alert()`. Alerts are not part of
the element tree — they're imperative, fire-and-forget calls that
trigger a native dialog.
Example:
```python
import pythonnative as pn
def confirm_delete():
pn.Alert.show(
title="Delete item?",
message="This action cannot be undone.",
buttons=[
{"label": "Cancel", "style": "cancel"},
{
"label": "Delete",
"style": "destructive",
"on_press": delete_item,
},
],
)
```
"""
from __future__ import annotations
from typing import Any, Callable, Dict, List, Optional
from .platform import Platform
class Alert:
"""Imperative alert / action-sheet helper.
All methods are static. Use `Alert.show()` for an alert dialog
and pass ``style="action_sheet"`` for an iOS-style action sheet.
"""
@staticmethod
def show(
*,
title: str,
message: Optional[str] = None,
buttons: Optional[List[Dict[str, Any]]] = None,
style: str = "alert",
) -> None:
"""Present a native alert dialog or action sheet.
Args:
title: Dialog title (required).
message: Optional body text.
buttons: Each button is ``{"label": str, "style":
"default"|"cancel"|"destructive", "on_press": callable}``.
Defaults to a single "OK" button.
style: ``"alert"`` (default) or ``"action_sheet"``.
On iOS this uses ``UIAlertController``; on Android it uses
``AlertDialog.Builder``. On the test backend the call is a
no-op so unit tests don't need to mock UIKit/AndroidX.
"""
if Platform.is_ios:
try:
from .native_views.ios import _present_alert as _ios_present_alert
_ios_present_alert(title=title, message=message, buttons=buttons or [], style=style)
except Exception:
pass
return
if Platform.is_android:
try:
from .native_views.android import _present_alert as _android_present_alert
_android_present_alert(title=title, message=message, buttons=buttons or [], style=style)
except Exception:
pass
return
# Test environment: record the call so unit tests can assert on it.
Alert._test_log.append(
{
"title": title,
"message": message,
"buttons": list(buttons or []),
"style": style,
}
)
@staticmethod
def confirm(
*,
title: str,
message: Optional[str] = None,
confirm_label: str = "OK",
cancel_label: str = "Cancel",
on_confirm: Optional[Callable[[], None]] = None,
on_cancel: Optional[Callable[[], None]] = None,
) -> None:
"""Convenience wrapper for two-button confirm/cancel dialogs."""
Alert.show(
title=title,
message=message,
buttons=[
{"label": cancel_label, "style": "cancel", "on_press": on_cancel},
{"label": confirm_label, "style": "default", "on_press": on_confirm},
],
)
#: Records every Alert.show call when running off-device. Tests
#: should reset this list between cases via
#: ``Alert._test_log.clear()``.
_test_log: List[Dict[str, Any]] = []