From a8e7e5275d0b0f0ae6a9e7ceaae0f7f7f6bddedc Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Wed, 4 Jun 2025 09:39:37 +0200 Subject: [PATCH] Fix wificonf --- .../assets/launcher.py | 3 +- .../META-INF/MANIFEST.JSON | 29 +- .../assets/wificonf.py | 590 +++++++++--------- internal_filesystem/lib/mpos/apps.py | 37 +- scripts/bundleapps.sh | 2 +- 5 files changed, 358 insertions(+), 303 deletions(-) diff --git a/internal_filesystem/builtin/apps/com.micropythonos.launcher/assets/launcher.py b/internal_filesystem/builtin/apps/com.micropythonos.launcher/assets/launcher.py index d1eb5e6d..9eff329c 100644 --- a/internal_filesystem/builtin/apps/com.micropythonos.launcher/assets/launcher.py +++ b/internal_filesystem/builtin/apps/com.micropythonos.launcher/assets/launcher.py @@ -24,7 +24,8 @@ class MainActivity(mpos.apps.Activity): main_screen.set_style_radius(0, 0) main_screen.set_pos(0, mpos.ui.NOTIFICATION_BAR_HEIGHT) # leave some margin for the notification bar main_screen.set_size(lv.pct(100), lv.pct(100)) - main_screen.set_style_pad_all(10, 0) + main_screen.set_style_pad_hor(5, 0) + main_screen.set_style_pad_ver(mpos.ui.NOTIFICATION_BAR_HEIGHT, 0) main_screen.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP) self.setContentView(main_screen) diff --git a/internal_filesystem/builtin/apps/com.micropythonos.wificonf/META-INF/MANIFEST.JSON b/internal_filesystem/builtin/apps/com.micropythonos.wificonf/META-INF/MANIFEST.JSON index 0f939d0a..31576def 100644 --- a/internal_filesystem/builtin/apps/com.micropythonos.wificonf/META-INF/MANIFEST.JSON +++ b/internal_filesystem/builtin/apps/com.micropythonos.wificonf/META-INF/MANIFEST.JSON @@ -1,13 +1,24 @@ { "name": "WiFi", -"publisher": "ACME Inc", -"short_description": "Wireless Network Configuration", -"long_description": "", -"icon_url": "http://demo.lnpiggy.com:2121/apps/com.example.wificonf_0.0.2.mpk_icon_64x64.png", -"download_url": "http://demo.lnpiggy.com:2121/apps/com.example.wificonf_0.0.2.mpk", -"fullname": "com.example.wificonf", -"version": "0.0.2", -"entrypoint": "assets/wificonf.py", -"category": "wificonf" +"publisher": "MicroPythonOS", +"short_description": "WiFi Network Configuration", +"long_description": "Scans for wireless networks, shows a list of SSIDs, allows for password entry, and connecting.", +"icon_url": "https://apps.micropythonos.com/apps/com.micropythonos.wificonf/icons/com.micropythonos.wificonf_0.0.3_64x64.png", +"download_url": "https://apps.micropythonos.com/apps/com.micropythonos.wificonf/mpks/com.micropythonos.wificonf_0.0.3.mpk", +"fullname": "com.micropythonos.wificonf", +"version": "0.0.3", +"category": "wificonf", +"activities": [ + { + "entrypoint": "assets/wificonf.py", + "classname": "WiFiConfig", + "intent_filters": [ + { + "action": "main", + "category": "launcher" + } + ] + } + ] } diff --git a/internal_filesystem/builtin/apps/com.micropythonos.wificonf/assets/wificonf.py b/internal_filesystem/builtin/apps/com.micropythonos.wificonf/assets/wificonf.py index 75cb0d41..a435823e 100644 --- a/internal_filesystem/builtin/apps/com.micropythonos.wificonf/assets/wificonf.py +++ b/internal_filesystem/builtin/apps/com.micropythonos.wificonf/assets/wificonf.py @@ -4,34 +4,317 @@ import time import lvgl as lv import _thread -import mpos.apps +from mpos.apps import Activity, Intent import mpos.ui -# Screens: -main_screen=None -password_page=None - -ssids=[] -busy_scanning=False -busy_connecting=False access_points={} -selected_ssid=None -aplist=None -password_ta=None -keyboard=None -error_label=None -connect_button=None -cancel_button=None last_tried_ssid = "" last_tried_result = "" -scan_button=None -scan_button_label=None scan_button_scan_text = "Rescan" scan_button_scanning_text = "Scanning..." -def load_config(): +RESULT_CODE_CONNECT = 1 +RESULT_CODE_CANCEL = 0 + + +class WiFiConfig(Activity): + + havenetwork = True + ssids=[] + busy_scanning=False + busy_connecting=False + #selected_ssid=None + + # Widgets: + aplist = None + error_label=None + scan_button=None + scan_button_label=None + + def onCreate(self): + main_screen = lv.obj() + main_screen.set_style_pad_all(15, 0) + print("create_ui: Creating list widget") + self.aplist=lv.list(main_screen) + self.aplist.set_size(lv.pct(100),lv.pct(80)) + self.aplist.align(lv.ALIGN.TOP_MID,0,0) + print("create_ui: Creating error label") + self.error_label=lv.label(main_screen) + self.error_label.set_text("") + self.error_label.align(lv.ALIGN.BOTTOM_MID,0,-40) + self.error_label.add_flag(lv.obj.FLAG.HIDDEN) + print("create_ui: Creating Scan button") + self.scan_button=lv.button(main_screen) + self.scan_button.set_size(lv.SIZE_CONTENT,lv.pct(15)) + self.scan_button.align(lv.ALIGN.BOTTOM_MID,0,0) + self.scan_button_label=lv.label(self.scan_button) + self.scan_button_label.set_text(scan_button_scan_text) + self.scan_button_label.center() + self.scan_button.add_event_cb(self.scan_cb,lv.EVENT.CLICKED,None) + self.setContentView(main_screen) + + def onStart(self, screen): + self.havenetwork = True + try: + import network + wlan=network.WLAN(network.STA_IF) + wlan.active(True) + except Exception as e: + self.havenetwork = False + self.start_scan_networks() + + def onResume(self, screen): + load_config() + + def show_error(self, message): + print(f"show_error: Displaying error: {message}") + lv.async_call(lambda l: self.error_label.set_text(message), None) + lv.async_call(lambda l: self.error_label.remove_flag(lv.obj.FLAG.HIDDEN), None) + timer=lv.timer_create(lambda t: self.error_label.add_flag(lv.obj.FLAG.HIDDEN),3000,None) + timer.set_repeat_count(1) + + def scan_networks_thread(self): + print("scan_networks: Scanning for Wi-Fi networks") + global ssids, busy_scanning, scan_button_label, scan_button + if self.havenetwork and not wlan.isconnected(): # restart WiFi hardware in case it's in a bad state + wlan.active(False) + wlan.active(True) + try: + if self.havenetwork: + networks = wlan.scan() + self.ssids = list(set(n[0].decode() for n in networks)) + else: + time.sleep(2) + self.ssids = ["Home WiFi", "I believe Wi can Fi", "Winternet is coming", "The Promised LAN"] + print(f"scan_networks: Found networks: {self.ssids}") + except Exception as e: + print(f"scan_networks: Scan failed: {e}") + self.show_error("Wi-Fi scan failed") + # scan done: + self.busy_scanning = False + lv.async_call(lambda l: self.scan_button_label.set_text(scan_button_scan_text), None) + lv.async_call(lambda l: self.scan_button.add_flag(lv.obj.FLAG.CLICKABLE), None) + lv.async_call(lambda l: self.refresh_list(), None) + + def start_scan_networks(self): + print("scan_networks: Showing scanning label") + if self.busy_scanning: + print("Not scanning for networks because already busy_scanning.") + else: + self.busy_scanning = True + self.scan_button.remove_flag(lv.obj.FLAG.CLICKABLE) + self.scan_button_label.set_text(scan_button_scanning_text) + _thread.stack_size(mpos.apps.good_stack_size()) + _thread.start_new_thread(self.scan_networks_thread, ()) + + def refresh_list(self): + print("refresh_list: Clearing current list") + self.aplist.clean() # this causes an issue with lost taps if an ssid is clicked that has been removed + print("refresh_list: Populating list with scanned networks") + for ssid in self.ssids: + if len(ssid) < 1 or len(ssid) > 32: + print(f"Skipping too short or long SSID: {ssid}") + continue + print(f"refresh_list: Adding SSID: {ssid}") + button=self.aplist.add_button(None,ssid) + button.add_event_cb(lambda e, s=ssid: self.select_ssid_cb(s),lv.EVENT.CLICKED,None) + if self.havenetwork and wlan.isconnected() and wlan.config('essid')==ssid: + status="connected" + elif last_tried_ssid==ssid: # implies not connected because not wlan.isconnected() + status=last_tried_result + elif ssid in access_points: + status="saved" + else: + status="" + if status: + print(f"refresh_list: Setting status '{status}' for SSID: {ssid}") + label=lv.label(button) + label.set_text(status) + label.align(lv.ALIGN.RIGHT_MID,-10,0) + + def scan_cb(self, event): + print("scan_cb: Scan button clicked, refreshing list") + self.start_scan_networks() + + def select_ssid_cb(self,ssid): + print(f"select_ssid_cb: SSID selected: {ssid}") + intent = Intent(activity_class=PasswordPage) + intent.putExtra("selected_ssid", ssid) + self.startActivityForResult(intent, self.password_page_result_cb) + + def password_page_result_cb(self, result): + print(f"PasswordPage finished, result: {result}") + if result.get("result_code") == RESULT_CODE_CONNECT: + data = result.get("data") + if data: + self.start_attempt_connecting(data.get("ssid"), data.get("password")) + + def start_attempt_connecting(self, ssid, password): + print(f"start_attempt_connecting: Attempting to connect to SSID: {ssid}") + self.scan_button.remove_flag(lv.obj.FLAG.CLICKABLE) + self.scan_button_label.set_text(f"Connecting to {ssid}...") + if self.busy_connecting: + print("Not attempting connect because busy_connecting.") + else: + self.busy_connecting = True + _thread.stack_size(mpos.apps.good_stack_size()) + _thread.start_new_thread(self.attempt_connecting_thread, (ssid,password)) + + def attempt_connecting_thread(self, ssid, password): + global last_tried_ssid, last_tried_result + print(f"attempt_connecting: Attempting to connect to SSID: {ssid}") + result="connected" + try: + if self.havenetwork: + wlan.disconnect() + wlan.connect(ssid,password) + for i in range(10): + if wlan.isconnected(): + print(f"attempt_connecting: Connected to {ssid} after {i+1} seconds") + break + print(f"attempt_connecting: Waiting for connection, attempt {i+1}/10") + time.sleep(1) + if not wlan.isconnected(): + result="timeout" + else: + print("Warning: not trying to connect because not havenetwork") + except Exception as e: + print(f"attempt_connecting: Connection error: {e}") + result=f"{e}" + self.show_error("Connecting to {ssid} failed!") + print(f"Connecting to {ssid} got result: {result}") + last_tried_ssid = ssid + last_tried_result = result + self.busy_connecting=False + # Schedule UI updates because different thread + lv.async_call(lambda l: self.scan_button_label.set_text(scan_button_scan_text), None) + lv.async_call(lambda l: self.scan_button.add_flag(lv.obj.FLAG.CLICKABLE), None) + lv.async_call(lambda l: self.refresh_list(), None) + + + + +class PasswordPage(Activity): + + # Would be good to add some validation here so the password is not too short etc... + + selected_ssid = None + + # Widgets: + password_ta=None + keyboard=None + connect_button=None + cancel_button=None + + def onCreate(self): + self.selected_ssid = self.getIntent().extras.get("selected_ssid") + print("PasswordPage: Creating new password page") + password_page=lv.obj() + password_page.set_size(lv.pct(100),lv.pct(100)) + print(f"show_password_page: Creating label for SSID: {self.selected_ssid}") + label=lv.label(password_page) + label.set_text(f"Password for {self.selected_ssid}") + label.align(lv.ALIGN.TOP_MID,0,5) + print("PasswordPage: Creating password textarea") + self.password_ta=lv.textarea(password_page) + self.password_ta.set_size(200,30) + self.password_ta.set_one_line(True) + self.password_ta.align_to(label, lv.ALIGN.OUT_BOTTOM_MID, 5, 0) + self.password_ta.add_event_cb(self.password_ta_cb,lv.EVENT.CLICKED,None) + # try to find saved password: + for apssid,password in access_points.items(): + if self.selected_ssid == apssid: + self.password_ta.set_text(password) + break + self.password_ta.set_placeholder_text("Password") + print("PasswordPage: Creating keyboard (hidden by default)") + self.keyboard=lv.keyboard(password_page) + self.keyboard.set_size(lv.pct(100),0) + self.keyboard.align(lv.ALIGN.BOTTOM_LEFT,0,0) + self.keyboard.set_textarea(self.password_ta) + self.keyboard.add_event_cb(self.keyboard_cb,lv.EVENT.READY,None) + self.keyboard.add_event_cb(self.keyboard_cb,lv.EVENT.CANCEL,None) + self.keyboard.add_event_cb(self.keyboard_value_changed_cb,lv.EVENT.VALUE_CHANGED,None) + print("PasswordPage: Creating Connect button") + self.connect_button=lv.button(password_page) + self.connect_button.set_size(100,40) + self.connect_button.align(lv.ALIGN.BOTTOM_LEFT,10,-40) + self.connect_button.add_event_cb(self.connect_cb,lv.EVENT.CLICKED,None) + label=lv.label(self.connect_button) + label.set_text("Connect") + label.center() + print("PasswordPage: Creating Cancel button") + self.cancel_button=lv.button(password_page) + self.cancel_button.set_size(100,40) + self.cancel_button.align(lv.ALIGN.BOTTOM_RIGHT,-10,-40) + self.cancel_button.add_event_cb(self.cancel_cb,lv.EVENT.CLICKED,None) + label=lv.label(self.cancel_button) + label.set_text("Close") + label.center() + print("PasswordPage: Loading password page") + self.setContentView(password_page) + + def hide_keyboard(self): + #global keyboard,connect_button,cancel_button + print("keyboard_cb: READY or CANCEL or RETURN clicked, hiding keyboard") + self.keyboard.set_height(0) + self.keyboard.remove_flag(lv.obj.FLAG.CLICKABLE) + print("keyboard_cb: Showing Connect and Cancel buttons") + self.connect_button.remove_flag(lv.obj.FLAG.HIDDEN) + self.cancel_button.remove_flag(lv.obj.FLAG.HIDDEN) + + def keyboard_cb(self, event): + #print("keyboard_cb: Keyboard event triggered") + code=event.get_code() + if code==lv.EVENT.READY or code==lv.EVENT.CANCEL: + self.hide_keyboard() + + def keyboard_value_changed_cb(self, event): + #print("keyboard value changed!") + #print(f"event: code={event.get_code()}, target={event.get_target()}, user_data={event.get_user_data()}, param={event.get_param()}") # event: code=32, target=, user_data=, param= + button = self.keyboard.get_selected_button() + text = self.keyboard.get_button_text(button) + #print(f"button {button} and text {text}") + if text == lv.SYMBOL.NEW_LINE: + print("Newline key pressed, hiding keyboard...") + hide_keyboard() + + def password_ta_cb(self, event): + print("password_ta_cb: Password textarea clicked") + print("password_ta_cb: Hiding Connect and Cancel buttons") + self.connect_button.add_flag(lv.obj.FLAG.HIDDEN) + self.cancel_button.add_flag(lv.obj.FLAG.HIDDEN) + print("password_ta_cb: Showing keyboard") + self.keyboard.set_height(160) + self.keyboard.add_flag(lv.obj.FLAG.CLICKABLE) # seems needed after showing/hiding the keyboard a few times + + + def connect_cb(self, event): + global access_points + print("connect_cb: Connect button clicked") + password=self.password_ta.get_text() + print(f"connect_cb: Got password: {password}") + access_points[self.selected_ssid]=password + print(f"connect_cb: Updated access_points: {access_points}") + save_config() + self.setResult(RESULT_CODE_CONNECT, {"ssid": self.selected_ssid, "password": password}) + print("connect_cb: Restoring main_screen") + self.finish() + + def cancel_cb(self, event): + print("cancel_cb: Cancel button clicked") + self.setResult(RESULT_CODE_CANCEL, None) + self.finish() + + + + +# Non-class functions: + + +def load_config(): # Maybe this should call a framework function print("load_config: Checking for /data directory") try: os.stat('data') @@ -56,281 +339,16 @@ def load_config(): access_points={} print("load_config: No config file found, using empty access_points") -def save_config(): + +def save_config(): # Maybe this should call a framework function print("save_config: Saving access_points to conf.json") try: with open('data/com.example.wificonf/conf.json','w') as f: ujson.dump(access_points,f) print(f"save_config: Saved access_points: {access_points}") except OSError: - show_error("Failed to save config") + self.show_error("Failed to save config") print("save_config: Failed to save config") -def scan_networks_thread(): - print("scan_networks: Scanning for Wi-Fi networks") - global ssids, busy_scanning, scan_button_label, scan_button - if havenetwork and not wlan.isconnected(): # restart WiFi hardware in case it's in a bad state - wlan.active(False) - wlan.active(True) - try: - if havenetwork: - networks = wlan.scan() - ssids = list(set(n[0].decode() for n in networks)) - else: - time.sleep(2) - ssids = ["Dummy", "Test", "SSIDs"] - print(f"scan_networks: Found networks: {ssids}") - except Exception as e: - print(f"scan_networks: Scan failed: {e}") - show_error("Wi-Fi scan failed") - # scan done: - busy_scanning = False - lv.async_call(lambda l: scan_button_label.set_text(scan_button_scan_text), None) - lv.async_call(lambda l: scan_button.add_flag(lv.obj.FLAG.CLICKABLE), None) - lv.async_call(lambda l: refresh_list(), None) - - -def start_scan_networks(): - print("scan_networks: Showing scanning label") - global scan_button_label, busy_scanning, scan_button - if busy_scanning: - print("Not scanning for networks because already busy_scanning.") - else: - busy_scanning = True - scan_button.remove_flag(lv.obj.FLAG.CLICKABLE) - scan_button_label.set_text(scan_button_scanning_text) - _thread.stack_size(mpos.apps.good_stack_size()) - _thread.start_new_thread(scan_networks_thread, ()) - - -def attempt_connecting_thread(ssid,password): - global busy_connecting, scan_button_label, scan_button, last_tried_ssid, last_tried_result - print(f"attempt_connecting: Attempting to connect to SSID: {ssid}") - result="connected" - try: - if havenetwork: - wlan.disconnect() - wlan.connect(ssid,password) - for i in range(10): - if wlan.isconnected(): - print(f"attempt_connecting: Connected to {ssid} after {i+1} seconds") - break - print(f"attempt_connecting: Waiting for connection, attempt {i+1}/10") - time.sleep(1) - if not wlan.isconnected(): - result="timeout" - else: - print("Warning: not trying to connect because not havenetwork") - except Exception as e: - print(f"attempt_connecting: Connection error: {e}") - result=f"{e}" - show_error("Connecting to {ssid} failed!") - print(f"Connecting to {ssid} got result: {result}") - last_tried_ssid = ssid - last_tried_result = result - busy_connecting=False - # Schedule UI updates because different thread - lv.async_call(lambda l: scan_button_label.set_text(scan_button_scan_text), None) - lv.async_call(lambda l: scan_button.add_flag(lv.obj.FLAG.CLICKABLE), None) - lv.async_call(lambda l: refresh_list(), None) - - -def start_attempt_connecting(ssid,password): - print(f"start_attempt_connecting: Attempting to connect to SSID: {ssid}") - global busy_connecting, scan_button_label, scan_button - scan_button.remove_flag(lv.obj.FLAG.CLICKABLE) - scan_button_label.set_text(f"Connecting to {ssid}...") - if busy_connecting: - print("Not attempting connect because busy_connecting.") - else: - busy_connecting = True - _thread.stack_size(get_good_stacksize()) - _thread.start_new_thread(attempt_connecting_thread, (ssid,password)) - -def show_error(message): - print(f"show_error: Displaying error: {message}") - global error_label - lv.async_call(lambda l: error_label.set_text(message), None) - lv.async_call(lambda l: error_label.remove_flag(lv.obj.FLAG.HIDDEN), None) - timer=lv.timer_create(lambda t: error_label.add_flag(lv.obj.FLAG.HIDDEN),3000,None) - timer.set_repeat_count(1) - -def refresh_list(): - global ssids - print("refresh_list: Clearing current list") - aplist.clean() # this causes an issue with lost taps if an ssid is clicked that has been removed - print("refresh_list: Populating list with scanned networks") - for ssid in ssids: - if len(ssid) < 1 or len(ssid) > 32: - print(f"Skipping too short or long SSID: {ssid}") - continue - print(f"refresh_list: Adding SSID: {ssid}") - button=aplist.add_button(None,ssid) - button.add_event_cb(lambda e, s=ssid: select_ssid_cb(e,s),lv.EVENT.CLICKED,None) - if havenetwork and wlan.isconnected() and wlan.config('essid')==ssid: - status="connected" - elif last_tried_ssid==ssid: # implies not connected because not wlan.isconnected() - status=last_tried_result - elif ssid in access_points: - status="saved" - else: - status="" - if status: - print(f"refresh_list: Setting status '{status}' for SSID: {ssid}") - label=lv.label(button) - label.set_text(status) - label.align(lv.ALIGN.RIGHT_MID,-10,0) - -def scan_cb(event): - print("scan_cb: Scan button clicked, refreshing list") - start_scan_networks() - -def select_ssid_cb(event,ssid): - global selected_ssid - print(f"select_ssid_cb: SSID selected: {ssid}") - selected_ssid=ssid - show_password_page(ssid) - -def hide_keyboard(): - global keyboard,connect_button,cancel_button - print("keyboard_cb: READY or CANCEL or RETURN clicked, hiding keyboard") - keyboard.set_height(0) - #keyboard.remove_flag(lv.obj.FLAG.CLICKABLE) - print("keyboard_cb: Showing Connect and Cancel buttons") - connect_button.remove_flag(lv.obj.FLAG.HIDDEN) - cancel_button.remove_flag(lv.obj.FLAG.HIDDEN) - -def keyboard_cb(event): - #print("keyboard_cb: Keyboard event triggered") - code=event.get_code() - if code==lv.EVENT.READY or code==lv.EVENT.CANCEL: - hide_keyboard() - -def keyboard_value_changed_cb(event): - global keyboard - #print("keyboard value changed!") - #print(f"event: code={event.get_code()}, target={event.get_target()}, user_data={event.get_user_data()}, param={event.get_param()}") # event: code=32, target=, user_data=, param= - button = keyboard.get_selected_button() - text = keyboard.get_button_text(button) - #print(f"button {button} and text {text}") - if text == lv.SYMBOL.NEW_LINE: - print("Newline key pressed, hiding keyboard...") - hide_keyboard() - -def password_ta_cb(event): - print("password_ta_cb: Password textarea clicked") - global keyboard,connect_button,cancel_button - print("password_ta_cb: Hiding Connect and Cancel buttons") - connect_button.add_flag(lv.obj.FLAG.HIDDEN) - cancel_button.add_flag(lv.obj.FLAG.HIDDEN) - print("password_ta_cb: Showing keyboard") - keyboard.set_height(160) - #keyboard.add_flag(lv.obj.FLAG.CLICKABLE) - -def show_password_page(ssid): - global password_page,password_ta,keyboard,connect_button,cancel_button - print("show_password_page: Creating new password page") - password_page=lv.obj() - password_page.set_size(lv.pct(100),lv.pct(100)) - print(f"show_password_page: Creating label for SSID: {selected_ssid}") - label=lv.label(password_page) - label.set_text(f"Enter password for {selected_ssid}") - label.align(lv.ALIGN.TOP_MID,0,5) - print("show_password_page: Creating password textarea") - password_ta=lv.textarea(password_page) - password_ta.set_size(200,30) - password_ta.set_one_line(True) - password_ta.align_to(label, lv.ALIGN.OUT_BOTTOM_MID, 5, 0) - # try to find saved password: - for apssid,password in access_points.items(): - if ssid == apssid: - password_ta.set_text(password) - break - password_ta.set_placeholder_text("Password") - password_ta.add_event_cb(password_ta_cb,lv.EVENT.CLICKED,None) - print("show_password_page: Creating keyboard (hidden by default)") - keyboard=lv.keyboard(password_page) - keyboard.set_size(lv.pct(100),0) - keyboard.align(lv.ALIGN.BOTTOM_LEFT,0,0) - keyboard.set_textarea(password_ta) - keyboard.add_event_cb(keyboard_cb,lv.EVENT.READY,None) - keyboard.add_event_cb(keyboard_cb,lv.EVENT.CANCEL,None) - keyboard.add_event_cb(keyboard_value_changed_cb,lv.EVENT.VALUE_CHANGED,None) - print("show_password_page: Creating Connect button") - connect_button=lv.button(password_page) - connect_button.set_size(100,40) - connect_button.align(lv.ALIGN.BOTTOM_LEFT,10,-40) - label=lv.label(connect_button) - label.set_text("Connect") - label.center() - connect_button.add_event_cb(connect_cb,lv.EVENT.CLICKED,None) - print("show_password_page: Creating Cancel button") - cancel_button=lv.button(password_page) - cancel_button.set_size(100,40) - cancel_button.align(lv.ALIGN.BOTTOM_RIGHT,-10,-40) - label=lv.label(cancel_button) - label.set_text("Close") - label.center() - cancel_button.add_event_cb(cancel_cb,lv.EVENT.CLICKED,None) - print("show_password_page: Loading password page") - mpos.ui.load_screen(password_page) - -def connect_cb(event): - global access_points - print("connect_cb: Connect button clicked") - password=password_ta.get_text() - print(f"connect_cb: Got password: {password}") - access_points[selected_ssid]=password - print(f"connect_cb: Updated access_points: {access_points}") - save_config() - print("connect_cb: Deleting password page") - password_page.delete() - print("connect_cb: Restoring main_screen") - mpos.ui.load_screen(main_screen) - print(f"connect_cb: Attempting connection to {selected_ssid}") - start_attempt_connecting(selected_ssid,password) - -def cancel_cb(event): - print("cancel_cb: Cancel button clicked") - print("Deleting password screen...") - password_page.delete() - print("cancel_cb: Restoring main_screen") - mpos.ui.back_screen() - -def create_ui(): - global aplist,main_screen,error_label,scan_button_label,scan_button - main_screen = lv.obj() - main_screen.set_style_pad_all(15, 0) - print("create_ui: Creating list widget") - aplist=lv.list(main_screen) - aplist.set_size(lv.pct(100),lv.pct(80)) - aplist.align(lv.ALIGN.TOP_MID,0,0) - print("create_ui: Creating error label") - error_label=lv.label(main_screen) - error_label.set_text("") - error_label.align(lv.ALIGN.BOTTOM_MID,0,-40) - error_label.add_flag(lv.obj.FLAG.HIDDEN) - print("create_ui: Creating Scan button") - scan_button=lv.button(main_screen) - scan_button.set_size(lv.SIZE_CONTENT,lv.pct(15)) - scan_button.align(lv.ALIGN.BOTTOM_MID,0,0) - scan_button_label=lv.label(scan_button) - scan_button_label.set_text(scan_button_scan_text) - scan_button_label.center() - scan_button.add_event_cb(scan_cb,lv.EVENT.CLICKED,None) - mpos.ui.load_screen(main_screen) - - -havenetwork = True -try: - import network - wlan=network.WLAN(network.STA_IF) - wlan.active(True) -except Exception as e: - havenetwork = False - -load_config() -create_ui() -start_scan_networks() diff --git a/internal_filesystem/lib/mpos/apps.py b/internal_filesystem/lib/mpos/apps.py index d2d1ee4b..500d4b76 100644 --- a/internal_filesystem/lib/mpos/apps.py +++ b/internal_filesystem/lib/mpos/apps.py @@ -247,6 +247,9 @@ class Activity: def startActivity(self, intent): ActivityNavigator.startActivity(intent) + def startActivityForResult(self, intent, result_callback): + ActivityNavigator.startActivityForResult(intent, result_callback) + def initError(self, e): print(f"WARNING: You might have inherited from Activity with a custom __init__() without calling super().__init__(). Got AttributeError: {e}") @@ -290,31 +293,53 @@ class Intent: class ActivityNavigator: - + @staticmethod def startActivity(intent): if not isinstance(intent, Intent): raise ValueError("Must provide an Intent") - if intent.action: # Implicit intent: resolve handlers + if intent.action: # Implicit intent: resolve handlers handlers = APP_REGISTRY.get(intent.action, []) if len(handlers) == 1: intent.activity_class = handlers[0] ActivityNavigator._launch_activity(intent) elif handlers: - _show_chooser(intent, handlers) + ActivityNavigator._show_chooser(intent, handlers) else: raise ValueError(f"No handlers for action: {intent.action}") else: - # Explicit intent ActivityNavigator._launch_activity(intent) - def _launch_activity(intent): + @staticmethod + def startActivityForResult(intent, result_callback): + """Launch an activity and pass a callback for the result.""" + if not isinstance(intent, Intent): + raise ValueError("Must provide an Intent") + if intent.action: # Implicit intent: resolve handlers + handlers = APP_REGISTRY.get(intent.action, []) + if len(handlers) == 1: + intent.activity_class = handlers[0] + return ActivityNavigator._launch_activity(intent, result_callback) + elif handlers: + ActivityNavigator._show_chooser(intent, handlers) + return None # Chooser handles result forwarding + else: + raise ValueError(f"No handlers for action: {intent.action}") + else: + return ActivityNavigator._launch_activity(intent, result_callback) + + @staticmethod + def _launch_activity(intent, result_callback=None): + """Launch an activity and set up result callback.""" activity = intent.activity_class() activity.intent = intent + activity._result_callback = result_callback # Pass callback to activity activity.onCreate() + return activity + @staticmethod def _show_chooser(intent, handlers): chooser_intent = Intent(ChooserActivity, extras={"original_intent": intent, "handlers": [h.__name__ for h in handlers]}) - _launch_activity(chooser_intent) + ActivityNavigator._launch_activity(chooser_intent) class ChooserActivity(Activity): diff --git a/scripts/bundleapps.sh b/scripts/bundleapps.sh index 22b56282..a18aceb1 100755 --- a/scripts/bundleapps.sh +++ b/scripts/bundleapps.sh @@ -25,7 +25,7 @@ for apprepo in internal_filesystem/apps internal_filesystem/builtin/apps; do version=$( jq -r '.version' "$manifest" ) cat "$manifest" | tee -a "$outputjson" echo -n "," | tee -a "$outputjson" - thisappdir="$output"/"$appdir" + thisappdir="$output"/apps/"$appdir" mkdir -p "$thisappdir" mkdir -p "$thisappdir"/mpks mkdir -p "$thisappdir"/icons