pythonnative 0.4.0__py3-none-any.whl → 0.5.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 (39) hide show
  1. pythonnative/__init__.py +45 -65
  2. pythonnative/cli/pn.py +15 -14
  3. pythonnative/components.py +241 -0
  4. pythonnative/element.py +47 -0
  5. pythonnative/native_views.py +800 -0
  6. pythonnative/page.py +319 -247
  7. pythonnative/reconciler.py +129 -0
  8. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PageFragment.kt +2 -1
  9. pythonnative/utils.py +21 -29
  10. {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/METADATA +35 -17
  11. {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/RECORD +15 -35
  12. pythonnative/activity_indicator_view.py +0 -71
  13. pythonnative/button.py +0 -113
  14. pythonnative/date_picker.py +0 -76
  15. pythonnative/image_view.py +0 -78
  16. pythonnative/label.py +0 -133
  17. pythonnative/list_view.py +0 -76
  18. pythonnative/material_activity_indicator_view.py +0 -71
  19. pythonnative/material_button.py +0 -69
  20. pythonnative/material_date_picker.py +0 -87
  21. pythonnative/material_progress_view.py +0 -70
  22. pythonnative/material_search_bar.py +0 -69
  23. pythonnative/material_switch.py +0 -69
  24. pythonnative/material_time_picker.py +0 -76
  25. pythonnative/picker_view.py +0 -69
  26. pythonnative/progress_view.py +0 -70
  27. pythonnative/scroll_view.py +0 -101
  28. pythonnative/search_bar.py +0 -69
  29. pythonnative/stack_view.py +0 -199
  30. pythonnative/switch.py +0 -68
  31. pythonnative/text_field.py +0 -132
  32. pythonnative/text_view.py +0 -135
  33. pythonnative/time_picker.py +0 -77
  34. pythonnative/view.py +0 -173
  35. pythonnative/web_view.py +0 -60
  36. {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/WHEEL +0 -0
  37. {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/entry_points.txt +0 -0
  38. {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/licenses/LICENSE +0 -0
  39. {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/top_level.txt +0 -0
pythonnative/switch.py DELETED
@@ -1,68 +0,0 @@
1
- from abc import ABC, abstractmethod
2
-
3
- from .utils import IS_ANDROID, get_android_context
4
- from .view import ViewBase
5
-
6
- # ========================================
7
- # Base class
8
- # ========================================
9
-
10
-
11
- class SwitchBase(ABC):
12
- @abstractmethod
13
- def __init__(self) -> None:
14
- super().__init__()
15
-
16
- @abstractmethod
17
- def set_on(self, value: bool) -> "SwitchBase":
18
- pass
19
-
20
- @abstractmethod
21
- def is_on(self) -> bool:
22
- pass
23
-
24
-
25
- if IS_ANDROID:
26
- # ========================================
27
- # Android class
28
- # https://developer.android.com/reference/android/widget/Switch
29
- # ========================================
30
-
31
- from java import jclass
32
-
33
- class Switch(SwitchBase, ViewBase):
34
- def __init__(self, value: bool = False) -> None:
35
- super().__init__()
36
- self.native_class = jclass("android.widget.Switch")
37
- context = get_android_context()
38
- self.native_instance = self.native_class(context)
39
- self.set_on(value)
40
-
41
- def set_on(self, value: bool) -> "Switch":
42
- self.native_instance.setChecked(value)
43
- return self
44
-
45
- def is_on(self) -> bool:
46
- return self.native_instance.isChecked()
47
-
48
- else:
49
- # ========================================
50
- # iOS class
51
- # https://developer.apple.com/documentation/uikit/uiswitch
52
- # ========================================
53
-
54
- from rubicon.objc import ObjCClass
55
-
56
- class Switch(SwitchBase, ViewBase):
57
- def __init__(self, value: bool = False) -> None:
58
- super().__init__()
59
- self.native_class = ObjCClass("UISwitch")
60
- self.native_instance = self.native_class.alloc().init()
61
- self.set_on(value)
62
-
63
- def set_on(self, value: bool) -> "Switch":
64
- self.native_instance.setOn_animated_(value, False)
65
- return self
66
-
67
- def is_on(self) -> bool:
68
- return self.native_instance.isOn()
@@ -1,132 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from typing import Any
3
-
4
- from .utils import IS_ANDROID, get_android_context
5
- from .view import ViewBase
6
-
7
- # ========================================
8
- # Base class
9
- # ========================================
10
-
11
-
12
- class TextFieldBase(ABC):
13
- @abstractmethod
14
- def __init__(self) -> None:
15
- super().__init__()
16
-
17
- @abstractmethod
18
- def set_text(self, text: str) -> "TextFieldBase":
19
- pass
20
-
21
- @abstractmethod
22
- def get_text(self) -> str:
23
- pass
24
-
25
- @abstractmethod
26
- def set_text_color(self, color: Any) -> "TextFieldBase":
27
- pass
28
-
29
- @abstractmethod
30
- def set_text_size(self, size: float) -> "TextFieldBase":
31
- pass
32
-
33
-
34
- if IS_ANDROID:
35
- # ========================================
36
- # Android class
37
- # https://developer.android.com/reference/android/widget/EditText
38
- # ========================================
39
-
40
- from java import jclass
41
-
42
- class TextField(TextFieldBase, ViewBase):
43
- def __init__(self, text: str = "") -> None:
44
- super().__init__()
45
- self.native_class = jclass("android.widget.EditText")
46
- context = get_android_context()
47
- self.native_instance = self.native_class(context)
48
- self.native_instance.setSingleLine(True)
49
- self.set_text(text)
50
-
51
- def set_text(self, text: str) -> "TextField":
52
- self.native_instance.setText(text)
53
- return self
54
-
55
- def get_text(self) -> str:
56
- return self.native_instance.getText().toString()
57
-
58
- def set_text_color(self, color: Any) -> "TextField":
59
- if isinstance(color, str):
60
- c = color.strip()
61
- if c.startswith("#"):
62
- c = c[1:]
63
- if len(c) == 6:
64
- c = "FF" + c
65
- color_int = int(c, 16)
66
- else:
67
- color_int = int(color)
68
- try:
69
- self.native_instance.setTextColor(color_int)
70
- except Exception:
71
- pass
72
- return self
73
-
74
- def set_text_size(self, size_sp: float) -> "TextField":
75
- try:
76
- self.native_instance.setTextSize(float(size_sp))
77
- except Exception:
78
- pass
79
- return self
80
-
81
- else:
82
- # ========================================
83
- # iOS class
84
- # https://developer.apple.com/documentation/uikit/uitextfield
85
- # ========================================
86
-
87
- from rubicon.objc import ObjCClass
88
-
89
- class TextField(TextFieldBase, ViewBase):
90
- def __init__(self, text: str = "") -> None:
91
- super().__init__()
92
- self.native_class = ObjCClass("UITextField")
93
- self.native_instance = self.native_class.alloc().init()
94
- self.set_text(text)
95
-
96
- def set_text(self, text: str) -> "TextField":
97
- self.native_instance.setText_(text)
98
- return self
99
-
100
- def get_text(self) -> str:
101
- return self.native_instance.text()
102
-
103
- def set_text_color(self, color: Any) -> "TextField":
104
- if isinstance(color, str):
105
- c = color.strip()
106
- if c.startswith("#"):
107
- c = c[1:]
108
- if len(c) == 6:
109
- c = "FF" + c
110
- color_int = int(c, 16)
111
- else:
112
- color_int = int(color)
113
- try:
114
- UIColor = ObjCClass("UIColor")
115
- a = ((color_int >> 24) & 0xFF) / 255.0
116
- r = ((color_int >> 16) & 0xFF) / 255.0
117
- g = ((color_int >> 8) & 0xFF) / 255.0
118
- b = (color_int & 0xFF) / 255.0
119
- color_obj = UIColor.colorWithRed_green_blue_alpha_(r, g, b, a)
120
- self.native_instance.setTextColor_(color_obj)
121
- except Exception:
122
- pass
123
- return self
124
-
125
- def set_text_size(self, size: float) -> "TextField":
126
- try:
127
- UIFont = ObjCClass("UIFont")
128
- font = UIFont.systemFontOfSize_(float(size))
129
- self.native_instance.setFont_(font)
130
- except Exception:
131
- pass
132
- return self
pythonnative/text_view.py DELETED
@@ -1,135 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from typing import Any
3
-
4
- from .utils import IS_ANDROID, get_android_context
5
- from .view import ViewBase
6
-
7
- # ========================================
8
- # Base class
9
- # ========================================
10
-
11
-
12
- class TextViewBase(ABC):
13
- @abstractmethod
14
- def __init__(self) -> None:
15
- super().__init__()
16
-
17
- @abstractmethod
18
- def set_text(self, text: str) -> "TextViewBase":
19
- pass
20
-
21
- @abstractmethod
22
- def get_text(self) -> str:
23
- pass
24
-
25
- @abstractmethod
26
- def set_text_color(self, color: Any) -> "TextViewBase":
27
- pass
28
-
29
- @abstractmethod
30
- def set_text_size(self, size: float) -> "TextViewBase":
31
- pass
32
-
33
-
34
- if IS_ANDROID:
35
- # ========================================
36
- # Android class
37
- # https://developer.android.com/reference/android/widget/EditText
38
- # ========================================
39
-
40
- from java import jclass
41
-
42
- class TextView(TextViewBase, ViewBase):
43
- def __init__(self, text: str = "") -> None:
44
- super().__init__()
45
- self.native_class = jclass("android.widget.EditText")
46
- context = get_android_context()
47
- self.native_instance = self.native_class(context)
48
- self.native_instance.setLines(3)
49
- self.native_instance.setMaxLines(5)
50
- self.native_instance.setVerticalScrollBarEnabled(True)
51
- # self.native_instance.movementMethod = ScrollingMovementMethod()
52
- self.set_text(text)
53
-
54
- def set_text(self, text: str) -> "TextView":
55
- self.native_instance.setText(text)
56
- return self
57
-
58
- def get_text(self) -> str:
59
- return self.native_instance.getText().toString()
60
-
61
- def set_text_color(self, color: Any) -> "TextView":
62
- if isinstance(color, str):
63
- c = color.strip()
64
- if c.startswith("#"):
65
- c = c[1:]
66
- if len(c) == 6:
67
- c = "FF" + c
68
- color_int = int(c, 16)
69
- else:
70
- color_int = int(color)
71
- try:
72
- self.native_instance.setTextColor(color_int)
73
- except Exception:
74
- pass
75
- return self
76
-
77
- def set_text_size(self, size_sp: float) -> "TextView":
78
- try:
79
- self.native_instance.setTextSize(float(size_sp))
80
- except Exception:
81
- pass
82
- return self
83
-
84
- else:
85
- # ========================================
86
- # iOS class
87
- # https://developer.apple.com/documentation/uikit/uitextview
88
- # ========================================
89
-
90
- from rubicon.objc import ObjCClass
91
-
92
- class TextView(TextViewBase, ViewBase):
93
- def __init__(self, text: str = "") -> None:
94
- super().__init__()
95
- self.native_class = ObjCClass("UITextView")
96
- self.native_instance = self.native_class.alloc().init()
97
- self.set_text(text)
98
-
99
- def set_text(self, text: str) -> "TextView":
100
- self.native_instance.setText_(text)
101
- return self
102
-
103
- def get_text(self) -> str:
104
- return self.native_instance.text()
105
-
106
- def set_text_color(self, color: Any) -> "TextView":
107
- if isinstance(color, str):
108
- c = color.strip()
109
- if c.startswith("#"):
110
- c = c[1:]
111
- if len(c) == 6:
112
- c = "FF" + c
113
- color_int = int(c, 16)
114
- else:
115
- color_int = int(color)
116
- try:
117
- UIColor = ObjCClass("UIColor")
118
- a = ((color_int >> 24) & 0xFF) / 255.0
119
- r = ((color_int >> 16) & 0xFF) / 255.0
120
- g = ((color_int >> 8) & 0xFF) / 255.0
121
- b = (color_int & 0xFF) / 255.0
122
- color_obj = UIColor.colorWithRed_green_blue_alpha_(r, g, b, a)
123
- self.native_instance.setTextColor_(color_obj)
124
- except Exception:
125
- pass
126
- return self
127
-
128
- def set_text_size(self, size: float) -> "TextView":
129
- try:
130
- UIFont = ObjCClass("UIFont")
131
- font = UIFont.systemFontOfSize_(float(size))
132
- self.native_instance.setFont_(font)
133
- except Exception:
134
- pass
135
- return self
@@ -1,77 +0,0 @@
1
- from abc import ABC, abstractmethod
2
-
3
- from .utils import IS_ANDROID
4
- from .view import ViewBase
5
-
6
- # ========================================
7
- # Base class
8
- # ========================================
9
-
10
-
11
- class TimePickerBase(ABC):
12
- @abstractmethod
13
- def __init__(self) -> None:
14
- super().__init__()
15
-
16
- @abstractmethod
17
- def set_time(self, hour: int, minute: int) -> "TimePickerBase":
18
- pass
19
-
20
- @abstractmethod
21
- def get_time(self) -> tuple:
22
- pass
23
-
24
-
25
- if IS_ANDROID:
26
- # ========================================
27
- # Android class
28
- # https://developer.android.com/reference/android/widget/TimePicker
29
- # ========================================
30
-
31
- from typing import Any
32
-
33
- from java import jclass
34
-
35
- class TimePicker(TimePickerBase, ViewBase):
36
- def __init__(self, context: Any, hour: int = 0, minute: int = 0) -> None:
37
- super().__init__()
38
- self.native_class = jclass("android.widget.TimePicker")
39
- self.native_instance = self.native_class(context)
40
- self.set_time(hour, minute)
41
-
42
- def set_time(self, hour: int, minute: int) -> "TimePicker":
43
- self.native_instance.setHour(hour)
44
- self.native_instance.setMinute(minute)
45
- return self
46
-
47
- def get_time(self) -> tuple:
48
- hour = self.native_instance.getHour()
49
- minute = self.native_instance.getMinute()
50
- return hour, minute
51
-
52
- else:
53
- # ========================================
54
- # iOS class
55
- # https://developer.apple.com/documentation/uikit/uidatepicker
56
- # ========================================
57
-
58
- from datetime import time
59
-
60
- from rubicon.objc import ObjCClass
61
-
62
- class TimePicker(TimePickerBase, ViewBase):
63
- def __init__(self, hour: int = 0, minute: int = 0) -> None:
64
- super().__init__()
65
- self.native_class = ObjCClass("UIDatePicker")
66
- self.native_instance = self.native_class.alloc().init()
67
- self.native_instance.setDatePickerMode_(1) # Setting mode to Time
68
- self.set_time(hour, minute)
69
-
70
- def set_time(self, hour: int, minute: int) -> "TimePicker":
71
- t = time(hour, minute)
72
- self.native_instance.setTime_(t)
73
- return self
74
-
75
- def get_time(self) -> tuple:
76
- t = self.native_instance.time()
77
- return t.hour, t.minute
pythonnative/view.py DELETED
@@ -1,173 +0,0 @@
1
- from abc import ABC
2
- from typing import Any, Optional, Tuple
3
-
4
- # ========================================
5
- # Base class
6
- # ========================================
7
-
8
-
9
- class ViewBase(ABC):
10
- def __init__(self) -> None:
11
- # Native bridge handles return types dynamically; these attributes are set at runtime.
12
- self.native_instance: Any = None
13
- self.native_class: Any = None
14
- # Record margins for parents that can apply them (Android LinearLayout)
15
- self._pn_margin: Optional[Tuple[int, int, int, int]] = None
16
-
17
- # ========================================
18
- # Lightweight style helpers
19
- # ========================================
20
-
21
- def set_background_color(self, color: Any) -> "ViewBase":
22
- """Set background color. Accepts platform color int or CSS-like hex string. Returns self."""
23
- try:
24
- from .utils import IS_ANDROID
25
-
26
- if isinstance(color, str):
27
- # Support formats: #RRGGBB or #AARRGGBB
28
- c = color.strip()
29
- if c.startswith("#"):
30
- c = c[1:]
31
- if len(c) == 6:
32
- c = "FF" + c
33
- color_int = int(c, 16)
34
- else:
35
- color_int = int(color)
36
-
37
- if IS_ANDROID:
38
- # Android expects ARGB int
39
- self.native_instance.setBackgroundColor(color_int)
40
- else:
41
- # iOS expects a UIColor
42
- from rubicon.objc import ObjCClass
43
-
44
- UIColor = ObjCClass("UIColor")
45
- a = ((color_int >> 24) & 0xFF) / 255.0
46
- r = ((color_int >> 16) & 0xFF) / 255.0
47
- g = ((color_int >> 8) & 0xFF) / 255.0
48
- b = (color_int & 0xFF) / 255.0
49
- try:
50
- color_obj = UIColor.colorWithRed_green_blue_alpha_(r, g, b, a)
51
- except Exception:
52
- color_obj = UIColor.blackColor()
53
- try:
54
- self.native_instance.setBackgroundColor_(color_obj)
55
- except Exception:
56
- try:
57
- # Some UIKit classes expose 'backgroundColor' property
58
- self.native_instance.setBackgroundColor_(color_obj)
59
- except Exception:
60
- pass
61
- except Exception:
62
- pass
63
- return self
64
-
65
- def set_padding(
66
- self,
67
- left: Optional[int] = None,
68
- top: Optional[int] = None,
69
- right: Optional[int] = None,
70
- bottom: Optional[int] = None,
71
- all: Optional[int] = None,
72
- horizontal: Optional[int] = None,
73
- vertical: Optional[int] = None,
74
- ) -> "ViewBase":
75
- """Set padding (dp on Android; best-effort on iOS where supported). Returns self.
76
-
77
- When provided, 'all' applies to all sides; 'horizontal' applies to left and right;
78
- 'vertical' applies to top and bottom; individual overrides take precedence.
79
- """
80
- try:
81
- from .utils import IS_ANDROID, get_android_context
82
-
83
- left_value = left
84
- top_value = top
85
- right_value = right
86
- bottom_value = bottom
87
- if all is not None:
88
- left_value = top_value = right_value = bottom_value = all
89
- if horizontal is not None:
90
- left_value = horizontal if left_value is None else left_value
91
- right_value = horizontal if right_value is None else right_value
92
- if vertical is not None:
93
- top_value = vertical if top_value is None else top_value
94
- bottom_value = vertical if bottom_value is None else bottom_value
95
- left_value = left_value or 0
96
- top_value = top_value or 0
97
- right_value = right_value or 0
98
- bottom_value = bottom_value or 0
99
-
100
- if IS_ANDROID:
101
- density = get_android_context().getResources().getDisplayMetrics().density
102
- lpx = int(left_value * density)
103
- tpx = int(top_value * density)
104
- rpx = int(right_value * density)
105
- bpx = int(bottom_value * density)
106
- self.native_instance.setPadding(lpx, tpx, rpx, bpx)
107
- else:
108
- # Best-effort: many UIKit views don't have direct padding; leave to containers (e.g. UIStackView)
109
- # No-op by default.
110
- pass
111
- except Exception:
112
- pass
113
- return self
114
-
115
- def set_margin(
116
- self,
117
- left: Optional[int] = None,
118
- top: Optional[int] = None,
119
- right: Optional[int] = None,
120
- bottom: Optional[int] = None,
121
- all: Optional[int] = None,
122
- horizontal: Optional[int] = None,
123
- vertical: Optional[int] = None,
124
- ) -> "ViewBase":
125
- """Record margins for this view (applied where supported). Returns self.
126
-
127
- Currently applied automatically when added to Android LinearLayout (StackView).
128
- """
129
- try:
130
- left_value = left
131
- top_value = top
132
- right_value = right
133
- bottom_value = bottom
134
- if all is not None:
135
- left_value = top_value = right_value = bottom_value = all
136
- if horizontal is not None:
137
- left_value = horizontal if left_value is None else left_value
138
- right_value = horizontal if right_value is None else right_value
139
- if vertical is not None:
140
- top_value = vertical if top_value is None else top_value
141
- bottom_value = vertical if bottom_value is None else bottom_value
142
- left_value = int(left_value or 0)
143
- top_value = int(top_value or 0)
144
- right_value = int(right_value or 0)
145
- bottom_value = int(bottom_value or 0)
146
- self._pn_margin = (left_value, top_value, right_value, bottom_value)
147
- except Exception:
148
- pass
149
- return self
150
-
151
- def wrap_in_scroll(self) -> Any:
152
- """Return a ScrollView containing this view as its only child. Returns the ScrollView."""
153
- try:
154
- # Local import to avoid circulars
155
- from .scroll_view import ScrollView
156
-
157
- sv = ScrollView()
158
- sv.add_view(self)
159
- return sv
160
- except Exception:
161
- return None
162
-
163
- # @abstractmethod
164
- # def add_view(self, view):
165
- # pass
166
- #
167
- # @abstractmethod
168
- # def set_layout(self, layout):
169
- # pass
170
- #
171
- # @abstractmethod
172
- # def show(self):
173
- # pass
pythonnative/web_view.py DELETED
@@ -1,60 +0,0 @@
1
- from abc import ABC, abstractmethod
2
-
3
- from .utils import IS_ANDROID, get_android_context
4
- from .view import ViewBase
5
-
6
- # ========================================
7
- # Base class
8
- # ========================================
9
-
10
-
11
- class WebViewBase(ABC):
12
- @abstractmethod
13
- def __init__(self) -> None:
14
- super().__init__()
15
-
16
- @abstractmethod
17
- def load_url(self, url: str) -> "WebViewBase":
18
- pass
19
-
20
-
21
- if IS_ANDROID:
22
- # ========================================
23
- # Android class
24
- # https://developer.android.com/reference/android/webkit/WebView
25
- # ========================================
26
-
27
- from java import jclass
28
-
29
- class WebView(WebViewBase, ViewBase):
30
- def __init__(self, url: str = "") -> None:
31
- super().__init__()
32
- self.native_class = jclass("android.webkit.WebView")
33
- context = get_android_context()
34
- self.native_instance = self.native_class(context)
35
- self.load_url(url)
36
-
37
- def load_url(self, url: str) -> "WebView":
38
- self.native_instance.loadUrl(url)
39
- return self
40
-
41
- else:
42
- # ========================================
43
- # iOS class
44
- # https://developer.apple.com/documentation/webkit/wkwebview
45
- # ========================================
46
-
47
- from rubicon.objc import NSURL, NSURLRequest, ObjCClass
48
-
49
- class WebView(WebViewBase, ViewBase):
50
- def __init__(self, url: str = "") -> None:
51
- super().__init__()
52
- self.native_class = ObjCClass("WKWebView")
53
- self.native_instance = self.native_class.alloc().init()
54
- self.load_url(url)
55
-
56
- def load_url(self, url: str) -> "WebView":
57
- ns_url = NSURL.URLWithString_(url)
58
- request = NSURLRequest.requestWithURL_(ns_url)
59
- self.native_instance.loadRequest_(request)
60
- return self