diff --git a/python_payload/apps/gr33nhouse/applist.py b/python_payload/apps/gr33nhouse/applist.py index c89b3eb86b9897f251fcbf4d7ad7b00fabea45fe..40b2739b9e065c25ed8a1b8cbf4507db552b0595 100644 --- a/python_payload/apps/gr33nhouse/applist.py +++ b/python_payload/apps/gr33nhouse/applist.py @@ -18,18 +18,19 @@ class ViewState(Enum): LOADED = 4 -class AppList(BaseView): +class AppSubList(BaseView): _scroll_pos: float = 0.0 - _state: ViewState = ViewState.INITIAL apps: list[Any] = [] background: Flow3rView - def __init__(self) -> None: + def __init__(self, apps) -> None: super().__init__() self.background = Flow3rView() self._sc = ScrollController() + self.apps = apps + self._sc.set_item_count(len(self.apps)) def on_exit(self) -> bool: # request thinks after on_exit @@ -38,6 +39,98 @@ class AppList(BaseView): def draw(self, ctx: Context) -> None: ctx.move_to(0, 0) + self.background.draw(ctx) + + ctx.save() + ctx.gray(1.0) + ctx.rectangle( + -120.0, + -15.0, + 240.0, + 30.0, + ).fill() + + ctx.translate(0, -30 * self._sc.current_position()) + + offset = 0 + + ctx.font = "Camp Font 3" + ctx.font_size = 24 + ctx.text_align = ctx.CENTER + ctx.text_baseline = ctx.MIDDLE + + ctx.move_to(0, 0) + for idx, app in enumerate(self.apps): + target = idx == self._sc.target_position() + if target: + ctx.gray(0.0) + else: + ctx.gray(1.0) + + if abs(self._sc.current_position() - idx) <= 5: + xpos = 0.0 + if target and (width := ctx.text_width(app["name"])) > 220: + xpos = sin(self._scroll_pos) * (width - 220) / 2 + ctx.move_to(xpos, offset) + ctx.text(app["name"]) + offset += 30 + + ctx.restore() + + def think(self, ins: InputState, delta_ms: int) -> None: + super().think(ins, delta_ms) + self._sc.think(ins, delta_ms) + + self.background.think(ins, delta_ms) + self._scroll_pos += delta_ms / 1000 + + if not self.is_active(): + return + + if self.input.buttons.app.left.pressed or self.input.buttons.app.left.repeated: + self._sc.scroll_left() + self._scroll_pos = 0.0 + elif ( + self.input.buttons.app.right.pressed + or self.input.buttons.app.right.repeated + ): + self._sc.scroll_right() + self._scroll_pos = 0.0 + elif self.input.buttons.app.middle.pressed: + if self.vm is None: + raise RuntimeError("vm is None") + + app = self.apps[self._sc.target_position()] + url = app["tarDownloadUrl"] + name = app["name"] + author = app["author"] + self.vm.push( + ConfirmationView( + url=url, + name=name, + author=author, + ) + ) + + +class AppList(BaseView): + _scroll_pos: float = 0.0 + _state: ViewState = ViewState.INITIAL + + items: list[Any] = ["All"] + category_order: list[Any] = ["Badge", "Music", "Media", "Apps", "Games"] + + background: Flow3rView + + def __init__(self) -> None: + super().__init__() + self.background = Flow3rView() + self._sc = ScrollController() + self._sc.set_item_count(len(self.items)) + + def draw(self, ctx): + ctx.move_to(0, 0) + if self._state == ViewState.INITIAL or self._state == ViewState.LOADING: ctx.rgb(*colours.BLACK) ctx.rectangle( @@ -78,6 +171,8 @@ class AppList(BaseView): return elif self._state == ViewState.LOADED: + ctx.move_to(0, 0) + self.background.draw(ctx) ctx.save() @@ -90,7 +185,6 @@ class AppList(BaseView): ).fill() ctx.translate(0, -30 * self._sc.current_position()) - offset = 0 ctx.font = "Camp Font 3" @@ -99,7 +193,7 @@ class AppList(BaseView): ctx.text_baseline = ctx.MIDDLE ctx.move_to(0, 0) - for idx, app in enumerate(self.apps): + for idx, item in enumerate(self.items): target = idx == self._sc.target_position() if target: ctx.gray(0.0) @@ -108,10 +202,10 @@ class AppList(BaseView): if abs(self._sc.current_position() - idx) <= 5: xpos = 0.0 - if target and (width := ctx.text_width(app["name"])) > 220: + if target and (width := ctx.text_width(item)) > 220: xpos = sin(self._scroll_pos) * (width - 220) / 2 ctx.move_to(xpos, offset) - ctx.text(app["name"]) + ctx.text(item) offset += 30 ctx.restore() @@ -136,8 +230,21 @@ class AppList(BaseView): self._state = ViewState.ERROR return + categories = [app.get("menu") for app in self.apps] + categories = [c for c in categories if c and isinstance(c, str)] + categories = list(set(categories)) + + def sortkey(obj): + try: + return self.category_order.index(obj) + except ValueError: + return len(self.category_order) + + categories.sort(key=sortkey) + self.items = ["All"] + categories + self._sc.set_item_count(len(self.items)) + self._state = ViewState.LOADED - self._sc.set_item_count(len(self.apps)) print("App list loaded") except Exception as e: print(f"Load failed: {e}") @@ -166,15 +273,9 @@ class AppList(BaseView): elif self.input.buttons.app.middle.pressed: if self.vm is None: raise RuntimeError("vm is None") - - app = self.apps[self._sc.target_position()] - url = app["tarDownloadUrl"] - name = app["name"] - author = app["author"] - self.vm.push( - ConfirmationView( - url=url, - name=name, - author=author, - ) - ) + if self._sc.target_position(): + category = self.items[self._sc.target_position()] + apps = [app for app in self.apps if app.get("menu") == category] + else: + apps = list(self.apps) + self.vm.push(AppSubList(apps=apps)) diff --git a/python_payload/apps/gr33nhouse/confirmation.py b/python_payload/apps/gr33nhouse/confirmation.py index 68328576533c97f3418149d98b46d6833ba6eea9..574fe85eb55c2cd32751c77dea0514dc5d70e188 100644 --- a/python_payload/apps/gr33nhouse/confirmation.py +++ b/python_payload/apps/gr33nhouse/confirmation.py @@ -52,13 +52,14 @@ class ConfirmationView(BaseView): ctx.move_to(0, -30) ctx.text(self.name) - ctx.font_size = 16 - ctx.move_to(0, 0) - ctx.text("by") - - ctx.font_size = 24 - ctx.move_to(0, 30) - ctx.text(self.author) + if self.author: + ctx.font_size = 16 + ctx.move_to(0, 0) + ctx.text("by") + + ctx.font_size = 24 + ctx.move_to(0, 30) + ctx.text(self.author) ctx.font_size = 16 ctx.move_to(0, 60)