Commit Graph
142 Commits
Author SHA1 Message Date
AskaEth 40751c09bd Tuku reader: 真实解码峰值模型 + 3MB 硬阈值 + 解码取消 + 3 槽(M22 止损版)
真机(R3 Pro II 480×720 / MemTotal 56872kB):空闲 RSS 6044kB → 翻页 11400kB →
峰值 15600kB(MemFree 仅 1404kB)→ SIGKILL。M20 审计坐实根因是「单页解码瞬时峰值」,
且旧模型把 stb 当缩解库,对 JPEG 低估 3.5–8 倍(实测 baseline 2000×3000 +10.1MB、
渐进 +23.5MB、1200×1600 PNG +12.9MB)。本次按实测重定预算:

- 真实峰值模型 decode_peak_bytes():JPEG 分量面(+渐进 short 系数面)、PNG 源缓冲 +
  RGBA 转换副本、BMP 直写目标,再叠精修/落框两段一次性重采样;上限常态 3MB
  (MR_DECODE_PEAK_CAP),只有 MemFree 真富余时才放宽到 min(12MB, MemFree-4MB)。
- 超预算时的降级:JPEG 逐步加粗 stbi 缩解档位(meow_img_load_file_step),
  PNG/BMP 无解码期缩放 → 占位;结果精确重采样回显示框(meow_img_resample),
  命中页仍是单次 blit(M17 热路径纪律不破)。
- 占位可重试(g_page_skip 与永久失败 g_page_fail 分离):焦点页冷却 1.5s 自动重试、
  中间区点按立即重试、离开再回来即重试;坏图仍是永久占位。
- 解码前内存门控:MemAvailable < 6MB 不解码(读不到就放行,不猜)。
- 解码请求取消:worker 出队后、mr_book_open 前二次判 gen/窗口;拖动/fling 期间只解落点页,
  预取邻居仅当 MemAvailable ≥ 12MB。
- 先释放再解码:queue_page 按落地字节 slots_reserve() 先淘汰不可见旧图;可见页不淘汰。
- 槽位 4→3、常驻上限 9MB→3MB、结果队列 4→2。
- 可观测性:`reader decode page=N src=WxH peak=XkB memfree=YkB memavail=ZkB ok|skip=… step=S ms=M`
  与进出阅读器 rss/hwm/memfree/memavail。

page_source: 头部探测新增 codec/progressive/channels/planes(mr_probe_info),
只带最小 SOF 的合成头仍能取尺寸(旧契约不退化)。

宿主证据:新增 test_reader_membudget(--wrap malloc 计真实峰值):
PNG 600×960 model 4001kB vs 实测 3943kB;JPEG 1000×1500 step2 model 3749/实测 3711;
连翻 100 页 peak_transient 0kB(先释放再解码让缓冲复用)、驻留 ≤3MB、解码 100 次(取消生效)、
3MB 阈值下 1.5MP JPEG 可解、4MP JPEG 需 MemFree 放行(否则占位)、渐进式模型更高于 baseline。

run_tests.sh 全绿(含 zip 106 / cbz 325)、run_webtoon_tests.sh 全绿、SDK 与 tuku 交叉构建零警告。
2026-11-05 21:28:50 +08:00
AskaEth 773ab9ff92 Merge branch 'feat/sdk-mipsel-clock-abi-fix-sync' 2026-11-05 20:27:36 +08:00
AskaEth a07f9752d3 SDK: 内置 mipsel o32 时钟/睡眠 ABI 修复(meow_ui_time.c)+ 宿主单测
zig 0.17 内置 musl 在 mipsel 上头声明 64 位 time_t、实现走 time32 系统调用
(__ILP32__ 守卫),导致 meow_ui_time_ms() 毫秒位恒 0、高 32 位随机,
usleep(16000) 立即返回(帧节拍/轮询变忙等空转)。主仓已验证的修复逐字节
搬入公开仓:取时按内核 o32 ABI(8 字节 {int32 sec; int32 nsec})再升 64 位,
同 TU 强定义 __clock_gettime/64 与睡眠入口,链接期接管 libc。

- meow_ui_time.c / CLOCK_ABI.md:cp 搬运,md5 与主仓一致(含原注释与依据链)
- meow_ui_gfx.c:删掉 now_ms/meow_ui_time_ms(避免与 meow_ui_time.o 重复符号),
  6 处内部调用改外部 meow_ui_time_ms;<time.h> 不再使用
- meow_ui_internal.h:补 meow_time_ms_from_parts 声明
- build_sdk.sh:OBJS 首位加 meow_ui_time,头注释写明归档须排在 -lc 之前
- test_meow_time.c:适配公开仓构建方式,加负 sec 回绕两例,输出断言数(15)
- sdk/README.md:公开说明本次修复、链接顺序要求与已知限制(2038 前有效)
- tuku/test/run_tests.sh、run_webtoon_tests.sh:$SDK 源文件清单补 meow_ui_time.c
  (宿主集成测试直接编 SDK 源,否则链接期 undefined symbol)

验证:sdk/build_sdk.sh 0 warning;宿主 test_meow_time == PASS == checks=15;
tuku 两套测试全 PASS(run_tests 462+106+325 断言、webtoon 240 断言,0 failed);
探针/ picbrowser 反汇编确认 __clock_gettime 取自本 TU(8 字节 time32 + 升位),
无 libc VDSO 前导;picbrowser 仍为 MIPS32r2 静态 ELF。
2026-11-05 20:27:26 +08:00
AskaEth 4773ec1a61 Merge branch 'feat/tuku-library-file-manager-mode' 2026-11-05 20:27:19 +08:00
AskaEth 4befbfe14c 图库: 书库点图改按文件名定位(修 P1 截断错位)+ 册间衔接根锁定(M18 评审 r1)
P1-1(会静默开错图):取消「书库从列表推导图片下标」。
- 新增 mr_reader_open_dir_at_name(dir, name):阅读器打开目录册后,在**自己刚枚举出的
  全量目录册**(mr_dir_book,与翻页同一份枚举)里按 basename 定位起始页(先精确,
  再大小写不敏感兜底;找不到退回续读/首页)。书库点击只传文件名。
