feat(files): 新增外置系统文件管理器 os.meow.files (agent-183) — 目录浏览(虚拟化列表/空态)+文本预览(≤256KB截断)+删除/重命名/新建/属性(BottomSheet+IME);路径写操作限 TF 卡内(拒 .. 越界);多文件结构(app.c+ui/{browser,viewer}.c+ui/common/chrome.c+logic/fsx.c) 按批次②范本

files md5 6f6b0a6d; 0 warning; 宿主 test_fsx 全过(路径安全/格式化/排序/虚拟化/写操作/文本嗅探); qemu 离屏冒烟通过
SDK 缺口记录: listview 仅单行 label(本 App 用 custom 画布自绘行); common 档字库中文缺字(未声明 fonts:full)
真机待验证: 列表渲染/滚动手感/IME 重命名/弹窗交互
This commit is contained in:
MeowOS committed 2026-08-31 04:03:56 +08:00
1 parent b5038f8673
commit c187b7bce3
12 files changed
+1741

No files matched your search

+87
View File
@@ -0,0 +1,87 @@
# os.meow.files — MeowOS 外置文件管理器
TF 卡应用(`framework=1` 走 `meow_ui` SDK)。浏览 TF 卡目录树,支持进/退目录、列表虚拟化、
行操作(删除/重命名/新建目录/属性)、文本预览(≤256KB 截断)、空态/错误页;写操作严格限制在
TF 卡内(`/usr/data/mnt/sd_0`),拒绝 `..` 越界与卡外路径。
## 目录结构(多文件,批次②拆分范本)
```
patch_v2/files_app/
├── app.c # main + 装配 + 事件分发(key/tap/swipe/tick/touch → 当前页)
├── files_internal.h # 跨 TU 共享头(Activity id / 布局 / chrome/browser/viewer 声明)
├── build_files.sh # 交叉编译脚本(zig-mipsel-cc 静态链 meow_ui.a libz.a -lpthread)
├── app.json # {"name":"Files","exec":".../os.meow.files/files",...,"framework":1,"immersive":1}
├── README.md
├── ui/
│ ├── browser.c # 目录浏览页(ACT_BROWSER 根页):虚拟化列表 + 空态 + 行操作
│ ├── viewer.c # 文本预览页(ACT_VIEWER 子页):只读、可滚动、≤256KB 截断
│ └── common/
│ └── chrome.c # 共享 chrome:topbar 建置 / 内容区几何 / 空态&页脚绘制
├── logic/
│ ├── fsx.h # 纯业务接口(不依赖 meow_ui)
│ └── fsx.c # 路径安全/格式化/枚举排序/虚拟化区间/写操作(可宿主测)
└── test/
└── test_fsx.c # 宿主单元自测(gcc 直接编,指向临时卡根)
```
## 构建
```bash
cd patch_v2/files_app && ./build_files.sh
# 产物:files(MIPS32r2 静态 ELF,~270KB)+ ./files + app.json
```
构建脚本仿 `hello_app/build_hello.sh`:`zig-mipsel-cc -Os -static -Wall -Wextra -I../sdk -I.`
链 `../sdk/meow_ui.a "$SYSROOT/lib/libz.a" -lpthread`。**零触及 `patch_v2/sdk/`**(未新增/改任何 SDK 文件);
`-Wall -Wextra` 0 warning。
## 部署
```
/usr/data/mnt/sd_0/MeowAPPs/os.meow.files/
├── app.json
└── files
```
数据目录 `MeowData/os.meow.files/{data,cache}` 由 launcher 经 `MEOW_DATA_DIR`/`MEOW_CACHE_DIR` 注入;
v1 无需持久化,暂未使用(启动恒进卡根 `/usr/data/mnt/sd_0/`)。
## 宿主自测(不跨编/不刷机)
```bash
cd patch_v2/files_app
gcc -O2 -Wall -Wextra -DFSX_SD_ROOT='"/tmp/meowfsx_fsx_test"' -Ilogic \
test/test_fsx.c logic/fsx.c -o /tmp/test_fsx && /tmp/test_fsx
```
覆盖:路径安全(`within_sd`/`join`/`sanitize`/`dirname`/`basename`)、展示格式化(`fmt_size`/`fmt_time`)、
目录枚举排序(`scan_dir`/`sort`)、虚拟化区间(`visible_range`/`max_scroll`)、写操作(`mkdir`/`rename`/
`delete`,含卡外/越界拒绝)、非文本写拒绝。宿主全 PASS。
## 交互
- 触摸:行 body=进目录/开文本预览;右侧 `⋯` 或长按→BottomSheet(删除[确认弹窗]/重命名[IME]/新建目录[IME]/属性[大小·mtime]);
TopAppBar `NEW`=当前目录新建。
- 左缘左滑/返回钮:预览页→回目录;浏览器→上级目录;卡根再左滑=退出 App。
- 物理键不映射(APPS.md §3.4.1):息屏/音量/媒体语义归系统/SDK。
## 已知限制 / SDK 能力缺口(未改 SDK,如需请走 agent 立项)
1. **SDK `meow_lazycolumn` 仅渲染单行 label**(`meow_list_source` 填文本),无法表达「图标+名称+大小/时间+右侧操作钮」
的行布局。本 App 用 `meow_widget_custom_create` 自绘虚拟化列表满足该行版式;`fsx_scan_dir` 仍以有界数组缓存
(`FSX_MAX_ENTRIES=1024`)承载数据,列表虚拟化只画可见行(`fsx_visible_range`)——大目录不一次全读进内存。
2. **中文字形**:SDK 默认 `common` 字库(≈4k)不含 CJK 全量;exFAT 中文文件名/中文文本预览在 common 档会显示缺字豆腐。
预览页不声明 `fonts`(app.json 未加 `"fonts":"full"`/`"gbk"`),如需中文预览可在 app.json 声明大字号档。
3. **预览仅文本**:按扩展名白名单 + 首 512 字节 NUL 嗅探判文本;二进制/图片无预览(提示「not a text file」)。
超 256KB 只读前 256KB,页脚标注 `>256KB (truncated)`。
4. **符号链接不追链**:v1 视 symlink 为普通文件展示/操作(lstat),避免链出卡外。
5. **单目录条目上限**:>1024 项时只展示前 1024 并在页脚标注 `showing first 1024`(分页流式读目录为二期)。
## 验证状态
- 编译:`-Wall -Wextra` 0 warning/0 error,产物 `files`(MIPS32r2 静态 ELF)。
- 宿主:`test/test_fsx.c` 全 PASS。
- qemu-mipsel(无 /dev/fb0 → SDK 离屏 480×720):正常运行到事件循环,导出离屏帧,
确认 init/建页/topbar(返回+NEW)/空态(NO STORAGE CARD)渲染正确、SIGTERM 干净退出。
- 实机目录列表渲染(有真实 TF 卡目录)需刷机/设备挂载验证——宿主模拟无法造出 `/usr/data/mnt/sd_0`。