Skip to content

Commit c4eeca4

Browse files
committed
Add more pythonnative views
1 parent c32c8bd commit c4eeca4

File tree

13 files changed

+788
-0
lines changed

13 files changed

+788
-0
lines changed

apps/android_pythonnative_3/app/src/main/python/app/main.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,44 @@ def main(context):
2828
progress_view.set_progress(0.5)
2929
layout.add_view(progress_view)
3030

31+
material_progress_view = pn.MaterialProgressView(context)
32+
material_progress_view.set_progress(0.5)
33+
layout.add_view(material_progress_view)
34+
35+
material_button = pn.MaterialButton(context, "MaterialButton")
36+
layout.add_view(material_button)
37+
38+
search_bar = pn.SearchBar(context)
39+
layout.add_view(search_bar)
40+
41+
image_view = pn.ImageView(context)
42+
layout.add_view(image_view)
43+
44+
picker_view = pn.PickerView(context)
45+
layout.add_view(picker_view)
46+
47+
# date_picker = pn.DatePicker(context)
48+
# layout.add_view(date_picker)
49+
50+
# time_picker = pn.TimePicker(context)
51+
# layout.add_view(time_picker)
52+
53+
# TODO: fix
54+
# material_time_picker = pn.MaterialTimePicker(context)
55+
# layout.add_view(material_time_picker)
56+
57+
# TODO: fix
58+
# material_date_picker = pn.MaterialDatePicker(context)
59+
# layout.add_view(material_date_picker)
60+
61+
# TODO: fix
62+
# material_switch = pn.MaterialSwitch(context)
63+
# layout.add_view(material_switch)
64+
65+
# TODO: fix
66+
# material_search_bar = pn.MaterialSearchBar(context)
67+
# layout.add_view(material_search_bar)
68+
3169
# web_view = pn.WebView(context)
3270
# web_view.load_url("https://www.djangoproject.com/")
3371
# layout.add_view(web_view)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
11
from .activity_indicator_view import ActivityIndicatorView
22
from .button import Button
3+
from .date_picker import DatePicker
4+
from .image_view import ImageView
35
from .label import Label
46
from .linear_layout import LinearLayout
57
from .material_activity_inidicator_view import MaterialActivityIndicatorView
8+
from .material_button import MaterialButton
9+
from .material_date_picker import MaterialDatePicker
10+
from .material_progress_view import MaterialProgressView
11+
from .material_search_bar import MaterialSearchBar
12+
from .material_switch import MaterialSwitch
13+
from .material_time_picker import MaterialTimePicker
14+
from .picker_view import PickerView
615
from .progress_view import ProgressView
716
from .screen import Screen
17+
from .search_bar import SearchBar
818
from .switch import Switch
919
from .text_field import TextField
1020
from .text_view import TextView
21+
from .time_picker import TimePicker
1122
from .web_view import WebView
1223

