diff --git a/python_payload/apps/fil3s/browser.py b/python_payload/apps/fil3s/browser.py index 1d03defa42b5f9ac68af349c538e821aec37cc4c..04648d16fcb3a175a4a39d21b766b7d11692e0c6 100644 --- a/python_payload/apps/fil3s/browser.py +++ b/python_payload/apps/fil3s/browser.py @@ -20,6 +20,7 @@ class Browser(ActionView): up_enabled: bool = False prev_enabled: bool = False next_enabled: bool = False + delete_enabled: bool = True current_pos = 0 current_entry: tuple[str, str] @@ -31,6 +32,10 @@ class Browser(ActionView): ) -> None: super().__init__() + self._delete_held_for = 0.0 + self._delete_hold_time = 1.5 + self._delete_require_release = False + self.path = path self.navigate = navigate self.update_path = update_path @@ -51,6 +56,8 @@ class Browser(ActionView): if self.current_pos < len(self.dir_entries) - 1: self.current_pos += 1 self._update_position() + elif index == 0: + self._delete() def draw(self, ctx: Context) -> None: utils.fill_screen(ctx, theme.BACKGROUND) @@ -72,15 +79,24 @@ class Browser(ActionView): def think(self, ins: InputState, delta_ms: int) -> None: super().think(ins, delta_ms) - for i in range(0, 5): + # Handle delete petal being held down + if ins.captouch.petals[0].pressed: + if not self._delete_require_release: + self._delete_held_for += delta_ms / 1000 + if self._delete_held_for > self._delete_hold_time: + self._delete_held_for = self._delete_hold_time + self._delete_require_release = True + self._on_action(0) + else: + self._delete_held_for = 0.0 + self._delete_require_release = False + self.actions[0].progress = self._delete_held_for / self._delete_hold_time + + for i in range(1, 5): if self.input.captouch.petals[i * 2].whole.pressed: self._on_action(i) return - def _is_dir(self, path: str) -> bool: - st_mode = uos.stat(path)[0] # Can fail with OSError - return stat.S_ISDIR(st_mode) - def _get_dir_entry( self, names: list[str] ) -> Generator[tuple[str, str], None, None]: @@ -88,7 +104,7 @@ class Browser(ActionView): try: if self.path + name == "/flash/sys/st3m": yield (name, "\ue545") - elif self._is_dir(self.path + name): + elif utils.is_dir(self.path + name): yield (name, "\ue2c7") else: yield (name, "\ue873") @@ -121,7 +137,7 @@ class Browser(ActionView): old_path = self.path new_path = self.path + name try: - if self._is_dir(new_path): + if utils.is_dir(new_path): self._change_path(new_path + "/") else: self.update_path(self.path + name) @@ -131,6 +147,24 @@ class Browser(ActionView): print(f"Failed to open {new_path}: {e}") self._change_path(old_path) + def _delete(self) -> None: + name = self.dir_entries[self.current_pos][0] + path = self.path + name + + try: + if utils.is_dir(path): + utils.rmdirs(path) + else: + os.remove(path) + print(f"deleted file: {path}") + + # refresh dir listing + self.current_pos = max(self.current_pos - 1, 0) + self._scan_path() + except Exception as e: + # TODO: Create error view + print(f"Failed to delete {path}: {e}") + def _up(self) -> None: if not self.up_enabled or len(self.path) <= 1: return @@ -144,7 +178,8 @@ class Browser(ActionView): def _update_actions(self) -> None: self.actions = [ - Action(icon="\ue3e3", label="Menu", enabled=False), + # TODO: swap for a better icon + Action(icon="\ue3e3", label="Delete", enabled=self.delete_enabled), Action(icon="\ue409", label="Next", enabled=self.next_enabled), Action(icon="\ue876", label="Select"), Action(icon="\ue5c4", label="Back", enabled=self.up_enabled), @@ -154,9 +189,18 @@ class Browser(ActionView): def _update_position(self) -> None: try: self.current_entry = self.dir_entries[self.current_pos] - except: + except Exception: self.current_entry = ("\ue002", "No files") self.prev_enabled = self.current_pos > 0 self.next_enabled = self.current_pos < len(self.dir_entries) - 1 + # disallow deleting st3m folder + name = self.dir_entries[self.current_pos][0] + self.delete_enabled = self.path + name not in [ + "/flash", + "/flash/sys", + "/flash/sys/st3m", + "/sd", + ] + self._update_actions() diff --git a/python_payload/apps/fil3s/common/action_view.py b/python_payload/apps/fil3s/common/action_view.py index 63cb097afa82b357e990040109eed9a5a52d4ec0..ea29742bd2ea8a9f1e809f4de4be55d1be27be0f 100644 --- a/python_payload/apps/fil3s/common/action_view.py +++ b/python_payload/apps/fil3s/common/action_view.py @@ -13,11 +13,15 @@ class Action: icon: str label: str enabled: bool + progress: float - def __init__(self, icon: str, label: str, enabled: bool = True) -> None: + def __init__( + self, icon: str, label: str, enabled: bool = True, progress: float = 0.0 + ) -> None: self.icon = icon self.label = label self.enabled = enabled + self.progress = progress class ActionView(BaseView): @@ -66,7 +70,12 @@ class ActionView(BaseView): if action.enabled: utils.draw_circle( - ctx, theme.PRIMARY, self.action_x[i], self.action_y[i], 18 + ctx, + theme.PRIMARY, + self.action_x[i], + self.action_y[i], + 18, + action.progress, ) else: utils.draw_circle( diff --git a/python_payload/apps/fil3s/common/utils.py b/python_payload/apps/fil3s/common/utils.py index e77db4f2c01e575d42431b40ef59d3b3de301fa6..dd1e72b2f73500e2855b1f9b96cdbc145f3d56e1 100644 --- a/python_payload/apps/fil3s/common/utils.py +++ b/python_payload/apps/fil3s/common/utils.py @@ -1,5 +1,7 @@ -from math import pi +from math import tau from ctx import Context +import uos +import stat def fill_screen(ctx: Context, color: tuple[float, float, float]) -> None: @@ -13,9 +15,31 @@ def fill_screen(ctx: Context, color: tuple[float, float, float]) -> None: def draw_circle( - ctx: Context, color: tuple[float, float, float], x: int, y: int, radius: int + ctx: Context, + color: tuple[float, float, float], + x: int, + y: int, + radius: int, + progress: float = 0.0, ) -> None: ctx.move_to(x, y) ctx.rgb(*color) - ctx.arc(x, y, radius, -pi, pi, True) + ctx.arc(x, y, radius, tau * progress, tau, 0) ctx.fill() + + +def is_dir(path: str) -> bool: + st_mode = uos.stat(path)[0] # Can fail with OSError + return stat.S_ISDIR(st_mode) + + +def rmdirs(base_path): + for entry in uos.listdir(base_path): + path = f"{base_path}/{entry}" + if is_dir(path): + rmdirs(path) + else: + uos.remove(path) + print(f"deleted file: {path}") + uos.rmdir(base_path) + print(f"deleted folder: {base_path}")