From 30fd567351a323f15b41e5d6864dd14eb3fd8b9f Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Mon, 28 Apr 2025 16:37:00 +0200 Subject: [PATCH] Add appstore --- .../com.example.appstore/META-INF/MANIFEST.MF | 3 + .../com.example.appstore/assets/appstore.py | 126 ++++++++++++++++++ .../res/mipmap-mdpi/icon_64x64.bin | Bin 0 -> 12300 bytes 3 files changed, 129 insertions(+) create mode 100644 internal_filesystem/apps/com.example.appstore/META-INF/MANIFEST.MF create mode 100644 internal_filesystem/apps/com.example.appstore/assets/appstore.py create mode 100644 internal_filesystem/apps/com.example.appstore/res/mipmap-mdpi/icon_64x64.bin diff --git a/internal_filesystem/apps/com.example.appstore/META-INF/MANIFEST.MF b/internal_filesystem/apps/com.example.appstore/META-INF/MANIFEST.MF new file mode 100644 index 00000000..2f0a306e --- /dev/null +++ b/internal_filesystem/apps/com.example.appstore/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Name: AppStore +Start-Script: assets/appstore.py diff --git a/internal_filesystem/apps/com.example.appstore/assets/appstore.py b/internal_filesystem/apps/com.example.appstore/assets/appstore.py new file mode 100644 index 00000000..dbe9790e --- /dev/null +++ b/internal_filesystem/apps/com.example.appstore/assets/appstore.py @@ -0,0 +1,126 @@ +import lvgl as lv +import json +import urequests +import gc + +class App: + def __init__(self, name, publisher, short_description, long_description, icon_url): + self.name = name + self.publisher = publisher + self.short_description = short_description + self.long_description = long_description + self.icon_url = icon_url + +class AppStore: + def __init__(self, subwindow, json_url): + print("__init__") + self.subwindow = subwindow + self.json_url = json_url + self.apps = [] + self.app_detail_screen = None + self.install_button = None + print("__init__") + self.main_screen_init() + def main_screen_init(self): + self.please_wait_label = lv.label(self.subwindow) + self.please_wait_label.set_text("Please wait...") + self.please_wait_label.center() + self.download_apps() + def download_apps(self): + try: + response = urequests.get(self.json_url) + print("download_apps") + if response.status_code == 200: + print(f"Got response text: {reponse.text}") + self.apps = [App(**app) for app in json.loads(response.text)] + response.close() + self.please_wait_label.add_flag(lv.obj.FLAG.HIDDEN) + self.create_apps_list() + except Exception as e: + print("Download failed:", e) + def create_apps_list(self): + print("create_apps_list") + self.apps_list = lv.list(self.subwindow) + self.apps_list.set_size(lv.pct(100), lv.pct(100)) + print("create_apps_list iterating") + for app in self.apps: + print("create_apps_list app found") + item = self.apps_list.add_button("", "") + print("create_apps_list app found 1") + item.add_flag(lv.obj.FLAG.CLICKABLE) + print("create_apps_list app found 2") + item.add_event_cb(lambda e, a=app: self.show_app_detail(a), lv.EVENT.CLICKED) + print("create_apps_list app found 3") + cont = lv.obj(item) + print("create_apps_list app found 4") + cont.set_flex_flow(lv.FLEX_FLOW.ROW) + print("create_apps_list app found 5") + cont.set_size(lv.pct(100), lv.SIZE_CONTENT) + print("create_apps_list app found 6") + icon_spacer = lv.obj(cont) + icon_spacer.set_size(40, 40) + label_cont = lv.obj(cont) + label_cont.set_flex_flow(lv.FLEX_FLOW.COLUMN) + label_cont.set_size(lv.pct(100), lv.SIZE_CONTENT) + name_label = lv.label(label_cont) + name_label.set_text(app.name) + name_label.set_style_text_font(lv.font_montserrat_16, 0) + desc_label = lv.label(label_cont) + desc_label.set_text(app.short_description) + desc_label.set_style_text_font(lv.font_montserrat_12, 0) + print("create_apps_list app one done") + print("create_apps_list app done") + def show_app_detail(self, app): + self.app_detail_screen = lv.obj(None) + self.app_detail_screen.set_size(lv.pct(100), lv.pct(100)) + back_button = lv.button(self.app_detail_screen) + back_button.set_size(30, 30) + back_button.add_flag(lv.obj.FLAG.CLICKABLE) + back_button.add_event_cb(self.back_to_main, lv.EVENT.CLICKED) + back_label = lv.label(back_button) + back_label.set_text(lv.SYMBOL.LEFT) + back_label.center() + cont = lv.obj(self.app_detail_screen) + cont.set_size(lv.pct(100), lv.pct(100)) + cont.set_pos(0, 40) + cont.set_flex_flow(lv.FLEX_FLOW.ROW) + icon_spacer = lv.obj(cont) + icon_spacer.set_size(60, 60) + detail_cont = lv.obj(cont) + detail_cont.set_flex_flow(lv.FLEX_FLOW.COLUMN) + detail_cont.set_size(lv.pct(100), lv.SIZE_CONTENT) + name_label = lv.label(detail_cont) + name_label.set_text(app.name) + name_label.set_style_text_font(lv.font_montserrat_24, 0) + publisher_label = lv.label(detail_cont) + publisher_label.set_text(app.publisher) + publisher_label.set_style_text_font(lv.font_montserrat_16, 0) + self.install_button = lv.button(detail_cont) + self.install_button.set_size(lv.pct(100), 40) + self.install_button.add_flag(lv.obj.FLAG.CLICKABLE) + self.install_button.add_event_cb(self.toggle_install, lv.EVENT.CLICKED) + install_label = lv.label(self.install_button) + install_label.set_text("Install") + install_label.center() + long_desc_label = lv.label(detail_cont) + long_desc_label.set_text(app.long_description) + long_desc_label.set_style_text_font(lv.font_montserrat_12, 0) + long_desc_label.set_width(lv.pct(100)) + lv.screen_load(self.app_detail_screen) + def toggle_install(self, event): + label = self.install_button.get_child(0) + if label.get_text() == "Install": + label.set_text("Cancel") + else: + label.set_text("Install") + def back_to_main(self, event): + if self.app_detail_screen: + self.app_detail_screen.delete() + self.app_detail_screen = None + lv.screen_load(self.subwindow) + gc.collect() + + +# Example usage: +#app_store = AppStore(lv.screen_active(), "http://demo.lnpiggy.com:2121/apps.json") +app_store = AppStore(subwindow, "http://demo.lnpiggy.com:2121/apps.json") diff --git a/internal_filesystem/apps/com.example.appstore/res/mipmap-mdpi/icon_64x64.bin b/internal_filesystem/apps/com.example.appstore/res/mipmap-mdpi/icon_64x64.bin new file mode 100644 index 0000000000000000000000000000000000000000..a307b259e3e73d4ccad691b64be8d17ad96a7ca3 GIT binary patch literal 12300 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 literal 0 HcmV?d00001