1324
__all__ = [
1425
"ActivityIndicatorView",
1526
"Button",
27+
"DatePicker",
28+
"ImageView",
1629
"Label",
1730
"LinearLayout",
1831
"MaterialActivityIndicatorView",
32+
"MaterialButton",
33+
"MaterialDatePicker",
34+
"MaterialProgressView",
35+
"MaterialSearchBar",
36+
"MaterialSwitch",
37+
"MaterialTimePicker",
38+
"PickerView",
1939
"ProgressView",
2040
"Screen",
41+
"SearchBar",
2142
"Switch",
2243
"TextField",
2344
"TextView",
45+
"TimePicker",
2446
"WebView",
2547
]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from abc import ABC, abstractmethod
2+
from .utils import IS_ANDROID
3+
from .view import ViewBase
4+
5+
# ========================================
6+
# Base class
7+
# ========================================
8+
9+
10+
class DatePickerBase(ABC):
11+
@abstractmethod
12+
def __init__(self) -> None:
13+
super().__init__()
14+
15+
@abstractmethod
16+
def set_date(self, year: int, month: int, day: int) -> None:
17+
pass
18+
19+
@abstractmethod
20+
def get_date(self) -> tuple:
21+
pass
22+
23+
24+
if IS_ANDROID:
25+
# ========================================
26+
# Android class
27+
# ========================================
28+
29+
from java import jclass
30+
31+
class DatePicker(DatePickerBase, ViewBase):
32+
def __init__(self, context, year: int = 0, month: int = 0, day: int = 0) -> None:
33+
super().__init__()
34+
self.native_class = jclass("android.widget.DatePicker")
35+
self.native_instance = self.native_class(context)
36+
self.set_date(year, month, day)
37+
38+
def set_date(self, year: int, month: int, day: int) -> None:
39+
self.native_instance.updateDate(year, month, day)
40+
41+
def get_date(self) -> tuple:
42+
year = self.native_instance.getYear()
43+
month = self.native_instance.getMonth()
44+
day = self.native_instance.getDayOfMonth()
45+
return year, month, day
46+
47+
else:
48+
# ========================================
49+
# iOS class
50+
# ========================================
51+
52+
from rubicon.objc import ObjCClass
53+
from datetime import datetime
54+
55+
class DatePicker(DatePickerBase, ViewBase):
56+
def __init__(self, year: int = 0, month: int = 0, day: int = 0) -> None:
57+
super().__init__()
58+
self.native_class = ObjCClass("UIDatePicker")
59+
self.native_instance = self.native_class.alloc().init()
60+
self.set_date(year, month, day)
61+
62+
def set_date(self, year: int, month: int, day: int) -> None:
63+
date = datetime(year, month, day)
64+
self.native_instance.setDate_(date)
65+
66+
def get_date(self) -> tuple:
67+
date = self.native_instance.date()
68+
return date.year, date.month, date.day
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from abc import ABC, abstractmethod
2+
from .utils import IS_ANDROID
3+
from .view import ViewBase
4+
5+
# ========================================
6+
# Base class
7+
# ========================================
8+
9+
10+
class ImageViewBase(ABC):
11+
@abstractmethod
12+
def __init__(self) -> None:
13+
super().__init__()
14+
15+
@abstractmethod
16+
def set_image(self, image: str) -> None:
17+
pass
18+
19+
@abstractmethod
20+
def get_image(self) -> str:
21+
pass
22+
23+
24+
if IS_ANDROID:
25+
# ========================================
26+
# Android class
27+
# ========================================
28+
29+
from java import jclass
30+
from java.io import File
31+
from android.graphics.drawable import Drawable
32+
from android.graphics import BitmapFactory
33+
34+
class ImageView(ImageViewBase, ViewBase):
35+
def __init__(self, context, image: str = "") -> None:
36+
super().__init__()
37+
self.native_class = jclass("android.widget.ImageView")
38+
self.native_instance = self.native_class(context)
39+
if image:
40+
self.set_image(image)
41+
42+
def set_image(self, image: str) -> None:
43+
bitmap = BitmapFactory.decodeFile(image)
44+
self.native_instance.setImageBitmap(bitmap)
45+
46+
def get_image(self) -> str:
47+
# Please note that this is a simplistic representation, getting image from ImageView
48+
# in Android would require converting Drawable to Bitmap and then to File
49+
return "Image file path in Android"
50+
51+
else:
52+
# ========================================
53+
# iOS class
54+
# ========================================
55+
56+
from rubicon.objc import ObjCClass
57+
from rubicon.objc.api import NSString, UIImage
58+
59+
class ImageView(ImageViewBase, ViewBase):
60+
def __init__(self, image: str = "") -> None:
61+
super().__init__()
62+
self.native_class = ObjCClass("UIImageView")
63+
self.native_instance = self.native_class.alloc().init()
64+
if image:
65+
self.set_image(image)
66+
67+
def set_image(self, image: str) -> None:
68+
ns_str = NSString.alloc().initWithUTF8String_(image)
69+
ui_image = UIImage.imageNamed_(ns_str)
70+
self.native_instance.setImage_(ui_image)
71+
72+
def get_image(self) -> str:
73+
# Similar to Android, getting the image from UIImageView isn't straightforward.
74+
return "Image file name in iOS"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from abc import ABC, abstractmethod
2+
from .utils import IS_ANDROID
3+
from .view import ViewBase
4+
5+
# ========================================
6+
# Base class
7+
# ========================================
8+
9+
10+
class MaterialButtonBase(ABC):
11+
@abstractmethod
12+
def __init__(self) -> None:
13+
super().__init__()
14+
15+
@abstractmethod
16+
def set_title(self, title: str) -> None:
17+
pass
18+
19+
@abstractmethod
20+
def get_title(self) -> str:
21+
pass
22+
23+
24+
if IS_ANDROID:
25+
# ========================================
26+
# Android class
27+
# ========================================
28+
29+
from java import jclass
30+
31+
class MaterialButton(MaterialButtonBase, ViewBase):
32+
def __init__(self, context, title: str = "") -> None:
33+
super().__init__()
34+
self.native_class = jclass("com.google.android.material.button.MaterialButton")
35+
self.native_instance = self.native_class(context)
36+
self.set_title(title)
37+
38+
def set_title(self, title: str) -> None:
39+
self.native_instance.setText(title)
40+
41+
def get_title(self) -> str:
42+
return self.native_instance.getText().toString()
43+
44+
else:
45+
# ========================================
46+
# iOS class
47+
# ========================================
48+
49+
from rubicon.objc import ObjCClass
50+
51+
class MaterialButton(MaterialButtonBase, ViewBase):
52+
def __init__(self, title: str = "") -> None:
53+
super().__init__()
54+
self.native_class = ObjCClass("UIButton") # Apple does not have a direct equivalent for MaterialButton
55+
self.native_instance = self.native_class.alloc().init()
56+
self.set_title(title)
57+
58+
def set_title(self, title: str) -> None:
59+
self.native_instance.setTitle_forState_(title, 0)
60+
61+
def get_title(self) -> str:
62+
return self.native_instance.titleForState_(0)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from abc import ABC, abstractmethod
2+
from .utils import IS_ANDROID
3+
from .view import ViewBase
4+
5+
# ========================================
6+
# Base class
7+
# ========================================
8+
9+
10+
class MaterialDatePickerBase(ABC):
11+
@abstractmethod
12+
def __init__(self) -> None:
13+
super().__init__()
14+
15+
@abstractmethod
16+
def set_date(self, year: int, month: int, day: int) -> None:
17+
pass
18+
19+
@abstractmethod
20+
def get_date(self) -> tuple:
21+
pass
22+
23+
24+
if IS_ANDROID:
25+
# ========================================
26+
# Android class
27+
# ========================================
28+
29+
from java import jclass
30+
31+
class MaterialDatePicker(MaterialDatePickerBase, ViewBase):
32+
def __init__(self, year: int = 0, month: int = 0, day: int = 0) -> None:
33+
super().__init__()
34+
self.native_class = jclass("com.google.android.material.datepicker.MaterialDatePicker")
35+
self.builder = self.native_class.Builder.datePicker()
36+
self.set_date(year, month, day)
37+
self.native_instance = self.builder.build()
38+
39+
def set_date(self, year: int, month: int, day: int) -> None:
40+
# MaterialDatePicker uses milliseconds since epoch to set date
41+
from java.util import Calendar
42+
cal = Calendar.getInstance()
43+
cal.set(year, month, day)
44+
milliseconds = cal.getTimeInMillis()
45+
self.builder.setSelection(milliseconds)
46+
47+
def get_date(self) -> tuple:
48+
# Convert selection (milliseconds since epoch) back to a date
49+
from java.util import Calendar
50+
cal = Calendar.getInstance()
51+
cal.setTimeInMillis(self.native_instance.getSelection())
52+
return cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)
53+
54+
else:
55+
# ========================================
56+
# iOS class
57+
# ========================================
58+
59+
from rubicon.objc import ObjCClass
60+
from datetime import datetime
61+
62+
class MaterialDatePicker(MaterialDatePickerBase, ViewBase):
63+
def __init__(self, year: int = 0, month: int = 0, day: int = 0) -> None:
64+
super().__init__()
65+
self.native_class = ObjCClass("UIDatePicker")
66+
self.native_instance = self.native_class.alloc().init()
67+
self.set_date(year, month, day)
68+
69+
def set_date(self, year: int, month: int, day: int) -> None:
70+
date = datetime(year, month, day)
71+
self.native_instance.setDate_(date)
72+
73+
def get_date(self) -> tuple:
74+
date = self.native_instance.date()
75+
return date.year, date.month, date.day

0 commit comments

Comments
 (0)