- 删除 mr_library_image_index(不再有跨枚举的隐式契约)。
- 截断提示文案改为「仅显示前 2000 项(图片可在阅读器中翻到)」。
- 修复前(cb02722 探针,2100 张 4 位名夹具):rows=2000/truncated=1/
  library_images=2000/reader_pages=2100/**mismatched=590**(首行 p1412 → 打开 p1411);
  评审夹具为 1995/2000。修复后:2000 个可见图片行按名定位 **0 mismatch**,
  2100 页全量可翻;26 次真实 UI 点开(首尾各 3 + 20 个确定性伪随机)逐张命中。

连带处理(评审 r1):
1. 删掉 reader_page_enter 的 c->view 死写(reopen 判定用 activity active/depth);
   顺手删掉 library_page_create 里同款死写。
2. 阅读器册间衔接根锁定:新增 mr_path_within_root + mr_book_adjacent_rooted,
   book_switch 用浏览根(默认 MR_ROOT_DIR,测试可注入)钳制相邻册;
   根外的兄弟册按「没有相邻册」处理。test_cont_adjacent A7 验证「明文 _ex 会越根、
   rooted 拒绝、根内翻册不受影响」;test_mode_switch_host H6 验证条漫末页不越根。
3. test_reader_perf 不再依赖顶栏 tap 命中时序:模式切换改走测试钩子
   mr_reader_test_toggle_mode()(与顶栏动作同一个 mode_set),负载下稳定。
4. page_cache 注释去掉「缩略图缓存/缩略图线程」过时描述(只改文字)。

回归:run_tests.sh(library 81 / nav 74 / lazy 57 / perf 25 / … / open_book 含 2100 用例)
与 run_webtoon_tests.sh(含 A7/H6)全 PASS;交叉构建零警告。
2026-11-05 20:26:40 +08:00
AskaEth 64336f95d9 图库: 书库改文件管理器模型 + 关闭缩略图 + 根锁定/无卡容错(M18)
用户反馈四件事一起改:
- 「目录里有一张图就被当成最终目录」→ 取消「目录含图=一本书」全部链路
  (探测/页数/封面/续读角标/懒算 worker/sr2 补位),列表 = 目录 + 图片 +
  .cbz/.zip(目录优先、组内自然序)。点目录=进入(空目录也进),点图片=
  mr_reader_open_dir_at(当前目录, 图片自然序下标),点档案册=打开档案册。
- 「文件夹浏览特别卡」→ 删除缩略图线程/磁盘 bmp 缓存/LRU/解码路径与行内
  缩略图;首帧只做一次 opendir/readdir+lstat,副标题(类型·大小)扫描期
  生成一次,行合成/滚动/点击零 IO 零格式化;去掉逐行 snap(自由滚动手感)。
  2000 项目录扫描 ~2.8ms(opendir=1, lstat=2000),行合成 2.78ms/200 万次
  (宿主实测;旧实现 2000 项 entry 含 512B cover,内存 2.7MB→1.7MB)。
- 「不要访问 SD 卡上级目录」→ 浏览根锁定 MR_ROOT_DIR:删除越根的顶栏
  「上级」/library_go_parent,根隐藏顶栏返回,左缘返回到根=退出 App。
- 「没有 SD 卡不要报错」→ 根不可访问(未插卡/挂载失败/根是文件)时友好空态
  「未检测到 SD 卡」+ 顶栏刷新/重进页面重试;子目录不可读才弹提示横幅。

集成陷阱:书库图片下标与阅读器目录册共享同一套过滤器(隐藏项/图片扩展名/
普通文件/符号链接)与 mr_natural_cmp,test_browse_lazy 直接对比
mr_dir_book_init 顺序,test_open_book_host 断言「点 img10 就开 img10」。

reader 侧 M17 遗留:mr_reader_open_dir_at 在阅读页已激活时先 pop 再 push,
走完整 leave/enter(SDK 对同 view 重复 push 是 no-op 且会压重复 activity)。

回归:run_tests.sh / run_webtoon_tests.sh 全 PASS;交叉构建零警告。
2026-11-05 20:26:40 +08:00
AskaEth d07b99056f Merge branch 'feat/sdk-scroll-wrap-slot-leak' 2026-11-05 19:53:11 +08:00
AskaEth c85877b447 SDK: 修 meow_scroll_wrap 池槽泄漏(free 归还 wrap 上下文槽)+ 64 次回收/交错/池满回归(M19)
meow_scroll_wrap 从 MEOW_SCROLL_POOL(=8) 个 wrap 上下文槽占一个,meow_scroll_free 只归还
会话槽、从不归还 wrap 槽也不清 ctx.w → 进程内最多成功 wrap 8 次,之后恒 NULL。图库
list_rebuild/load_dir 每次重建,进 8 个目录后列表丢惯性(g_scroll==NULL 走 scroll_by 兜底),
os.meow.files 同样每次 reload 重建。

- meow_scroll 结构内记 wrap_slot(创建置 -1),wrap 时写入槽下标;free 时按该下标清
  g_wrap_ctx[].w/lv 并归还 g_wrap_used,随后置 -1(二次 free 不触碰任何槽)。
  直接 create 的实例 wrap_slot=-1,free 不误清别人的槽。
- 池满语义不变:8 个同时活跃时第 9 个 wrap 仍返回 NULL(不越界);free(NULL) 安全。
- test_meow_ui_scroll 补回归:64 次 wrap/free 全可用(修复前 8/64,修复后 64/64)、free 后
  再 wrap、8 满 + 第 9 个 NULL + 释放其一即复用、两 wrap 交错 free 其一不串槽、直接 create
  不误清槽、list→listview→list 槽复用不残留 kind、free(NULL)/二次 free。
2026-11-05 19:38:55 +08:00
AskaEth 782a5f7c90 Merge branch 'feat/tuku-reader-perf-and-crash-fixes' 2026-11-05 18:49:23 +08:00
AskaEth ceb65dfd01 图库: 修条漫长页/竖翻每帧重采样(解码几何对齐排版)+ 判据与活锁(M17 评审 P1-1/P2)
评审用真实 UI 链路实测:600x960、800x1280(长宽比 1.6)在翻页拖动与条漫模式
都是 blit+0 / scaled+5;「先适高再切条漫」scaled+10。根因是解码几何来源与排版几何
不同源:decode_long_side() 把长边钳到屏长边 720(600x960 解成 450x720),而
strip_page_height() 按屏宽算出 480x768;mode_set() 又不动 g_fit,适高/原始进条漫
100% 重采样。

修复:
- 解码目标 = 排版真正要的显示框:新增 page_geometry_at()(条漫=strip 高度、宽=视口宽;
  翻页=fit/zoom),解码计划与绘页/就绪判据同源。
- plan_decode_long() 去掉屏长边钳制,只保留 MR_PAGE_BYTES_CAP(3MB) 硬上界,
  超长条漫按比例收缩(不再因为「高度 > 屏长边」就永远对不上)。
- slot 记录本次解码的 want 几何;slot_ready() 改为几何比较:
  fit/缩放/模式变化 → 重解一次(放大再缩回、适高→条漫回到纯 blit);
  被 3MB 钳住的解码 want 不变 → 不再反复重解(大屏活锁)。
- 解码几何随 page_req 下发、随 page_res 返回:worker 不再读 g_fit/g_zoom/g_vw/g_vh。
- 峰值估算把 downscale/缩解输出一并计入(P2-3)。
- 适宽长图(竖向单独溢出)不再算平移模式:1.6 比例页原先左右 tap/横拖会变成
  「水平平移 0px」的空操作,页面根本翻不动;现在仍按翻页处理(原始档/横向溢出不变)。
- 窗口不再主动清窗口外的页图:0→1→0 来回翻不再反复重解同一页(140 页测试
  decode 次数 21→14);容量仍由 MR_SLOTS + 字节淘汰兜底。
- state_reset 复位 g_meta/g_start_at(起始页在 on_enter 入口先取走),删重复注释。

测试:test_reader_perf 夹具改成 600x960(1.6)并补 800x1280、翻页拖动、条漫、
「适高→条漫」、双击放大缩回、静止无重解、大屏 1080x1920 无活锁;test_reader_many_pages
补 meow_ui_paint_full(绘制路径覆盖,P2-5)。
2026-11-05 18:28:52 +08:00
AskaEth 462cfd5bc0 图库: 阅读器翻页按显示尺寸解码(零重采样)+ 多页闪退防御 + 从第 N 张开始(M17)
用户反馈「横竖翻页都卡(40 页也卡)」「140 张图的文件夹一打开就闪退」
「要从中间某张开始看」三条,本次分别处理:

翻页卡顿(真因:每帧一次重采样)
- 解码目标从「屏长边」改成「当前 fit/zoom 的显示尺寸」:适宽 3:4 页原来解成
  540x720、显示 480x640,draw_page_at 于是每帧走 meow_ui_img_scaled —— 每页每帧
  多一遍全图最近邻重采样 + 一次 1.2MB 临时 malloc/free(>128KB 走 mmap)。
- 现在解码结果与显示框一致(±2px 容差)→ 翻页/滚动热路径只有原生 blit。
- fit/zoom 变化时按新几何重解(slot_ready 判据 + 同页替换),不再残留缩放;
  已到解码预算或已是原始分辨率的小图不会反复重解。
- 拖动/吸附/fling 帧只 invalidate 内容区(顶栏静态,不再每帧重绘标题文字);
  异步落位只在「该页真的在屏幕上」时才重绘,预取邻居不刷屏。
- 页原始尺寸按册缓存(8B/页),绘制几何不再每帧 fopen probe 文件。

多页闪退(宿主未能复现,按内存边界防御)
- 常驻页图改为「显示尺寸」并加上限:单页 ≤3MB、整窗 ≤9MB(超限淘汰最远页);
  常驻内存只与解码窗大小有关,不随页数增长。
- 解码中间峰值 >12MB 的页直接跳过并显示占位 + WARN(旧代码 PNG/BMP 放到 40MB,
  3000x3000 就是 36MB 瞬时分配;JPEG 完全没上限)。140 页夹具(含坏图/超大图)
  走真实 UI 链路打开、翻页、跳页、条漫全部通过。

新增 mr_reader_open_dir_at(dir, start_index)(文件管理器模式入口)
- 显式下标优先于续读记录;-1=续读(旧入口语义),其它负数钳到 0,≥页数钳到末页。
- mr_reader_open_dir 保留为 (dir, MR_READER_START_RESUME) 的包装;reader.h 导出。

测试:新增 test_reader_perf(翻页零重采样/fit 切换/驻留上界)与
test_reader_many_pages(140 页 + 坏图/超大图 + 起始下标/钳制/续读优先级 + 条漫跳页)。
2026-11-05 18:06:26 +08:00
AskaEth 73a9603ef0 Merge branch 'feat/tuku-one-click-pack-with-signing' 2026-11-05 17:40:57 +08:00
AskaEth 94eeabd789 图库: 打包改根布局并接入 meow_sign 一键签名(M16) 2026-11-05 17:37:50 +08:00
AskaEth e6a9e53ae9 Merge branch 'feat/tuku-open-book-and-back-gesture-fixes' 2026-11-05 13:07:51 +08:00
AskaEth 3cbcaaaac1 图库: 修系统返回语义与打开册资源路径(M15)
- 返回手势:书库列表排除左缘 24px 系统返回带并清空残留拖拽态;library_go_up
  到 TF 根返回 0(app.c 退出 App),不再上溯系统目录;顶栏返回改为显式
  library_go_parent(访问放开,可越过 TF 根到 /)。lock 页继续自行消费返回。
- 打开册:缩略图源图改用预算解码(meow_img_load_file_dim,峰值数十 MB→~1MB);
  离开书库页停止后台探测/缩略图线程,避免与 open_book 争内存/FD;打开失败按
  errno 记日志,ENOMEM/EMFILE/ENFILE/EAGAIN/EINTR 自动重试一次;修 open_book
  自拷贝 snprintf 的未定义行为。
- 测试:test_browse_ui_host 增加 TF 根退出/顶栏上级/左缘不拖拽断言;新增
  test_open_book_host(封面图+含图子目录的父目录 → reader 打开的完整 UI 链路)。
2026-11-05 13:03:20 +08:00
AskaEth 5ac227b225 Merge branch 'feat/tuku-fast-library-browsing' 2026-11-05 12:34:20 +08:00
AskaEth 66e598cb62 图库: 恢复缩略图 LRU 跳过解压页缓存(M11 P2-1 回归),补启动空列表/prune 回归测试(M13 评审 P2)
- ui/library/library.c cache_prune:rebase 时丢失了 M11 c775f85 的必修保护,
  恢复 `if (mr_cache_is_page_name(de->d_name)) continue;`(在 .bmp 过滤之前)。
  解压页缓存与缩略图同目录,mrpage_* 归 page_cache 自己的 64 页/32MiB LRU 管理;
  否则档案页被缩略图 LRU 统计并删除 → 每翻页重解压,且「touch 命中→解码」窗口内
  可能被删导致解码失败。
- 回归测试(MR_LIBRARY_UI_TEST_HOOKS 接缝):test_browse_ui_host 新增 U6——
  预置 1 个最旧 mrpage_*.bmp + 65 个较新缩略图,调用 library_test_cache_prune(),
  断言 mrpage_* 保留且不计入 64 张额度、缩略图被裁到 64;已验证去掉修复时该用例
  会失败(防止再次在 rebase 中丢失)。
- 顺手补齐/校正:
  ① test_browse_ui_host 的启动路径改为 create 前就把根指向不存在的目录,真实覆盖
     「启动根不可读仍建空列表」(断言 has_list/rows==0/横幅/当前目录),不再只是声明;
  ② tuku_internal.h 的 library_at_root 注释改为「书库根(生产=MR_ROOT_DIR,测试可改根)」。
- 复验:run_tests.sh 全 PASS(73/69/90/18/108/19/85 + settings 集成 + browse UI 集成
  + zip 106 + cbz 325);run_webtoon_tests.sh 全 PASS(76/36/71/57 + 集成);
  sdk/build_sdk.sh + build_tuku.sh 零警告 MIPS32r2 静态 ELF;UI host 测试 ASan/UBSan 全绿。
2026-11-05 12:31:46 +08:00
AskaEth 9f34417c49 图库: 单层浏览 + 懒判定与 M7/M11 整合;探测缓存 P2 修复(M13)
rebase 到 picbrowser(含 M7 条漫/续读、M11 CBZ 档案册)后的语义拼接:
- 保留单层扫描重写:一次 opendir/readdir+lstat 只列当前层(目录 + 注入 archive_pages
  时的 .cbz/.zip 档案文件),自然升序、隐藏项/符号链接跳过、2000 条截断标注;
  系统目录/空目录/无图目录一律列出;彻底删除递归「子树含图」探测
- 保留并复用 M11 档案册分支:add_dir_entry / add_archive_entry / entry_subtitle /
  entry_badge / archive_pages_at / sibling_is_book / mr_library_scan_ex 注入;
  档案册行同样先成行、页数由后台 probe(注入 zip 页数回调)懒算
- 保留 M7:mr_library_dir_has_images / mr_book_adjacent(_ex) 语义不变;为 adjacency
  恢复 ignored_dir_name(仅册间衔接跳过系统/隐藏目录,浏览本身不隐藏);
  mr_library_format_subtitle 在补位后拼「· 续读 Pn」角标
- mr_library_probe_path 统一探测目录/档案册:mtime(秒+纳秒)+size 失效的 256 项 LRU +
  互斥锁;评审 P2:只缓存「探测前后 stat 完全一致」的结果,期间变化则不写缓存
  (消除「不完整结果绑定新 mtime」的假新鲜;下次调用重新探测)
- UI:列表用 src2 每帧取行;后台线程探测优先于缩略图;档案册封面解压档内首图(M11);
  行语义=书页数/缩略图、空目录「空目录」、无图/坏档「无图片」;可上溯至文件系统 /、
  不可读目录提示并停留;TopAppBar「TF卡」回根;启动时根目录不可读也建空列表;
  顶栏回根命中加 g_tb_home_idx>=0 防御
- tuku_internal.h:library_go_up 注释校正(0=到达文件系统 /,app.c 据此退出)
- 测试:test_library 改单层语义;新增 browse_nav / browse_lazy / browse_perf /
  browse_ui_host(含评审 P2 的「探测期间变化不写缓存」用例);test_cont_adjacent A6
  改两段式;test_cbz T8/T10 改两段式(坏档/无图档案列出但非书);
  run_tests.sh 保留双方全部条目(browse 4 套 + run_zip_tests/run_cbz_tests)
- 复验:run_tests.sh 全 PASS(含 M11 zip/cbz)、run_webtoon_tests.sh 全 PASS;
  worktree 内 sdk/build_sdk.sh + build_tuku.sh 零警告静态 MIPS32r2 ELF
2026-11-05 12:23:31 +08:00
AskaEth c9cff99af3 Merge branch 'feat/tuku-cbz-integration' 2026-11-05 12:16:59 +08:00
AskaEth c775f8558c fix(tuku): 评审 P2-1/P2-2——解压页与缩略图缓存互删自愈 + 大页溢出文档化
P2-1(必修):解压页缓存与缩略图 LRU 在 *.bmp 上相互踩踏
- ui/library 的 cache_prune 先按 page_cache 的共用判据 mr_cache_is_page_name
  跳过 mrpage_*,不再把 BMP 解压页算进缩略图额度或 unlink(含 Vol10.cbz 这类
  BMP 档不再出现「被缩略图 LRU 删掉 → 首页解码失败」);
- mr_cache_touch 命中时 stat 校验文件存在与大小,缺失/尺寸不符即移出索引并按
  未命中返回,调用方重新解压——外部清理/掉电残留/误删都能自愈,不再返回死路径。

P2-2(文档化一次性溢出):
- page_cache.h 与 make_room_locked 写明:单条目本身超过 32MiB 时只保留该条、
  其它全部淘汰,占用上限受页源单页 64MiB(MR_ZIP_PAGE_MAX_BYTES)约束;
  大页仍可读,不因预算拒绝落缓存。
- 新增 33MiB 页夹具(PNG 头 + 可压零填充,deflate 后仅数十 KB)与断言:
  大页可读、cache_bytes 允许超 32MiB、小页被淘汰、再来小页时大页按预算淘汰。

顺手:page_cache.h 注释包名 os.meow.picobrowser → os.meow.picbrowser(测试路径同步)。

测试:test_cbz 267 → 296 项全 PASS;run_tests.sh(zip 106)与
run_webtoon_tests.sh 全绿;交叉构建 sdk/tuku 零警告,产物静态 MIPS32r2 ELF。
2026-11-05 12:13:47 +08:00
AskaEth 562cc44931 feat(tuku): CBZ 档案册集成——档案页源/书库列册/解压缓存
- logic/reader/archive_source.c:档案册页源实现 M6 mr_book 契约
  (mz_open/mz_count/mz_entry_at/mz_read_alloc),条目自然序 + 图片后缀 +
  路径安全(`..`/绝对路径/反斜杠/隐藏段/内嵌 NUL)+ 单页尺寸上限过滤;
  meta 按需解压只读图片头(不落缓存,结果按页记忆);mr_book_open_auto
  统一目录册/档案册开册,翻页与条漫两套消费代码零改动。
- logic/reader/page_cache.c/h:解压页落 MeowData/<pkg>/cache,LRU 64 页或
  32MiB,启动清 mrpage_* 孤儿,写入 .part + rename;与缩略图缓存同目录、
  前缀隔离;互斥量保护,解码/缩略图线程可并发。
- logic/library.c/h:扫描直接子文件里的 .cbz/.zip 成册(行=文件名+页数,
  点入直接阅读);档案探测由调用方注入(logic 不依赖 zip 容器),不注入时
  与 M7 行为逐字一致;册间衔接兄弟表=含图目录∪含页档案册,同列自然序。
  条目构造/副标题/角标/兄弟判据拆成小函数,便于 M13 书库重写拼接。
- ui/library:档案册行 + 封面缩略图(解压档内首图)、扫描注入探测、缓存
  目录统一由 page_cache 推导(一份规则)。
- ui/reader:open_book 走 mr_book_open_auto;跨册衔接纳入档案册。
- build_tuku.sh 补 zip/archive/cache 源与 sysroot zlib 头(zip.c include
  <zlib.h>);run_tests.sh 纳入 zip+cbz 用例;run_webtoon_tests.sh 的宿主
  集成构建补新源与 -lz;.gitignore 同步测试产物。
- test/test_cbz.c(267 项断言)+ make_cbz_samples.py 真实 cbz 夹具:
  列档/自然序/解压字节 CRC/路径安全/坏档与 zip 炸弹容错/LRU 与 32MiB 上限/
  启动清孤儿/续读角标/封面首图。
2026-11-05 11:58:12 +08:00
AskaEth 19620a7957 Merge branch 'feat/tuku-zip-reader-core' 2026-11-05 11:39:36 +08:00
AskaEth fbd4db3aec feat(tuku): zip 容器读取器核心(纯 C + zlib,central directory 校验/单条目按需解压) 2026-11-05 11:39:34 +08:00
AskaEth 6caf2bc6e6 Merge branch 'feat/tuku-webtoon-mode-and-continuity' 2026-11-05 11:39:24 +08:00
AskaEth ff97f3cee7 feat(tuku): M7 条漫模式与续读——模式一键切换/每册记忆、视口±1 懒解码、滑块跳页、册间衔接
- 条漫:meow_scroll 跟手+fling,按滚动位置懒解码视口±1 页(驻留上限 4 页);
  排版用 mr_book_meta 累加适宽高度(nav.c 纯逻辑,宿主可测)
- 模式:阅读 chrome 图标一键切翻页/条漫;每册模式与 last page 经 meow_config 持久化
  (reader.mode/page.<FNV1a64(册路径)>),重进该册恢复模式与页码
- 续读:离开/翻页/滚动停止节流落盘;书库扫描给含图册副标题追加「· 续读 Pn」
- 册间衔接:末页前进→同父目录下一含图册首页,首页后退→上一册末页;无相邻册轻提示不退出
- 跳页:chrome 内 meow_slider,目标页预解码完成后落位(2.5s 超时降级提示)
- 解码:改走 M12 预算解码 meow_img_load_file_dim;超大 PNG/BMP 先 probe 预判,
  超 40MiB 原始 RGBA 跳过并显示「图片无法显示」,12MiB 以上记 WARN(如实保留残余风险)
- 测试:新增条漫排版/跳页状态/模式续读持久化/册间边界宿主测试,以及真实 SDK 源码树上的
  阅读器集成测试(模式切换/跳页落位/续读/跨册),test/run_webtoon_tests.sh 一键运行
2026-11-04 21:49:33 +08:00
AskaEth 8cbb240931 Merge branch 'feat/mangareader-settings-and-pin-lock' 2026-11-04 21:32:17 +08:00
AskaEth cca3906c80 图库: M5 设置页(阅读方向/PIN/主题状态)与启动 PIN 锁屏;阅读方向持久化(评审 P1)
logic/pin(纯 C):加盐迭代哈希(FNV-1a ×1000 轮 + 每次设置新随机盐,16 位 hex)经
meow_config_* 持久化 pin.enabled/pin.hash/pin.salt;提供 set/verify/change/disable 与
4-8 位纯数字校验;enabled=1 但盐/哈希残缺时 fail-closed;落盘半途失败会还原旧盐,不留
「新盐+旧哈希」的双失效状态。

ui/settings(ACT_SETTINGS):MD3 分组表单(meow_listview 容器圆角卡 + 段头标签)——
阅读方向 RTL/LTR 走 mr_reader_set_direction;启动 PIN 开关与修改(开启/修改均两遍
MEOW_IME_NUM 确认);版本与主题状态行(跟随系统 + 当前明暗,随 app.c 主题 listener
整帧重绘)。控件一律在 on_enter 建(栈顶=ACT_SETTINGS),避免 §6.1 owner 绑到
ACT_LIBRARY 的跨页命中泄漏。

ui/lock(ACT_LOCK):lock_view_should_show() 读 logic/pin;启用时启动先入锁屏,验证前
不绘制任何书库内容;「输入 PIN」按钮弹系统数字键盘(MEOW_IME_NUM),错 PIN 就地提示
重试(无惩罚性锁定),正确则 page_pop 回书库;on_event 消费 SWIPE——左缘返回不能绕过
PIN 或退出 App(meow_view_dispatch_event 先于 app.c 的 on_swipe)。

logic/reader(评审 P1 修复,最小持久化):mr_reader_set_direction 成功切换后 best-effort
写 meow_config("reader.dir","rtl"/"ltr"),写失败只打 WARN 不阻断本次切换;
mr_reader_get_direction 首次调用惰性读一次配置恢复(无配置/非法值 → 默认 RTL),之后
纯内存快路径。宿主测试经 -DMR_READER_TEST_HOOKS 的 mr_reader_test_reset() 模拟重启。

测试/构建:test_pin(85 项,PIN 全分支,含单键半途落盘失败);test_settings_reader_persist
(19 项:默认/落盘/重启恢复/坏值/非法值/只读一次/写失败只告警);可选宿主集成
test_settings_lock_host(真实 SDK view/activity/widget + IME 注入,端到端验证错/对 PIN
解锁与设置页两遍开启;SDK 无源码时 SKIP);run_tests.sh 保持 46/46 并纳入上述测试
(reader.c 的配置/日志依赖由 test/settings_reader_stub.c 存根),build_tuku.sh 加入
logic/pin.c。交叉构建静态 MIPS ELF(zig-mipsel)零警告。

安全口径:PIN 防随手翻看,不是安全边界——TF 卡可拔出直读、配置可改;存储不使用加密库,
锁屏与设置页文案均如实标注该局限。
2026-11-04 21:25:17 +08:00
AskaEth 47325f2b81 Merge branch 'feat/sdk-image-budget-decode' 2026-11-04 21:19:03 +08:00
AskaEth 21bffa1aeb sdk: 图片层追加预算解码入口,JPEG 解码期缩解(峰值 43.7→14.0 MiB)
M6 finding(vuln/high):meow_img_load_file 必先整幅 RGBA 解码,1600×2400 漫画页
瞬时峰值 20.2 MiB(15.4 MiB 输出 + 5.5 MiB YCbCr 平面),超设备 ~14MB 口径,
App 侧无法规避。

调研(vendored stb v2.30):无解码期缩放能力——JPEG 走固定 hs/vs 重采样到全尺寸,
PNG 一次性 inflate 整幅 raw_image,公共 API 只有 load/load_16/loadf/info。
完整缩小 IDCT 需改编 1/2、1/4、1/8 IDCT + 进升级系数存储 + MCU 尺寸,改动面大且
易出静默像素错误,故不重写解码器。

改为受控的最小追加(sdk/stb_image.h):
- 新增 stbi_load_scaled / stbi_load_scaled_from_memory:JPEG 输出级按步长 s 抽取
  行/列(resample 状态机逐行推进,仅采样行做颜色转换),整幅原尺寸输出缓冲从不
  物化;scale<=1 与旧 API 逐字节等价,非 JPEG 忽略。
- 进升级 JPEG:各分量系数 IDCT 进像素平面后立即释放(原来拖到输出分配之后)。
- 旧公共 API 行为不变。

SDK 追加式入口(旧 API 一字未改):
- meow_img_load_file_dim / meow_img_load_mem_dim(path/buf, maxdim):stbi_info 头探测
  选 1/2、1/4、1/8 整数档(取「长边/s ≥ maxdim」最大档,不欠采样),再交既有
  meow_img_downscale 精修;小图/maxdim<=0 走旧路径。
- meow_img_probe_file:只读头取尺寸,供 App 在 OOM 前提示。

实测(宿主 test_meow_img_budget,--wrap malloc 打点,全部 PASS):
  8.32MP JPEG   43.70 → 13.96 MiB(新/旧 0.32)
  1600×2400 页  20.16 →  9.18 MiB
  progressive   43.70 → 35.83 MiB(系数阵列扫描期驻留,残余上限)
  PNG 2400×1600 25.65 → 25.65 MiB(stb 无 PNG 缩解,如实记录)
  BMP 2400×1600 14.65 → 15.23 MiB(同上,多一次降采样小缓冲)
缩解结果与「整幅解码+downscale」网格平均差 6.28;对 PIL 逐像素比对与全幅解码
同误差量级(mean ≤0.02, max ≤3)。

验证:build_sdk.sh 重编 meow_ui.a 0 warning;examples/hello 重链 0 warning;
tuku 用 MEOW_SDK_DIR 指向本分支 sdk 重链 0 warning;既有 test_meow_img_color 仍全 PASS。
2026-11-04 21:02:39 +08:00
AskaEth 5f40d6fd87 Merge branch 'feat/tuku-fluid-viewer-core' 2026-11-04 20:58:13 +08:00
AskaEth 23c9db73df feat(tuku): 阅读器左右翻页核心——页源契约/预解码窗口/跟手翻页/方向感知 tap
- 页源契约(logic/reader):count/meta/open/close + 目录册(文件夹即书)为第一个实现;
  meta 由纯 C 图片头探测(PNG IHDR/JPEG SOF/BMP)提供原始尺寸,条漫可先排版再取图,
  zip 册(M9/M11)只需另写 mr_book_ops,两种消费方式零改动复用
- 翻页引擎:pthread 后台解码窗口=当前±1 页(目录册 downscale 到屏幕长边),翻页只 blit
  缓存页图 + meow_anim 150ms 滑动吸附;未命中立即切页显示加载态、不在翻页路径解码;
  只 flush 内容区;decode/flip 首帧/翻页完成/进出内存全部 meow_log 打点
- 阅读页 UI:fit 三档(适宽/适高/原始,TopAppBar 动作循环,标题显示页码 x/y)+
  双击以点击点为锚放大(临时缓冲超上限自动降倍率)+ 单指拖拽/滑动步进平移;
  tap 三分区方向感知(RTL 默认:左=下一页,LTR 反之),中区切 chrome;
  左缘返回交给 app.c、屏底热区交给 SDK 回桌面,两者都不拦截
- 跟手:app.c 仅补 2 处极小路由(ACT_READER 的 down/move),reader 自行算位移;
  屏底 28px/左缘 24px 不进拖动,竖向主导放弃横滑
- 内存纪律:驻留 ≤3 张 downscale 页图;放大时窗口收缩到当前页;on_leave 停解码线程、
  释放全部页图/册索引/TopAppBar,并记录 VmRSS/MemAvailable 前后对比
- 测试/构建:新增 test_reader_core(契约边界/空册/越界/重复 open-close/首末页/头探测/
  方向语义/fit/平移夹取,108 项);run_tests.sh 与 build_tuku.sh 源列表接线;
  宿主 46+108 全 PASS,交叉构建静态 MIPS32r2 ELF、-Wall -Wextra 零警告
2026-11-04 20:58:05 +08:00
AskaEth 28b67a7b8d Merge branch 'feat/sdk-host-test-fixes-d1-d7' 2026-11-04 20:26:48 +08:00
AskaEth 432875d4e6 sdk: 宿主测试头注释按实测修订 + select T1 探针修正
- test_meow_ui_select: T1 选中高亮探针移到容器卡内(x=12),
  适配 M6.37 起的 listview 默认容器模式;6/6 PASS
- 各 test_*.c 头注释补 -Iinclude、meow_ui_nav.c 及精简源列表最小补集
  (theme/widgets/notif_gesture/overlay/suppress/sdk_fixes/pinyin/ime_fix)
- test_sb_statusbar 头注释给出可链接命令(--allow-multiple-definition)
- notify_post/ui_audio_host/p1p2p3 标注需主仓组件,公开仓跳过
- docs/APP_DEV_GUIDE.md: 去掉叠字与过强表述,改为 34/38 实测口径
2026-11-04 20:26:35 +08:00
AskaEth 2c60de141f 图库: 包名定为 os.meow.picbrowser(用户指定系统前缀)——app.json package/exec、build/pack 产物名与 README/.gitignore 同步;交叉构建+打包复验通过 2026-11-04 20:22:44 +08:00
AskaEth 429535e4d9 Merge branch 'feat/mangareader-skeleton-and-library' 2026-11-04 20:20:34 +08:00
AskaEth f4c21c74a1 fix(tuku): 书库显式启用 MD3 容器模式并补 M4/M5 接缝注释
- P1:list_rebuild() 在 set_item_renderer/set_item_tier 后调用 meow_listview_set_container(g_lv,1),
  修正 SDK 默认 container=0(扁平满幅+分隔线)与任务要求的 MD3 圆角卡观感不一致
- P2:reader/lock/settings 桩头补接缝注释——on_create 在 meow_view_create 内运行且 activity 栈空,
  非根页控件须 lazy 到 on_enter 或 push→建→pop;lock 另注明必须由自身 view on_event 消费 SWIPE,
  否则左缘滑动绕过 PIN
- 复验:宿主测试 46/46 PASS;交叉构建静态 MIPS32r2 ELF、-Wall -Wextra 零警告
2026-11-04 20:09:24 +08:00
AskaEth bed6a95485 feat(tuku): 图库 M3 骨架——书库浏览/主题同步/阅读器与锁屏接缝
- 新增顶层 tuku/ 工程(package dev.tuku.app、二进制 tuku):app.c/internal 头/logic/ui 分层、app.json、build/pack 脚本
- 书库:从 TF 卡根浏览文件夹,含图目录=一本书;logic/library 纯 C 扫描+自然排序(page2<page10)
- 流式缩略图:后台线程解码+meow_img_downscale(96),首帧/滚动不阻塞;磁盘缓存 MeowData/<pkg>/cache(mtime 失效+LRU)
- 列表 meow_listview 虚拟化 + meow_scroll fling/snap;行=缩略图+目录名+页数
- 主题:全部语义色 + meow_theme_add_listener 即时重绘;明暗/风格族两态可读
- 导航:meow_view page push/pop、TopAppBar ⚙→设置;reader/settings/lock 最小桩
- 接缝:mr_reader_get/set_direction(默认 RTL)、lock_view_should_show()(桩 0)
- 宿主 gcc 测试 46 项 PASS;交叉构建静态 MIPS32r2 ELF、-Wall -Wextra 零警告
2026-11-04 19:44:18 +08:00
AskaEth c0396e40ce sync(SDK): 增量同步主仓 M6.37–M6.39 至公开 SDK 仓
sdk/:
- 同步 meow_ui_widget/input/gfx/lazygrid/audio/media/img 等源码与头
  (SDK 默认列表/容器控件默认 MD3 — meow_list_set_container 可回退;
   全局 App 内底部上滑回桌面 — meow_ui_input_is_home_swipe 系统保留手势;
   LazyGrid/LazyColumn/LazyRow MD3 化;叠加让位自抑改 app_id 判定;
   DSD 音频格式等)
- 新增独立模块源码 meow_img_color / meow_lyric / meow_lyric_view 及对应宿主 test_*.c
- 保留公开仓自包含适配:vendored meow_font.c/meow_font.h/meow_notif.h 不动;
  build_sdk.sh 自包含版本不动;meow_ui_gfx.c 仅改 meow_font.h include 路径;
  meow_ui_internal.h 去除 FreeType 内部声明
- meow_ipc.h 同步到主仓 launcher 版本(含 AUDIO_FMT_DOP/媒体歌词/蓝牙输出协议)
- 不含 FreeType 矢量字 meow_ft_*(需 freetype vendor,公开仓以位图 meow_font
  自包含);不含 mipsel 二进制 / .o / .a / 固件 / 密钥 / devdocs

examples/hello/:
- 新增 ui/demo/sdk2/sdk2.c;build_hello.sh 纳入该文件(保持自包含)

docs / README / .gitignore:
- docs/MEOW_APP_SDK.md 补 §12.5(默认 MD3 容器 + 底部上滑回桌面 + 两个新 API)
- README 能力清单补「默认 MD3 容器」与「底部上滑回桌面」
- .gitignore 补新增宿主测试二进制

验证:sdk/meow_ui.a 与 examples/hello/hello 交叉编译均 0 warning;工作区无生成物。
2026-09-04 18:05:36 +08:00
AskaEth a1687486bc sdk: full-sync M7.0a/b (theme view input gfx 等, 真实功能非FT) 2026-09-03 06:51:44 +08:00
AskaEth a70cdbc0f7 sdk: 补同步 swipe-delete 缺失文件(widget/widgets.h/internal.h/build_sdk.sh) 2026-09-03 05:59:59 +08:00
AskaEth 64cde13c8d sdk: 同步主仓新增模块 cachegov/lazygrid/select/net 通道 2026-09-03 05:09:05 +08:00
AskaEth 0af6af7c7e docs: 同步主仓最新 SDK 设计/开发者指南 + README 新能力清单
MEOW_APP_SDK.md(相对主仓 MEOW_APP_SDK.md,保留公开仓化改写与免责声明):
- 公共头模块索引补 meow_ui_str.h 行
- §5.5 新增「虚拟化层」(W_LISTVIEW 固定 item 池/多行富 item/自绘钩子;去除 ncm 引用)
- §5.8 新增 TopAppBar 位图动作图标 + sb_icons[] 30 图标索引表
- §6.1 后插入 §6.4 事件分发形式化(命中/捕获/消费/层间隔离/唯一焦点)
- 新增 §12 布局/动画/滚动(meow_box/meow_anim/meow_scroll)+ §13 字符串 i18n(meow_str_*)
- 遗留/待实现 由 §12 重编号为 §14;去除 ncm/网易云/NetEase 字样

APP_DEV_GUIDE.md:新增 §7.11 字符串资源/i18n(保留既有公开化改写 §1.1/§5.2/§10 等)

README.md:更新 include/ 子头计数(20),补「SDK 能力速览」(布局/动画/滚动/事件分发/
虚拟列表/i18n/图标库/图片降采样)

.gitignore:新增本次引入的宿主测试二进制名(test_meow_ui_box/anim/dispatch/listvirt/scroll/str)
2026-09-02 09:17:20 +08:00
AskaEth 4b094d62a5 sdk: 增量同步主仓新模块(box/anim/scroll/dispatch/listvirt/str/sb_icons/img)
subtree pull sdk 来自主仓 pub/sdk(主仓 commit 68ce46a 等)。新增:
- 布局引擎 meow_ui_box / 动画基座 meow_ui_anim / 滚动物理 meow_ui_scroll
- §6.4 事件分发形式化 / W_LISTVIEW 虚拟化多行 / meow_str 字符串资源 i18n
- sb_icons 动作图标扩充 + topbar 位图图标 / meow_img_downscale
- tools/ 图标生成脚本与 SVG 源
- 对应宿主 test_*.c 与 demo_box_scroll.c

build_sdk.sh 冲突解析:保留公开仓自包含版(vendored meow_font + -Iinclude -I.),
OBJS 手工并入 4 个新模块(meow_ui_box/anim/scroll/str)。保留 vendored meow_font.c/
meow_ipc.h/meow_font.h/meow_notif.h,剔除宿主测试二进制与编译产物。
2026-09-02 09:08:51 +08:00
AskaEth 66e9cd5fa4 fix(ncm §32): 内存瘦身修 OOM 被杀 —— 封面降采样(8.28MB→0.78MB) + 瞬态 rbuf 缩减 + 线程栈显式
真机 dmesg 实锤:OOM Kill ncm (score 460, anon-rss 26.9MB, 设备 56MB)。
画像:封面全分辨率 RGBA 8.28MB(1448x1448 原生解码驻留) 是最大可控块。

瘦身(按收益排序):
1. sdk meow_ui_img 新增纯增量 meow_img_downscale + cover.c cover_cap(≤480px)
   → 封面 8.28MB→0.78MB,-7.65MB(mem_sim 实测 PASS)。
2. ncm_api.c 瞬态响应 rbuf:song_url→64KB、lyric/song_detail/cloudsearch/user_playlist→256KB
   (detail/track_all 保 1MB)。
3. ncm_app_internal.h 新增 ncm_thread_create(显式 128KB 栈),替换全部 14 处 pthread_create。
4. 滑动窗口/meta 复核零回退(window_sim:608B/首,6000 首 280KB 恒定)。

验证:mem_sim 封面收益 PASS + host home/player 渲染 OK + stream_sim/player_flow_sim/
window_sim/search_sim/cache_evict_sim 全 PASS + test_ncm_core host+mipsel(qemu) PASS
+ build_ncm.sh -Wall -Wextra 0 warning。真机 scp 播放在跑确认(缓存曲,0 播放请求)。

新 ncm md5 44fa16fe(text 1015150/bss 1362500)。正式部署留主会话。
2026-09-02 03:43:42 +08:00
AskaEth f44d702124 sdk: sb_icons 扩充动作图标 + TopAppBar 位图图标支持
TopAppBar 动作项此前用字体码点(⚙↻⌕)绘制,4k 字库无这些码点→豆腐。改走位图:
- sb_icons.h 追加 15 个 Material Symbols Rounded 动作位图(settings/refresh/search/
  play_arrow/pause/skip_next/skip_previous/arrow_back/close/add/check/lyrics/
  queue_music/download/heart),FILL=1 实心与状态栏一致;sb_icons[] 只追加(0-14 不变),
  动作索引 15-29。
- 生成脚本 tools/gen_action_icons.py(cairosvg svg→32x32 单通道 alpha,SVG 缓存
  icons_src/ 可复现、断网可跑)。
- meow_ui_gfx.c 抽取图标 blit 像素核心 icon_blit_px,新增 meow_gfx_blit_icon_ink
  (控件路径不标顶栏脏区);meow_gfx_blit_icon 状态栏路径行为不变。
- meow_ui_widget.c W_TOPAPPBAR 项支持位图模式:新 API meow_topappbar_set_item_icon
  (w, idx, icon_idx),绘制取主题 onSurface/按压向栏底色淡 12%,文本项行为不变;
  hit 用统一项宽。
- 公共头 widgets.h 加 MEOW_ICON_*(15-29) 枚举与 set_item_icon 声明;internal.h 声明
  meow_gfx_blit_icon_ink。
- 宿主测试(test_meow_ui_widgets)加 topbar 位图图标绘制/命中/按压变淡 + 状态栏 blit
  回归断言;test_umbrella 加 MEOW_ICON_* 编译期锁;MEOW_APP_SDK.md 补说明+索引表。
- 验证:宿主测试 ALL PASS(14项);交叉 zig 构建 0 warning;meow_ui.a 新 md5
  1d69cdae55ab5dde3a98f5e2124f3656。
2026-09-02 03:24:46 +08:00
AskaEth 2e8fac2a07 sdk(ui): 字符串资源外置(i18n 雏形 §13)—— meow_str_* + 内嵌双语表 + TF 覆盖表 + 控件接入
公开 SDK 前把 SDK/App 硬编码文案外置:新增 meow_str/meow_strf/meow_str_set_locale/
meow_str_locale,按当前 locale 取串(永不 NULL),第三方开发者可做多语言。

- 新增 include/meow_ui_str.h + meow_ui_str.c:取串优先级 = TF 覆盖表 > 内嵌当前语言
  (en_us→en 其余→zh) > 内嵌内置默认(zh_cn) > 原样返回 id。内嵌双语表(common.* 21 条 +
  ime.* 9 条);热路径零 malloc(编译期静态表 + ≤256 静态覆盖数组);纯 libc 宿主可单测。
- locale 存系统设置 settings.conf 的 ui.locale(默认 zh_cn,首次调用惰性读取);
  meow_str_set_locale 即时切换 + 重载覆盖表 + best-effort 持久化(流式改写保留其它行)。
- TF 覆盖表 MeowData/<pkg>/strings/<locale>.txt(id=text 行,UTF-8,'=' 两侧去空白);
  无卡/无文件/无该 id → 回落内嵌。meow_strf 用调用方缓冲(snprintf 语义,重入安全)。
- SDK 控件接入:dialog 默认按钮 OK/CANCEL + INPUT 占位、IME 键面/徽标(空格/确定/拼英/
  ?123/清/拼音/(无候选)/中)改走 meow_str;空态/加载态给 App 提供 common.no_data/loading。
- 测试:新增 test_meow_ui_str.c(内嵌回退/TF 覆盖优先级/未知 id 回退/切 locale 即时生效/
  查找正确性/meow_strf,tmp+env 两模式);全量宿主回归(widgets/dispatch/box/anim/scroll/
  listvirt/theme/ime_fix/pinyin/overlay/notif/sdk_input_keys/p1p2p3/config/vol/sb_collapse/
  notify_*) 0 回归;交叉 zig-mipsel -Wall -Wextra 0 warning。
- 文档:MEOW_APP_SDK.md 新增 §13(字符串资源/i18n,遗留顺延为 §14);docs/APP_DEV_GUIDE.md
  新增 §7.11。各宿主 test_*.c 头注释补 meow_ui_str.c 编译依赖。

边界(§13.7):仅 zh_cn/en_us 整串取用;不做复数规则 / BiDi / RTL / 动态字体回退(雏形)。
2026-09-02 02:37:38 +08:00
AskaEth 2d974bed62 sdk(ui): W_LISTVIEW 虚拟化层 — 固定 item 池 + 多行富 item + 完全自绘 (§5.5)
在既有 W_LISTVIEW (src2 每帧取行) 之上叠加虚拟化层 (API 追加式, 旧 API 一字不改):
- 数据源 count_fn + bind_fn (index, meow_lv_item*, ctx); count 每帧实时查 (任意长度≥65535,
  不常驻 item 对象); bind 仅在行进入视口时被调一次
- 固定 item 池: 视口行数+2 静态槽 (有界 ≤96), 回滚不重绑 (同 index 命中同槽); 整表扫过后
  wrap 回收合法但每次 draw 有界 (≤视口窗口)
- 多行富 item: 主标题/副标题/左图标·缩略图/右尾件; 行高 set_item_h(px) 或 set_item_tier(1→48/2→56);
  默认 renderer 主题语义色绘制; set_item_draw 完全自绘; section 段头占位行(非粘性); 空态占位
- 集成: tap_at→meow_ui_focus_acquire (§6.4); meow_scroll_wrap(lv,1) track+fling+snap(行边界);
  选中/按压态走主题; enabled=0 变淡不响应
- 兼容: src2==NULL 走既有路径; W_LIST/W_LISTVIEW 单行用法零改动

验证(宿主): 新测试 test_meow_ui_listvirt T1-T5 全 44 PASS (10000 项滚动窗口内容正确/hit 映射/
bind 有界=count/回滚不重绑/多行渲染/截断/图标占位/段头/空态/自绘/焦点/fling 吸附);
全量回归 widgets/dispatch/box/anim/scroll/ime/pinyin/overlay/notif/sdk_input_keys/p1p2p3 全 PASS;
交叉 zig-mipsel -Wall -Wextra 全 SDK TU 0 warning; meow_ui.a 新 md5=2a2d8000b95dd211d09dc736d5538ad0

文档: MEOW_APP_SDK.md §5.5 同步虚拟化层(API 一览/池语义/集成/回归).
2026-09-02 01:36:48 +08:00
AskaEth 63ac0fd7dc sdk: 事件分发形式化(§6.4)—— 统一命中/捕获/消费/层间隔离/焦点
根治「焦点/事件穿透」一类反复 bug。此前命中/捕获/消费/层间隔离各处 ad-hoc;
现上收为单一仲裁者(meow_ui_input.c),公共 API 只追加、不删改既有签名。

分发模型:
- 触摸沿 z 序自顶向下命中(meow_draw_hit_topdown,owner==active+enable 过滤);
- 命中即消费;模态层永远先审(meow_ui_modal_begin/end/active/depth);
- down 捕获(meow_ui_gesture_begin/owner/end):命中目标捕获手势直到 up,防滑出误触下层;
- 模态存在时下层完全收不到事件——hit_topdown 恒返回模态哨兵(背板消费,不透传);
- meow_ui_run 在 TOUCH_DOWN 自动 begin、TAP/SWIPE/LONG_PRESS/NOTIF_PULL 自动 end。

焦点模型:
- 唯一持有者(meow_ui_focus_acquire/release/owner/tap);
- 点非 focus 区域→释放并通知(meow_ui_focus_tap,list 焦点残留根治);
- 滚动容器(list/listview)tap_at 命中行自动 acquire,点外由 run 的 focus_tap 释放;
- lost 回调(meow_ui_focus_set_lost_cb)通知转移。

迁移(行为修复,正常交互语义不变):
- dialog/sheet → meow_ui_modal_begin/end(模态期下层收不到;叠黑由既有整帧快照+卡片仅重绘保证);
- list/listview tap → meow_ui_focus_acquire;
- 注入/叠加让位(overlay_input_suppressed)与模态层隔离互补,语义不变。

验证:新穿透矩阵 test_meow_ui_dispatch(M1 模态点下层不触发 / M2 弹层叠开两层层隔离 /
M3 捕获手势滑出不误触 / M4 list 焦点点外释放)ALL PASS;
全量回归 widgets/ime_fix/pinyin/overlay_suppress/notif_gesture/sdk_fixes/sb_collapse/
p1p2p3_repro/box/anim/scroll/sdk_input_keys 全 PASS;交叉 -Wall -Wextra 0 warning。

meow_ui.a 新 md5:a9fcfb6eeb07ddbdd48039df4f8f18ce(主会话统一重链,本仓未重链 App)
2026-09-02 00:57:58 +08:00
MeowOS 962888b96f SDK 冲刺批①+②+⑤: meow_box 线性布局 + meow_anim 动画基座 + meow_scroll 滚动物理
- meow_box(include/meow_ui_box.h + meow_ui_box.c):竖直/水平容器;子项=固定|weight|wrap;
  margin/padding/gap;主轴对齐 start/center/end/space-between/around/evenly;交叉轴 start/center/end/stretch;
  嵌套(深度≤16 静态栈,单遍求解,无递归爆炸)。可作 meow_view 布局提供者
  (meow_view_set_layout/relayout,opt-in;未设布局的 view 保持现有绝对坐标行为)。
  新增 meow_widget_set_rect(只写字段不标脏)作为 box 写坐标的通道。
- meow_anim(include/meow_ui_anim.h + meow_ui_anim.c):时间驱动 tween(from/to/duration/easing:
  linear/ease-out/ease-in-out/overshoot)+ update/done 回调;静态池≤16、取消、并行多动画;
  meow_anim_set_region 让每帧只 flush 动画影响区(不整屏)。meow_anim_tick 挂主循环 on_tick,
  无动画零开销(只查计数即返回)。
- meow_scroll(include/meow_ui_scroll.h + meow_ui_scroll.c):速度跟踪(最近 N 采样加权)+ 松手 fling
  (减速度曲线,用 anim 基座驱动)+ 边界过冲 clamp + 简单回弹(不做 spring)+ 可选 snap;
  跟手拖动行为不变(track 内部调既有 set_scroll);每帧只 redraw 列表视口区;不引 libm。
- 追加式:既有 meow_row/column/box 与全部 meow_*_create/hit/scroll 签名一行未改;旧绝对坐标永远有效;
  既有 App 免改源码。
- 验证:宿主新测试 box(42)/anim(32)/scroll(17) 全 PASS;既存 9 回归(widgets/sdk_input_keys/ime_fix/
  pinyin/overlay_suppress/notif_gesture/sdk_fixes/sb_collapse/p1p2p3_repro)全 PASS;
  离屏 demo(demo_box_scroll.c)渲染 box 布局 + 列表 fling 正常;zig-mipsel -Wall -Wextra 全 TU 0 warning;
  meow_ui.a md5 83dd6a2d0d24cc748a8659c29f1de2b5(未重链/部署 hello/files/ncm/reader,由主会话统一处理)。
2026-09-01 23:49:24 +08:00
AskaEth 35a623dfb6 merge: 接入 Gitea 初始提交(内容以本仓为准) 2026-09-01 23:28:57 +08:00