Skip to content

Commit 09f1be4

Browse files
File Manager: custom implementation
1 parent 29daed6 commit 09f1be4

1 file changed

Lines changed: 140 additions & 33 deletions

File tree

  • internal_filesystem/apps/com.micropythonos.file_manager/assets
Lines changed: 140 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,150 @@
1+
import os
12
import lvgl as lv
2-
from mpos import Activity, Intent, print_event, sdcard, ui
3-
from action_activity import ActionActivity
3+
from mpos import Activity, print_event, sdcard
4+
45

56
class FileManager(Activity):
67

7-
# Widgets:
8-
file_explorer = None
8+
_action_bar = None
9+
_selected_path = None
10+
_current_path = None
11+
_list = None
12+
_path_label = None
913

1014
def onCreate(self):
11-
sdcard.mount_with_optional_format('/sdcard')
12-
#lv.log_register_print_cb(self.log_callback)
15+
sdcard.mount_with_optional_format("/sdcard")
1316
screen = lv.obj()
14-
self.file_explorer = lv.file_explorer(screen)
15-
self.file_explorer.explorer_open_dir('M:/')
16-
self.file_explorer.align(lv.ALIGN.CENTER, 0, 0)
17-
self.file_explorer.add_event_cb(self.file_explorer_event_cb, lv.EVENT.ALL, None)
18-
self.file_explorer.explorer_set_quick_access_path(lv.EXPLORER.HOME_DIR, "M:/home/user/")
19-
self.file_explorer.explorer_set_quick_access_path(lv.EXPLORER.PICTURES_DIR, "M:/data/images/")
20-
21-
file_table = self.file_explorer.explorer_get_file_table()
22-
file_table.add_event_cb(lambda e: print("FileManager: long press detected"), lv.EVENT.LONG_PRESSED, None)
17+
screen.set_flex_flow(lv.FLEX_FLOW.COLUMN)
18+
19+
self._path_label = lv.label(screen)
20+
self._path_label.set_width(lv.pct(100))
21+
self._path_label.set_style_pad_all(6, lv.PART.MAIN)
22+
23+
self._list = lv.list(screen)
24+
self._list.set_size(lv.pct(100), lv.pct(100))
25+
26+
self._populate_dir("/home/user/")
2327
self.setContentView(screen)
2428

