Skip to content

Commit 7bd71eb

Browse files
Move SettingsActivity to its own file
1 parent 580ba0d commit 7bd71eb

File tree

2 files changed

+222
-216
lines changed

2 files changed

+222
-216
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
import lvgl as lv
2+
3+
import mpos
4+
from mpos.apps import Activity, Intent
5+
6+
"""
7+
SettingActivity is used to edit one setting.
8+
For now, it only supports strings.
9+
"""
10+
class SettingActivity(Activity):
11+
12+
active_radio_index = -1 # Track active radio button index
13+
prefs = None # taken from the intent
14+
15+
# Widgets:
16+
keyboard = None
17+
textarea = None
18+
dropdown = None
19+
radio_container = None
20+
21+
def __init__(self):
22+
super().__init__()
23+
self.setting = None
24+
25+
def onCreate(self):
26+
self.prefs = self.getIntent().extras.get("prefs")
27+
setting = self.getIntent().extras.get("setting")
28+
29+
settings_screen_detail = lv.obj()
30+
settings_screen_detail.set_style_pad_all(mpos.ui.pct_of_display_width(2), 0)
31+
settings_screen_detail.set_flex_flow(lv.FLEX_FLOW.COLUMN)
32+
33+
top_cont = lv.obj(settings_screen_detail)
34+
top_cont.set_width(lv.pct(100))
35+
top_cont.set_style_border_width(0, 0)
36+
top_cont.set_height(lv.SIZE_CONTENT)
37+
top_cont.set_style_pad_all(mpos.ui.pct_of_display_width(1), 0)
38+
top_cont.set_flex_flow(lv.FLEX_FLOW.ROW)
39+
top_cont.set_style_flex_main_place(lv.FLEX_ALIGN.SPACE_BETWEEN, 0)
40+
top_cont.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF)
41+
42+
setting_label = lv.label(top_cont)
43+
setting_label.set_text(setting["title"])
44+
setting_label.align(lv.ALIGN.TOP_LEFT,0,0)
45+
setting_label.set_style_text_font(lv.font_montserrat_20, 0)
46+
47+
ui = setting.get("ui")
48+
ui_options = setting.get("ui_options")
49+
current_setting = self.prefs.get_string(setting["key"])
50+
if ui and ui == "radiobuttons" and ui_options:
51+
# Create container for radio buttons
52+
self.radio_container = lv.obj(settings_screen_detail)
53+
self.radio_container.set_width(lv.pct(100))
54+
self.radio_container.set_height(lv.SIZE_CONTENT)
55+
self.radio_container.set_flex_flow(lv.FLEX_FLOW.COLUMN)
56+
self.radio_container.add_event_cb(self.radio_event_handler, lv.EVENT.VALUE_CHANGED, None)
57+
# Create radio buttons and check the right one
58+
self.active_radio_index = -1 # none
59+
for i, (option_text, option_value) in enumerate(ui_options):
60+
cb = self.create_radio_button(self.radio_container, option_text, i)
61+
if current_setting == option_value:
62+
self.active_radio_index = i
63+
cb.add_state(lv.STATE.CHECKED)
64+
elif ui and ui == "dropdown" and ui_options:
65+
self.dropdown = lv.dropdown(settings_screen_detail)
66+
self.dropdown.set_width(lv.pct(100))
67+
options_with_newlines = ""
68+
for option in ui_options:
69+
if option[0] != option[1]:
70+
options_with_newlines += (f"{option[0]} ({option[1]})\n")
71+
else: # don't show identical options
72+
options_with_newlines += (f"{option[0]}\n")
73+
self.dropdown.set_options(options_with_newlines)
74+
# select the right one:
75+
for i, (option_text, option_value) in enumerate(ui_options):
76+
if current_setting == option_value:
77+
self.dropdown.set_selected(i)
78+
break # no need to check the rest because only one can be selected
79+
else:
80+
# Textarea for other settings
81+
self.textarea = lv.textarea(settings_screen_detail)
82+
self.textarea.set_width(lv.pct(100))
83+
self.textarea.set_height(lv.SIZE_CONTENT)
84+
self.textarea.align_to(top_cont, lv.ALIGN.OUT_BOTTOM_MID, 0, 0)
85+
if current_setting:
86+
self.textarea.set_text(current_setting)
87+
placeholder = setting.get("placeholder")
88+
if placeholder:
89+
self.textarea.set_placeholder_text(placeholder)
90+
self.textarea.add_event_cb(lambda *args: mpos.ui.anim.smooth_show(self.keyboard), lv.EVENT.CLICKED, None) # it might be focused, but keyboard hidden (because ready/cancel clicked)
91+
self.textarea.add_event_cb(lambda *args: mpos.ui.anim.smooth_hide(self.keyboard), lv.EVENT.DEFOCUSED, None)
92+
# Initialize keyboard (hidden initially)
93+
self.keyboard = MposKeyboard(settings_screen_detail)
94+
self.keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0)
95+
self.keyboard.add_flag(lv.obj.FLAG.HIDDEN)
96+
self.keyboard.add_event_cb(lambda *args: mpos.ui.anim.smooth_hide(self.keyboard), lv.EVENT.READY, None)
97+
self.keyboard.add_event_cb(lambda *args: mpos.ui.anim.smooth_hide(self.keyboard), lv.EVENT.CANCEL, None)
98+
self.keyboard.set_textarea(self.textarea)
99+
100+
# Button container
101+
btn_cont = lv.obj(settings_screen_detail)
102+
btn_cont.set_width(lv.pct(100))
103+
btn_cont.set_style_border_width(0, 0)
104+
btn_cont.set_height(lv.SIZE_CONTENT)
105+
btn_cont.set_flex_flow(lv.FLEX_FLOW.ROW)
106+
btn_cont.set_style_flex_main_place(lv.FLEX_ALIGN.SPACE_BETWEEN, 0)
107+
# Save button
108+
save_btn = lv.button(btn_cont)
109+
save_btn.set_size(lv.pct(45), lv.SIZE_CONTENT)
110+
save_label = lv.label(save_btn)
111+
save_label.set_text("Save")
112+
save_label.center()
113+
save_btn.add_event_cb(lambda e, s=setting: self.save_setting(s), lv.EVENT.CLICKED, None)
114+
# Cancel button
115+
cancel_btn = lv.button(btn_cont)
116+
cancel_btn.set_size(lv.pct(45), lv.SIZE_CONTENT)
117+
cancel_label = lv.label(cancel_btn)
118+
cancel_label.set_text("Cancel")
119+
cancel_label.center()
120+
cancel_btn.add_event_cb(lambda e: self.finish(), lv.EVENT.CLICKED, None)
121+
122+
if False: # No scan QR button for text settings because they're all short right now
123+
cambutton = lv.button(settings_screen_detail)
124+
cambutton.align(lv.ALIGN.BOTTOM_MID,0,0)
125+
cambutton.set_size(lv.pct(100), lv.pct(30))
126+
cambuttonlabel = lv.label(cambutton)
127+
cambuttonlabel.set_text("Scan data from QR code")
128+
cambuttonlabel.set_style_text_font(lv.font_montserrat_18, 0)
129+
cambuttonlabel.align(lv.ALIGN.TOP_MID, 0, 0)
130+
cambuttonlabel2 = lv.label(cambutton)
131+
cambuttonlabel2.set_text("Tip: Create your own QR code,\nusing https://genqrcode.com or another tool.")
132+
cambuttonlabel2.set_style_text_font(lv.font_montserrat_10, 0)
133+
cambuttonlabel2.align(lv.ALIGN.BOTTOM_MID, 0, 0)
134+
cambutton.add_event_cb(self.cambutton_cb, lv.EVENT.CLICKED, None)
135+
136+
self.setContentView(settings_screen_detail)
137+
138+
def onStop(self, screen):
139+
if self.keyboard:
140+
mpos.ui.anim.smooth_hide(self.keyboard)
141+
142+
def radio_event_handler(self, event):
143+
print("radio_event_handler called")
144+
target_obj = event.get_target_obj()
145+
target_obj_state = target_obj.get_state()
146+
print(f"target_obj state {target_obj.get_text()} is {target_obj_state}")
147+
checked = target_obj_state & lv.STATE.CHECKED
148+
current_checkbox_index = target_obj.get_index()
149+
print(f"current_checkbox_index: {current_checkbox_index}")
150+
if not checked:
151+
if self.active_radio_index == current_checkbox_index:
152+
print(f"unchecking {current_checkbox_index}")
153+
self.active_radio_index = -1 # nothing checked
154+
return
155+
else:
156+
if self.active_radio_index >= 0: # is there something to uncheck?
157+
old_checked = self.radio_container.get_child(self.active_radio_index)
158+
old_checked.remove_state(lv.STATE.CHECKED)
159+
self.active_radio_index = current_checkbox_index
160+
161+
def create_radio_button(self, parent, text, index):
162+
cb = lv.checkbox(parent)
163+
cb.set_text(text)
164+
cb.add_flag(lv.obj.FLAG.EVENT_BUBBLE)
165+
# Add circular style to indicator for radio button appearance
166+
style_radio = lv.style_t()
167+
style_radio.init()
168+
style_radio.set_radius(lv.RADIUS_CIRCLE)
169+
cb.add_style(style_radio, lv.PART.INDICATOR)
170+
style_radio_chk = lv.style_t()
171+
style_radio_chk.init()
172+
style_radio_chk.set_bg_image_src(None)
173+
cb.add_style(style_radio_chk, lv.PART.INDICATOR | lv.STATE.CHECKED)
174+
return cb
175+
176+
def gotqr_result_callback_unused(self, result):
177+
print(f"QR capture finished, result: {result}")
178+
if result.get("result_code"):
179+
data = result.get("data")
180+
print(f"Setting textarea data: {data}")
181+
self.textarea.set_text(data)
182+
183+
def cambutton_cb_unused(self, event):
184+
print("cambutton clicked!")
185+
self.startActivityForResult(Intent(activity_class=CameraApp).putExtra("scanqr_mode", True), self.gotqr_result_callback)
186+
187+
def save_setting(self, setting):
188+
ui = setting.get("ui")
189+
ui_options = setting.get("ui_options")
190+
if ui and ui == "radiobuttons" and ui_options:
191+
selected_idx = self.active_radio_index
192+
new_value = ""
193+
if selected_idx >= 0:
194+
new_value = ui_options[selected_idx][1]
195+
elif ui and ui == "dropdown" and ui_options:
196+
selected_index = self.dropdown.get_selected()
197+
print(f"selected item: {selected_index}")
198+
new_value = ui_options[selected_index][1]
199+
elif self.textarea:
200+
new_value = self.textarea.get_text()
201+
else:
202+
new_value = ""
203+
old_value = self.prefs.get_string(setting["key"])
204+
205+
# Save it
206+
if setting.get("dont_persist") is not True:
207+
editor = self.prefs.edit()
208+
editor.put_string(setting["key"], new_value)
209+
editor.commit()
210+
211+
# Update model for UI
212+
setting["value_label"].set_text(new_value if new_value else "(not set)")
213+
self.finish() # the self.finish (= back action) should happen before callback, in case it happens to start a new activity
214+
215+
# Call changed_callback if set
216+
changed_callback = setting.get("changed_callback")
217+
#print(f"changed_callback: {changed_callback}")
218+
if changed_callback and old_value != new_value:
219+
print(f"Setting {setting['key']} changed from {old_value} to {new_value}, calling changed_callback...")
220+
changed_callback(new_value)

0 commit comments

Comments
 (0)