From d0444f10cbd8dff77ef973f4d999de3c39f034dd Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Sat, 5 Jul 2025 02:26:59 +0200 Subject: [PATCH] Add file manager app --- .../META-INF/MANIFEST.JSON | 24 ++++ .../assets/file_manager.py | 58 ++++++++ internal_filesystem/lib/mpos/fs_driver.py | 132 ++++++++++++++++++ internal_filesystem/lib/mpos/ui/__init__.py | 2 - internal_filesystem/main.py | 4 +- 5 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 internal_filesystem/apps/com.micropythonos.filemanager/META-INF/MANIFEST.JSON create mode 100644 internal_filesystem/apps/com.micropythonos.filemanager/assets/file_manager.py create mode 100644 internal_filesystem/lib/mpos/fs_driver.py diff --git a/internal_filesystem/apps/com.micropythonos.filemanager/META-INF/MANIFEST.JSON b/internal_filesystem/apps/com.micropythonos.filemanager/META-INF/MANIFEST.JSON new file mode 100644 index 00000000..69292d15 --- /dev/null +++ b/internal_filesystem/apps/com.micropythonos.filemanager/META-INF/MANIFEST.JSON @@ -0,0 +1,24 @@ +{ +"name": "File Manager", +"publisher": "MicroPythonOS", +"short_description": "Manage files", +"long_description": "Traverse around the filesystem and manage files and folders you find..", +"icon_url": "https://apps.micropythonos.com/apps/com.micropythonos.explorer/icons/com.micropythonos.filemanager.0.1_64x64.png", +"download_url": "https://apps.micropythonos.com/apps/com.micropythonos.fileexplorer/mpks/com.micropythonos.filemanager.0.1.mpk", +"fullname": "com.micropythonos.filemanager", +"version": "0.0.1", +"category": "development", +"activities": [ + { + "entrypoint": "assets/file_manager.py", + "classname": "FileManager", + "intent_filters": [ + { + "action": "main", + "category": "launcher" + } + ] + } + ] +} + diff --git a/internal_filesystem/apps/com.micropythonos.filemanager/assets/file_manager.py b/internal_filesystem/apps/com.micropythonos.filemanager/assets/file_manager.py new file mode 100644 index 00000000..5a25ac96 --- /dev/null +++ b/internal_filesystem/apps/com.micropythonos.filemanager/assets/file_manager.py @@ -0,0 +1,58 @@ +from mpos.apps import Activity +import mpos.ui + +class FileManager(Activity): + + # Widgets: + file_explorer = None + + def onCreate(self): + #lv.log_register_print_cb(self.log_callback) + screen = lv.obj() + self.file_explorer = lv.file_explorer(screen) + #self.file_explorer.set_root_path("M:data/images/") + #self.file_explorer.explorer_open_dir('/') + #self.file_explorer.explorer_open_dir('M:data/images/') + #self.file_explorer.explorer_open_dir('M:/') + self.file_explorer.explorer_open_dir('M:/') + #self.file_explorer.explorer_open_dir('M:data/images/') + #self.file_explorer.explorer_open_dir('P:.') # POSIX works, fs_driver doesn't because it doesn't have dir_open, dir_read, dir_close + #self.file_explorer.explorer_open_dir('P:/tmp') # POSIX works, fs_driver doesn't because it doesn't have dir_open, dir_read, dir_close + #file_explorer.explorer_open_dir('S:/') + #self.file_explorer.set_size(lv.pct(100), lv.pct(100)) + #file_explorer.set_mode(lv.FILE_EXPLORER.MODE.DEFAULT) # Default browsing mode + #file_explorer.set_sort(lv.FILE_EXPLORER.SORT.NAME_ASC) # Sort by name, ascending + self.file_explorer.align(lv.ALIGN.CENTER, 0, 0) + # Attach event callback + self.file_explorer.add_event_cb(self.file_explorer_event_cb, lv.EVENT.ALL, None) + self.setContentView(screen) + + def file_explorer_event_cb(self, event): + event_code = event.get_code() + # Ignore: + # ======= + # 2: PRESSING + # 19: HIT_TEST + # COVER_CHECK + # 24: REFR_EXT_DRAW_SIZE + # DRAW_MAIN + # DRAW_MAIN_BEGIN + # DRAW_MAIN_END + # DRAW_POST + # DRAW_POST_BEGIN + # DRAW_POST_END + # GET_SELF_SIZE + # 47 STYLE CHANGED + if event_code not in [2,19,23,24,25,26,27,28,29,30,47,49]: + name = mpos.ui.get_event_name(event_code) + print(f"file_explorer_event_cb {event_code} with name {name}") + if event_code == lv.EVENT.VALUE_CHANGED: + path = self.file_explorer.explorer_get_current_path() + file = self.file_explorer.explorer_get_selected_file_name() + print(f"Selected: {path}{file}") + + # Custom log callback to capture FPS + def log_callback(self, level, log_str): + # Convert log_str to string if it's a bytes object + log_str = log_str.decode() if isinstance(log_str, bytes) else log_str + print(f"Level: {level}, Log: {log_str}") diff --git a/internal_filesystem/lib/mpos/fs_driver.py b/internal_filesystem/lib/mpos/fs_driver.py new file mode 100644 index 00000000..0d31cdf0 --- /dev/null +++ b/internal_filesystem/lib/mpos/fs_driver.py @@ -0,0 +1,132 @@ +# Original author: mhepp(https://forum.lvgl.io/u/mhepp/summary) +# Copyright (c) 2024 - 2025 Kevin G. Schlosser +# Added directory support, upstreamed at https://github.com/lvgl-micropython/lvgl_micropython/issues/398 + + +import lvgl as lv +import struct + + +def _fs_open_cb(drv, path, mode): + + if mode == lv.FS_MODE.WR: + p_mode = 'wb' + elif mode == lv.FS_MODE.RD: + p_mode = 'rb' + elif mode == lv.FS_MODE.WR | lv.FS_MODE.RD: + p_mode = 'rb+' + else: + raise RuntimeError("fs_open_callback() - open mode error, %s is invalid mode" % mode) + + try: + f = open(path, p_mode) + + except OSError as e: + raise RuntimeError("fs_open_callback(%s) exception: %s" % (path, e)) + + return {'file' : f, 'path': path} + + +def _fs_close_cb(drv, fs_file): + try: + fs_file.__cast__()['file'].close() + except OSError as e: + raise RuntimeError("fs_close_callback(%s) exception: %s" % (fs_file.__cast__()['path'], e)) + + return lv.FS_RES.OK + + +def _fs_read_cb(drv, fs_file, buf, btr, br): + try: + tmp_data = fs_file.__cast__()['file'].read(btr) + buf.__dereference__(btr)[0:len(tmp_data)] = tmp_data + br.__dereference__(4)[0:4] = struct.pack("= 0: + fs_drv.cache_size = cache_size + + fs_drv.register() + diff --git a/internal_filesystem/lib/mpos/ui/__init__.py b/internal_filesystem/lib/mpos/ui/__init__.py index e6d66683..b63dab8b 100644 --- a/internal_filesystem/lib/mpos/ui/__init__.py +++ b/internal_filesystem/lib/mpos/ui/__init__.py @@ -1,5 +1,3 @@ -#import utime # for time profiling - import lvgl as lv import mpos.apps import mpos.battery_voltage diff --git a/internal_filesystem/main.py b/internal_filesystem/main.py index 8c93ff5e..530fbad6 100644 --- a/internal_filesystem/main.py +++ b/internal_filesystem/main.py @@ -3,9 +3,9 @@ import _thread import lvgl as lv # Allow LVGL M:/path/to/file or M:relative/path/to/file to work for image set_src etc -import fs_driver +import mpos.fs_driver fs_drv = lv.fs_drv_t() -fs_driver.fs_register(fs_drv, 'M') +mpos.fs_driver.fs_register(fs_drv, 'M') import mpos.apps import mpos.config