2529
def onResume(self, screen):
26-
sdcard.mount_with_optional_format('/sdcard')
27-
28-
def file_explorer_event_cb(self, event):
29-
print_event(event)
30-
event_code = event.get_code()
31-
if event_code == lv.EVENT.VALUE_CHANGED:
32-
path = self.file_explorer.explorer_get_current_path()
33-
clean_path = path[2:] if path[1] == ':' else path
34-
file = self.file_explorer.explorer_get_selected_file_name()
35-
fullpath = f"{clean_path}{file}"
36-
print(f"Selected: {fullpath}")
37-
self.startActivity(Intent(activity_class=ActionActivity).putExtra("path", fullpath))
38-
39-
# Custom log callback to capture FPS
40-
def log_callback(self, level, log_str):
41-
# Convert log_str to string if it's a bytes object
42-
log_str = log_str.decode() if isinstance(log_str, bytes) else log_str
43-
print(f"Level: {level}, Log: {log_str}")
30+
sdcard.mount_with_optional_format("/sdcard")
31+
32+
def _populate_dir(self, path):
33+
self._dismiss_action_bar()
34+
self._list.clean()
35+
path = path.rstrip("/") + "/"
36+
self._current_path = path
37+
self._path_label.set_text(" " + path)
38+
39+
if path != "/":
40+
parent = "/".join(path.rstrip("/").split("/")[:-1]) + "/"
41+
btn = self._list.add_button(None, lv.SYMBOL.LEFT + " ..")
42+
btn.add_event_cb(lambda e, p=parent: self._populate_dir(p), lv.EVENT.CLICKED, None)
43+
44+
try:
45+
items = os.listdir(path)
46+
except OSError:
47+
return
48+
49+
dirs = []
50+
files = []
51+
for item in items:
52+
full = path + item
53+
try:
54+
if os.stat(full)[0] & 0x4000:
55+
dirs.append(item)
56+
else:
57+
files.append(item)
58+
except OSError:
59+
files.append(item)
60+
61+
dirs.sort()
62+
files.sort()
63+
64+
for d in dirs:
65+
fullpath = path + d + "/"
66+
btn = self._list.add_button(None, lv.SYMBOL.DIRECTORY + " " + d)
67+
btn.add_event_cb(lambda e, p=fullpath: self._populate_dir(p), lv.EVENT.CLICKED, None)
68+
btn.add_event_cb(lambda e, p=fullpath: self._on_list_long_press(p), lv.EVENT.LONG_PRESSED, None)
69+
70+
for f in files:
71+
fullpath = path + f
72+
btn = self._list.add_button(None, lv.SYMBOL.FILE + " " + f)
73+
btn.add_event_cb(lambda e, p=fullpath: self._on_list_long_press(p), lv.EVENT.LONG_PRESSED, None)
74+
75+
def _on_list_long_press(self, path):
76+
print(f"FileManager: long press on {path}")
77+
self._selected_path = path
78+
self._show_action_bar()
79+
80+
def _show_action_bar(self):
81+
self._dismiss_action_bar()
82+
screen = lv.screen_active()
83+
bar = lv.obj(screen)
84+
bar.add_flag(lv.obj.FLAG.FLOATING)
85+
bar.set_size(lv.pct(100), 60)
86+
bar.align(lv.ALIGN.BOTTOM_MID, 0, 0)
87+
bar.set_style_bg_color(lv.color_hex(0x444444), lv.PART.MAIN)
88+
bar.set_style_pad_all(8, lv.PART.MAIN)
89+
bar.set_flex_flow(lv.FLEX_FLOW.ROW)
90+
bar.set_flex_align(lv.FLEX_ALIGN.SPACE_EVENLY, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER)
91+
92+
delete_btn = lv.button(bar)
93+
lv.label(delete_btn).set_text("Delete")
94+
delete_btn.add_event_cb(lambda e: self._delete_selected(), lv.EVENT.CLICKED, None)
95+
96+
rename_btn = lv.button(bar)
97+
lv.label(rename_btn).set_text("Rename")
98+
rename_btn.add_event_cb(lambda e: self._show_rename_ui(), lv.EVENT.CLICKED, None)
99+
100+
cancel_btn = lv.button(bar)
101+
lv.label(cancel_btn).set_text("Cancel")
102+
cancel_btn.add_event_cb(lambda e: self._dismiss_action_bar(), lv.EVENT.CLICKED, None)
103+
104+
self._action_bar = bar
105+
106+
def _dismiss_action_bar(self):
107+
if self._action_bar:
108+
self._action_bar.delete()
109+
self._action_bar = None
110+
111+
def _delete_selected(self):
112+
path = self._selected_path
113+
try:
114+
os.remove(path)
115+
except OSError:
116+
try:
117+
os.rmdir(path.rstrip("/"))
118+
except OSError as e:
119+
print(f"FileManager: delete error {path}: {e}")
120+
print(f"FileManager: deleted {path}")
121+
self._dismiss_action_bar()
122+
self._populate_dir(self._current_path)
123+
124+
def _show_rename_ui(self):
125+
bar = self._action_bar
126+
if not bar:
127+
return
128+
bar.clean()
129+
old_name = self._selected_path.rstrip("/").split("/")[-1]
130+
ta = lv.textarea(bar)
131+
ta.set_text(old_name)
132+
ta.set_width(130)
133+
confirm_btn = lv.button(bar)
134+
lv.label(confirm_btn).set_text("Confirm")
135+
confirm_btn.add_event_cb(lambda e: self._confirm_rename(ta.get_text()), lv.EVENT.CLICKED, None)
136+
cancel_btn = lv.button(bar)
137+
lv.label(cancel_btn).set_text("Back")
138+
cancel_btn.add_event_cb(lambda e: self._show_action_bar(), lv.EVENT.CLICKED, None)
139+
140+
def _confirm_rename(self, new_name):
141+
path = self._selected_path
142+
dir_part = "/".join(path.rstrip("/").split("/")[:-1])
143+
new_path = f"{dir_part}/{new_name}"
144+
try:
145+
os.rename(path, new_path)
146+
print(f"FileManager: renamed {path} -> {new_path}")
147+
except OSError as e:
148+
print(f"FileManager: rename error {path} -> {new_path}: {e}")
149+
self._dismiss_action_bar()
150+
self._populate_dir(self._current_path)

0 commit comments

Comments
 (0)