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.
- pythonnative/__init__.py +45 -65
- pythonnative/cli/pn.py +15 -14
- pythonnative/components.py +241 -0
- pythonnative/element.py +47 -0
- pythonnative/native_views.py +800 -0
- pythonnative/page.py +319 -247
- pythonnative/reconciler.py +129 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PageFragment.kt +2 -1
- pythonnative/utils.py +21 -29
- {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/METADATA +35 -17
- {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/RECORD +15 -35
- pythonnative/activity_indicator_view.py +0 -71
- pythonnative/button.py +0 -113
- 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_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/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.5.0.dist-info}/WHEEL +0 -0
- {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/entry_points.txt +0 -0
- {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {pythonnative-0.4.0.dist-info → pythonnative-0.5.0.dist-info}/top_level.txt +0 -0
pythonnative/material_switch.py
DELETED
|
@@ -1,69 +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 MaterialSwitchBase(ABC):
|
|
12
|
-
@abstractmethod
|
|
13
|
-
def __init__(self) -> None:
|
|
14
|
-
super().__init__()
|
|
15
|
-
|
|
16
|
-
@abstractmethod
|
|
17
|
-
def set_on(self, value: bool) -> "MaterialSwitchBase":
|
|
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/com/google/android/material/materialswitch/MaterialSwitch
|
|
29
|
-
# ========================================
|
|
30
|
-
|
|
31
|
-
from typing import Any
|
|
32
|
-
|
|
33
|
-
from java import jclass
|
|
34
|
-
|
|
35
|
-
class MaterialSwitch(MaterialSwitchBase, ViewBase):
|
|
36
|
-
def __init__(self, context: Any, value: bool = False) -> None:
|
|
37
|
-
super().__init__()
|
|
38
|
-
self.native_class = jclass("com.google.android.material.switch.MaterialSwitch")
|
|
39
|
-
self.native_instance = self.native_class(context)
|
|
40
|
-
self.set_on(value)
|
|
41
|
-
|
|
42
|
-
def set_on(self, value: bool) -> "MaterialSwitch":
|
|
43
|
-
self.native_instance.setChecked(value)
|
|
44
|
-
return self
|
|
45
|
-
|
|
46
|
-
def is_on(self) -> bool:
|
|
47
|
-
return self.native_instance.isChecked()
|
|
48
|
-
|
|
49
|
-
else:
|
|
50
|
-
# ========================================
|
|
51
|
-
# iOS class
|
|
52
|
-
# https://developer.apple.com/documentation/uikit/uiswitch
|
|
53
|
-
# ========================================
|
|
54
|
-
|
|
55
|
-
from rubicon.objc import ObjCClass
|
|
56
|
-
|
|
57
|
-
class MaterialSwitch(MaterialSwitchBase, ViewBase):
|
|
58
|
-
def __init__(self, value: bool = False) -> None:
|
|
59
|
-
super().__init__()
|
|
60
|
-
self.native_class = ObjCClass("UISwitch")
|
|
61
|
-
self.native_instance = self.native_class.alloc().init()
|
|
62
|
-
self.set_on(value)
|
|
63
|
-
|
|
64
|
-
def set_on(self, value: bool) -> "MaterialSwitch":
|
|
65
|
-
self.native_instance.setOn_animated_(value, False)
|
|
66
|
-
return self
|
|
67
|
-
|
|
68
|
-
def is_on(self) -> bool:
|
|
69
|
-
return self.native_instance.isOn()
|
|
@@ -1,76 +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 MaterialTimePickerBase(ABC):
|
|
12
|
-
@abstractmethod
|
|
13
|
-
def __init__(self) -> None:
|
|
14
|
-
super().__init__()
|
|
15
|
-
|
|
16
|
-
@abstractmethod
|
|
17
|
-
def set_time(self, hour: int, minute: int) -> "MaterialTimePickerBase":
|
|
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/com/google/android/material/timepicker/MaterialTimePicker
|
|
29
|
-
# ========================================
|
|
30
|
-
|
|
31
|
-
from typing import Any
|
|
32
|
-
|
|
33
|
-
from java import jclass
|
|
34
|
-
|
|
35
|
-
class MaterialTimePicker(MaterialTimePickerBase, ViewBase):
|
|
36
|
-
def __init__(self, context: Any, hour: int = 0, minute: int = 0) -> None:
|
|
37
|
-
super().__init__()
|
|
38
|
-
self.native_class = jclass("com.google.android.material.timepicker.MaterialTimePicker")
|
|
39
|
-
self.native_instance = self.native_class(context)
|
|
40
|
-
self.set_time(hour, minute)
|
|
41
|
-
|
|
42
|
-
def set_time(self, hour: int, minute: int) -> "MaterialTimePicker":
|
|
43
|
-
self.native_instance.setTime(hour, minute)
|
|
44
|
-
return self
|
|
45
|
-
|
|
46
|
-
def get_time(self) -> tuple:
|
|
47
|
-
hour = self.native_instance.getHour()
|
|
48
|
-
minute = self.native_instance.getMinute()
|
|
49
|
-
return hour, minute
|
|
50
|
-
|
|
51
|
-
else:
|
|
52
|
-
# ========================================
|
|
53
|
-
# iOS class
|
|
54
|
-
# https://developer.apple.com/documentation/uikit/uidatepicker
|
|
55
|
-
# ========================================
|
|
56
|
-
|
|
57
|
-
from datetime import time
|
|
58
|
-
|
|
59
|
-
from rubicon.objc import ObjCClass
|
|
60
|
-
|
|
61
|
-
class MaterialTimePicker(MaterialTimePickerBase, ViewBase):
|
|
62
|
-
def __init__(self, hour: int = 0, minute: int = 0) -> None:
|
|
63
|
-
super().__init__()
|
|
64
|
-
self.native_class = ObjCClass("UIDatePicker")
|
|
65
|
-
self.native_instance = self.native_class.alloc().init()
|
|
66
|
-
self.native_instance.setDatePickerMode_(1) # Setting mode to Time
|
|
67
|
-
self.set_time(hour, minute)
|
|
68
|
-
|
|
69
|
-
def set_time(self, hour: int, minute: int) -> "MaterialTimePicker":
|
|
70
|
-
t = time(hour, minute)
|
|
71
|
-
self.native_instance.setTime_(t)
|
|
72
|
-
return self
|
|
73
|
-
|
|
74
|
-
def get_time(self) -> tuple:
|
|
75
|
-
t = self.native_instance.time()
|
|
76
|
-
return t.hour, t.minute
|
pythonnative/picker_view.py
DELETED
|
@@ -1,69 +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 PickerViewBase(ABC):
|
|
12
|
-
@abstractmethod
|
|
13
|
-
def __init__(self) -> None:
|
|
14
|
-
super().__init__()
|
|
15
|
-
|
|
16
|
-
@abstractmethod
|
|
17
|
-
def set_selected(self, index: int) -> "PickerViewBase":
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
@abstractmethod
|
|
21
|
-
def get_selected(self) -> int:
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if IS_ANDROID:
|
|
26
|
-
# ========================================
|
|
27
|
-
# Android class
|
|
28
|
-
# https://developer.android.com/reference/android/widget/Spinner
|
|
29
|
-
# ========================================
|
|
30
|
-
|
|
31
|
-
from typing import Any
|
|
32
|
-
|
|
33
|
-
from java import jclass
|
|
34
|
-
|
|
35
|
-
class PickerView(PickerViewBase, ViewBase):
|
|
36
|
-
def __init__(self, context: Any, index: int = 0) -> None:
|
|
37
|
-
super().__init__()
|
|
38
|
-
self.native_class = jclass("android.widget.Spinner")
|
|
39
|
-
self.native_instance = self.native_class(context)
|
|
40
|
-
self.set_selected(index)
|
|
41
|
-
|
|
42
|
-
def set_selected(self, index: int) -> "PickerView":
|
|
43
|
-
self.native_instance.setSelection(index)
|
|
44
|
-
return self
|
|
45
|
-
|
|
46
|
-
def get_selected(self) -> int:
|
|
47
|
-
return self.native_instance.getSelectedItemPosition()
|
|
48
|
-
|
|
49
|
-
else:
|
|
50
|
-
# ========================================
|
|
51
|
-
# iOS class
|
|
52
|
-
# https://developer.apple.com/documentation/uikit/uipickerview
|
|
53
|
-
# ========================================
|
|
54
|
-
|
|
55
|
-
from rubicon.objc import ObjCClass
|
|
56
|
-
|
|
57
|
-
class PickerView(PickerViewBase, ViewBase):
|
|
58
|
-
def __init__(self, index: int = 0) -> None:
|
|
59
|
-
super().__init__()
|
|
60
|
-
self.native_class = ObjCClass("UIPickerView")
|
|
61
|
-
self.native_instance = self.native_class.alloc().init()
|
|
62
|
-
self.set_selected(index)
|
|
63
|
-
|
|
64
|
-
def set_selected(self, index: int) -> "PickerView":
|
|
65
|
-
self.native_instance.selectRow_inComponent_animated_(index, 0, False)
|
|
66
|
-
return self
|
|
67
|
-
|
|
68
|
-
def get_selected(self) -> int:
|
|
69
|
-
return self.native_instance.selectedRowInComponent_(0)
|
pythonnative/progress_view.py
DELETED
|
@@ -1,70 +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 ProgressViewBase(ABC):
|
|
12
|
-
@abstractmethod
|
|
13
|
-
def __init__(self) -> None:
|
|
14
|
-
super().__init__()
|
|
15
|
-
|
|
16
|
-
@abstractmethod
|
|
17
|
-
def set_progress(self, progress: float) -> "ProgressViewBase":
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
@abstractmethod
|
|
21
|
-
def get_progress(self) -> float:
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if IS_ANDROID:
|
|
26
|
-
# ========================================
|
|
27
|
-
# Android class
|
|
28
|
-
# https://developer.android.com/reference/android/widget/ProgressBar
|
|
29
|
-
# ========================================
|
|
30
|
-
|
|
31
|
-
from java import jclass
|
|
32
|
-
|
|
33
|
-
class ProgressView(ProgressViewBase, ViewBase):
|
|
34
|
-
def __init__(self) -> None:
|
|
35
|
-
super().__init__()
|
|
36
|
-
self.native_class = jclass("android.widget.ProgressBar")
|
|
37
|
-
# self.native_instance = self.native_class(context, None, android.R.attr.progressBarStyleHorizontal)
|
|
38
|
-
context = get_android_context()
|
|
39
|
-
self.native_instance = self.native_class(context, None, jclass("android.R$attr").progressBarStyleHorizontal)
|
|
40
|
-
self.native_instance.setIndeterminate(False)
|
|
41
|
-
|
|
42
|
-
def set_progress(self, progress: float) -> "ProgressView":
|
|
43
|
-
self.native_instance.setProgress(int(progress * 100))
|
|
44
|
-
return self
|
|
45
|
-
|
|
46
|
-
def get_progress(self) -> float:
|
|
47
|
-
return self.native_instance.getProgress() / 100.0
|
|
48
|
-
|
|
49
|
-
else:
|
|
50
|
-
# ========================================
|
|
51
|
-
# iOS class
|
|
52
|
-
# https://developer.apple.com/documentation/uikit/uiprogressview
|
|
53
|
-
# ========================================
|
|
54
|
-
|
|
55
|
-
from rubicon.objc import ObjCClass
|
|
56
|
-
|
|
57
|
-
class ProgressView(ProgressViewBase, ViewBase):
|
|
58
|
-
def __init__(self) -> None:
|
|
59
|
-
super().__init__()
|
|
60
|
-
self.native_class = ObjCClass("UIProgressView")
|
|
61
|
-
self.native_instance = self.native_class.alloc().initWithProgressViewStyle_(
|
|
62
|
-
0
|
|
63
|
-
) # 0: UIProgressViewStyleDefault
|
|
64
|
-
|
|
65
|
-
def set_progress(self, progress: float) -> "ProgressView":
|
|
66
|
-
self.native_instance.setProgress_animated_(progress, False)
|
|
67
|
-
return self
|
|
68
|
-
|
|
69
|
-
def get_progress(self) -> float:
|
|
70
|
-
return self.native_instance.progress()
|
pythonnative/scroll_view.py
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
from typing import Any, List
|
|
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 ScrollViewBase(ABC):
|
|
13
|
-
@abstractmethod
|
|
14
|
-
def __init__(self) -> None:
|
|
15
|
-
super().__init__()
|
|
16
|
-
self.views: List[Any] = []
|
|
17
|
-
|
|
18
|
-
@abstractmethod
|
|
19
|
-
def add_view(self, view: Any) -> None:
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
@staticmethod
|
|
23
|
-
@abstractmethod
|
|
24
|
-
def wrap(view: Any) -> "ScrollViewBase":
|
|
25
|
-
"""Return a new ScrollView containing the provided view as its only child."""
|
|
26
|
-
pass
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if IS_ANDROID:
|
|
30
|
-
# ========================================
|
|
31
|
-
# Android class
|
|
32
|
-
# https://developer.android.com/reference/android/widget/ScrollView
|
|
33
|
-
# ========================================
|
|
34
|
-
|
|
35
|
-
from java import jclass
|
|
36
|
-
|
|
37
|
-
class ScrollView(ScrollViewBase, ViewBase):
|
|
38
|
-
def __init__(self) -> None:
|
|
39
|
-
super().__init__()
|
|
40
|
-
self.native_class = jclass("android.widget.ScrollView")
|
|
41
|
-
context = get_android_context()
|
|
42
|
-
self.native_instance = self.native_class(context)
|
|
43
|
-
|
|
44
|
-
def add_view(self, view: Any) -> None:
|
|
45
|
-
self.views.append(view)
|
|
46
|
-
# In Android, ScrollView can host only one direct child
|
|
47
|
-
if len(self.views) == 1:
|
|
48
|
-
self.native_instance.addView(view.native_instance)
|
|
49
|
-
else:
|
|
50
|
-
raise Exception("ScrollView can host only one direct child")
|
|
51
|
-
|
|
52
|
-
@staticmethod
|
|
53
|
-
def wrap(view: Any) -> "ScrollView":
|
|
54
|
-
"""Return a new ScrollView containing the provided view as its only child."""
|
|
55
|
-
sv = ScrollView()
|
|
56
|
-
sv.add_view(view)
|
|
57
|
-
return sv
|
|
58
|
-
|
|
59
|
-
else:
|
|
60
|
-
# ========================================
|
|
61
|
-
# iOS class
|
|
62
|
-
# https://developer.apple.com/documentation/uikit/uiscrollview
|
|
63
|
-
# ========================================
|
|
64
|
-
|
|
65
|
-
from rubicon.objc import ObjCClass
|
|
66
|
-
|
|
67
|
-
class ScrollView(ScrollViewBase, ViewBase):
|
|
68
|
-
def __init__(self) -> None:
|
|
69
|
-
super().__init__()
|
|
70
|
-
self.native_class = ObjCClass("UIScrollView")
|
|
71
|
-
self.native_instance = self.native_class.alloc().initWithFrame_(((0, 0), (0, 0)))
|
|
72
|
-
|
|
73
|
-
def add_view(self, view: Any) -> None:
|
|
74
|
-
self.views.append(view)
|
|
75
|
-
# Add as subview and size child to fill scroll view by default so content is visible
|
|
76
|
-
try:
|
|
77
|
-
self.native_instance.addSubview_(view.native_instance)
|
|
78
|
-
except Exception:
|
|
79
|
-
pass
|
|
80
|
-
# Default layout: if the child has no size yet, size it to fill the scroll view
|
|
81
|
-
# and enable flexible width/height. If the child is already sized explicitly,
|
|
82
|
-
# leave it unchanged.
|
|
83
|
-
try:
|
|
84
|
-
frame = getattr(view.native_instance, "frame")
|
|
85
|
-
size = getattr(frame, "size", None)
|
|
86
|
-
width = getattr(size, "width", 0) if size is not None else 0
|
|
87
|
-
height = getattr(size, "height", 0) if size is not None else 0
|
|
88
|
-
if width <= 0 or height <= 0:
|
|
89
|
-
bounds = self.native_instance.bounds
|
|
90
|
-
view.native_instance.setFrame_(bounds)
|
|
91
|
-
# UIViewAutoresizingFlexibleWidth (2) | UIViewAutoresizingFlexibleHeight (16)
|
|
92
|
-
view.native_instance.setAutoresizingMask_(2 | 16)
|
|
93
|
-
except Exception:
|
|
94
|
-
pass
|
|
95
|
-
|
|
96
|
-
@staticmethod
|
|
97
|
-
def wrap(view: Any) -> "ScrollView":
|
|
98
|
-
"""Return a new ScrollView containing the provided view as its only child."""
|
|
99
|
-
sv = ScrollView()
|
|
100
|
-
sv.add_view(view)
|
|
101
|
-
return sv
|
pythonnative/search_bar.py
DELETED
|
@@ -1,69 +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 SearchBarBase(ABC):
|
|
12
|
-
@abstractmethod
|
|
13
|
-
def __init__(self) -> None:
|
|
14
|
-
super().__init__()
|
|
15
|
-
|
|
16
|
-
@abstractmethod
|
|
17
|
-
def set_query(self, query: str) -> "SearchBarBase":
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
@abstractmethod
|
|
21
|
-
def get_query(self) -> str:
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if IS_ANDROID:
|
|
26
|
-
# ========================================
|
|
27
|
-
# Android class
|
|
28
|
-
# https://developer.android.com/reference/android/widget/SearchView
|
|
29
|
-
# ========================================
|
|
30
|
-
|
|
31
|
-
from typing import Any
|
|
32
|
-
|
|
33
|
-
from java import jclass
|
|
34
|
-
|
|
35
|
-
class SearchBar(SearchBarBase, ViewBase):
|
|
36
|
-
def __init__(self, context: Any, query: str = "") -> None:
|
|
37
|
-
super().__init__()
|
|
38
|
-
self.native_class = jclass("android.widget.SearchView")
|
|
39
|
-
self.native_instance = self.native_class(context)
|
|
40
|
-
self.set_query(query)
|
|
41
|
-
|
|
42
|
-
def set_query(self, query: str) -> "SearchBar":
|
|
43
|
-
self.native_instance.setQuery(query, False)
|
|
44
|
-
return self
|
|
45
|
-
|
|
46
|
-
def get_query(self) -> str:
|
|
47
|
-
return self.native_instance.getQuery().toString()
|
|
48
|
-
|
|
49
|
-
else:
|
|
50
|
-
# ========================================
|
|
51
|
-
# iOS class
|
|
52
|
-
# https://developer.apple.com/documentation/uikit/uisearchbar
|
|
53
|
-
# ========================================
|
|
54
|
-
|
|
55
|
-
from rubicon.objc import ObjCClass
|
|
56
|
-
|
|
57
|
-
class SearchBar(SearchBarBase, ViewBase):
|
|
58
|
-
def __init__(self, query: str = "") -> None:
|
|
59
|
-
super().__init__()
|
|
60
|
-
self.native_class = ObjCClass("UISearchBar")
|
|
61
|
-
self.native_instance = self.native_class.alloc().init()
|
|
62
|
-
self.set_query(query)
|
|
63
|
-
|
|
64
|
-
def set_query(self, query: str) -> "SearchBar":
|
|
65
|
-
self.native_instance.set_text_(query)
|
|
66
|
-
return self
|
|
67
|
-
|
|
68
|
-
def get_query(self) -> str:
|
|
69
|
-
return self.native_instance.text()
|
pythonnative/stack_view.py
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
from typing import Any, List
|
|
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 StackViewBase(ABC):
|
|
13
|
-
@abstractmethod
|
|
14
|
-
def __init__(self) -> None:
|
|
15
|
-
super().__init__()
|
|
16
|
-
self.views: List[Any] = []
|
|
17
|
-
|
|
18
|
-
@abstractmethod
|
|
19
|
-
def add_view(self, view: Any) -> None:
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
@abstractmethod
|
|
23
|
-
def set_axis(self, axis: str) -> "StackViewBase":
|
|
24
|
-
pass
|
|
25
|
-
|
|
26
|
-
@abstractmethod
|
|
27
|
-
def set_spacing(self, spacing: float) -> "StackViewBase":
|
|
28
|
-
pass
|
|
29
|
-
|
|
30
|
-
@abstractmethod
|
|
31
|
-
def set_alignment(self, alignment: str) -> "StackViewBase":
|
|
32
|
-
pass
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if IS_ANDROID:
|
|
36
|
-
# ========================================
|
|
37
|
-
# Android class
|
|
38
|
-
# https://developer.android.com/reference/android/widget/LinearLayout
|
|
39
|
-
# ========================================
|
|
40
|
-
|
|
41
|
-
from java import jclass
|
|
42
|
-
|
|
43
|
-
class StackView(StackViewBase, ViewBase):
|
|
44
|
-
def __init__(self) -> None:
|
|
45
|
-
super().__init__()
|
|
46
|
-
self.native_class = jclass("android.widget.LinearLayout")
|
|
47
|
-
context = get_android_context()
|
|
48
|
-
self.native_instance = self.native_class(context)
|
|
49
|
-
self.native_instance.setOrientation(self.native_class.VERTICAL)
|
|
50
|
-
# Cache context and current orientation for spacing/alignment helpers
|
|
51
|
-
self._context = context
|
|
52
|
-
self._axis = "vertical"
|
|
53
|
-
|
|
54
|
-
def add_view(self, view: Any) -> None:
|
|
55
|
-
self.views.append(view)
|
|
56
|
-
# Apply margins if the child has any recorded (supported for LinearLayout)
|
|
57
|
-
try:
|
|
58
|
-
lp = view.native_instance.getLayoutParams()
|
|
59
|
-
except Exception:
|
|
60
|
-
lp = None
|
|
61
|
-
if lp is None:
|
|
62
|
-
# Create default LayoutParams (WRAP_CONTENT)
|
|
63
|
-
layout_params = jclass("android.widget.LinearLayout$LayoutParams")(-2, -2)
|
|
64
|
-
else:
|
|
65
|
-
layout_params = lp
|
|
66
|
-
margin = getattr(view, "_pn_margin", None)
|
|
67
|
-
if margin is not None:
|
|
68
|
-
left, top, right, bottom = margin
|
|
69
|
-
# Convert dp to px
|
|
70
|
-
density = self._context.getResources().getDisplayMetrics().density
|
|
71
|
-
lpx = int(left * density)
|
|
72
|
-
tpx = int(top * density)
|
|
73
|
-
rpx = int(right * density)
|
|
74
|
-
bpx = int(bottom * density)
|
|
75
|
-
try:
|
|
76
|
-
layout_params.setMargins(lpx, tpx, rpx, bpx)
|
|
77
|
-
except Exception:
|
|
78
|
-
pass
|
|
79
|
-
try:
|
|
80
|
-
view.native_instance.setLayoutParams(layout_params)
|
|
81
|
-
except Exception:
|
|
82
|
-
pass
|
|
83
|
-
self.native_instance.addView(view.native_instance)
|
|
84
|
-
|
|
85
|
-
def set_axis(self, axis: str) -> "StackView":
|
|
86
|
-
"""Set stacking axis: 'vertical' or 'horizontal'. Returns self."""
|
|
87
|
-
axis_l = (axis or "").lower()
|
|
88
|
-
if axis_l not in ("vertical", "horizontal"):
|
|
89
|
-
return self
|
|
90
|
-
orientation = self.native_class.VERTICAL if axis_l == "vertical" else self.native_class.HORIZONTAL
|
|
91
|
-
self.native_instance.setOrientation(orientation)
|
|
92
|
-
self._axis = axis_l
|
|
93
|
-
return self
|
|
94
|
-
|
|
95
|
-
def set_spacing(self, spacing: float) -> "StackView":
|
|
96
|
-
"""Set spacing between children in dp (Android: uses LinearLayout dividers). Returns self."""
|
|
97
|
-
try:
|
|
98
|
-
density = self._context.getResources().getDisplayMetrics().density
|
|
99
|
-
px = max(0, int(spacing * density))
|
|
100
|
-
# Use a transparent GradientDrawable with specified size as divider
|
|
101
|
-
GradientDrawable = jclass("android.graphics.drawable.GradientDrawable")
|
|
102
|
-
drawable = GradientDrawable()
|
|
103
|
-
drawable.setColor(0x00000000)
|
|
104
|
-
if self._axis == "vertical":
|
|
105
|
-
drawable.setSize(1, px)
|
|
106
|
-
else:
|
|
107
|
-
drawable.setSize(px, 1)
|
|
108
|
-
self.native_instance.setShowDividers(self.native_class.SHOW_DIVIDER_MIDDLE)
|
|
109
|
-
self.native_instance.setDividerDrawable(drawable)
|
|
110
|
-
except Exception:
|
|
111
|
-
pass
|
|
112
|
-
return self
|
|
113
|
-
|
|
114
|
-
def set_alignment(self, alignment: str) -> "StackView":
|
|
115
|
-
"""Set cross-axis alignment: 'fill', 'center', 'leading'/'top', 'trailing'/'bottom'. Returns self."""
|
|
116
|
-
try:
|
|
117
|
-
Gravity = jclass("android.view.Gravity")
|
|
118
|
-
a = (alignment or "").lower()
|
|
119
|
-
if self._axis == "vertical":
|
|
120
|
-
# Cross-axis is horizontal
|
|
121
|
-
if a in ("fill",):
|
|
122
|
-
self.native_instance.setGravity(Gravity.FILL_HORIZONTAL)
|
|
123
|
-
elif a in ("center", "centre"):
|
|
124
|
-
self.native_instance.setGravity(Gravity.CENTER_HORIZONTAL)
|
|
125
|
-
elif a in ("leading", "start", "left"):
|
|
126
|
-
self.native_instance.setGravity(Gravity.START)
|
|
127
|
-
elif a in ("trailing", "end", "right"):
|
|
128
|
-
self.native_instance.setGravity(Gravity.END)
|
|
129
|
-
else:
|
|
130
|
-
# Cross-axis is vertical
|
|
131
|
-
if a in ("fill",):
|
|
132
|
-
self.native_instance.setGravity(Gravity.FILL_VERTICAL)
|
|
133
|
-
elif a in ("center", "centre"):
|
|
134
|
-
self.native_instance.setGravity(Gravity.CENTER_VERTICAL)
|
|
135
|
-
elif a in ("top",):
|
|
136
|
-
self.native_instance.setGravity(Gravity.TOP)
|
|
137
|
-
elif a in ("bottom",):
|
|
138
|
-
self.native_instance.setGravity(Gravity.BOTTOM)
|
|
139
|
-
except Exception:
|
|
140
|
-
pass
|
|
141
|
-
return self
|
|
142
|
-
|
|
143
|
-
else:
|
|
144
|
-
# ========================================
|
|
145
|
-
# iOS class
|
|
146
|
-
# https://developer.apple.com/documentation/uikit/uistackview
|
|
147
|
-
# ========================================
|
|
148
|
-
|
|
149
|
-
from rubicon.objc import ObjCClass
|
|
150
|
-
|
|
151
|
-
class StackView(StackViewBase, ViewBase):
|
|
152
|
-
def __init__(self) -> None:
|
|
153
|
-
super().__init__()
|
|
154
|
-
self.native_class = ObjCClass("UIStackView")
|
|
155
|
-
self.native_instance = self.native_class.alloc().initWithFrame_(((0, 0), (0, 0)))
|
|
156
|
-
# Default to vertical axis
|
|
157
|
-
self.native_instance.setAxis_(1)
|
|
158
|
-
|
|
159
|
-
def add_view(self, view: Any) -> None:
|
|
160
|
-
self.views.append(view)
|
|
161
|
-
self.native_instance.addArrangedSubview_(view.native_instance)
|
|
162
|
-
|
|
163
|
-
def set_axis(self, axis: str) -> "StackView":
|
|
164
|
-
"""Set stacking axis: 'vertical' or 'horizontal'. Returns self."""
|
|
165
|
-
axis_l = (axis or "").lower()
|
|
166
|
-
value = 1 if axis_l == "vertical" else 0
|
|
167
|
-
try:
|
|
168
|
-
self.native_instance.setAxis_(value)
|
|
169
|
-
except Exception:
|
|
170
|
-
pass
|
|
171
|
-
return self
|
|
172
|
-
|
|
173
|
-
def set_spacing(self, spacing: float) -> "StackView":
|
|
174
|
-
"""Set spacing between arranged subviews. Returns self."""
|
|
175
|
-
try:
|
|
176
|
-
self.native_instance.setSpacing_(float(spacing))
|
|
177
|
-
except Exception:
|
|
178
|
-
pass
|
|
179
|
-
return self
|
|
180
|
-
|
|
181
|
-
def set_alignment(self, alignment: str) -> "StackView":
|
|
182
|
-
"""Set cross-axis alignment: 'fill', 'center', 'leading'/'top', 'trailing'/'bottom'. Returns self."""
|
|
183
|
-
a = (alignment or "").lower()
|
|
184
|
-
# UIStackViewAlignment: Fill=0, Leading/Top=1, Center=3, Trailing/Bottom=4
|
|
185
|
-
mapping = {
|
|
186
|
-
"fill": 0,
|
|
187
|
-
"leading": 1,
|
|
188
|
-
"top": 1,
|
|
189
|
-
"center": 3,
|
|
190
|
-
"centre": 3,
|
|
191
|
-
"trailing": 4,
|
|
192
|
-
"bottom": 4,
|
|
193
|
-
}
|
|
194
|
-
value = mapping.get(a, 0)
|
|
195
|
-
try:
|
|
196
|
-
self.native_instance.setAlignment_(value)
|
|
197
|
-
except Exception:
|
|
198
|
-
pass
|
|
199
|
-
return self
|