feat(reader): M27 书架按目录分组(ui.shelf_group=folder|format,默认 format 不变)

- 新增 shelf_model.c/.h:扫描/行序列从 shelf.c 拆出(纯 C,宿主可测);shelf_book 加 group[96](相对 Books/ 的目录路径,根下空串),path 语义/内容完全不变(进度键仍为 rdprog_hash(path))
- folder 模式:目录段头(根下=未分类),未分类置顶、其余按目录名排序;组内沿用最近阅读优先/其次书名;空目录不产生段头
- format 模式逐行保持旧行为;新增 reader.conf ui.shelf_group,缺键默认 format
- 上限 256→2048(SHELF_MAX_ROWS=2N=4096,段头≤书数),超限置可读提示,不再静默截断
- 顶栏加「目录/格式」切换,设置页加「书架分组」;UTF-8 安全截断长中文目录名
- 单测 test/shelf_group_smoke.c(38 断言)+ 计时 test/shelf_scan_bench.c
- build_reader.sh:链 meow_ui.a 解析冒烟 stbi_*;无 qemu 时跳过执行而非失败
This commit is contained in:
AskaEth committed 2026-11-09 21:55:33 +08:00
1 parent db672cbe8f
commit 409fd1edf7
11 files changed
+800 -129

No files matched your search

+6
View File
@@ -44,6 +44,7 @@ static void conf_defaults(rdconf *c)
strcpy(c->bg, "black"); /* B 定案:默认纯黑 */
strcpy(c->theme, "auto");
strcpy(c->shelf, "list"); /* A 定案:默认 list */
strcpy(c->shelf_group, "format");/* M27:默认按格式,升级不改变现有用户书架 */
c->header = 1;
c->footer = 1;
c->font[0] = 0;
@@ -72,6 +73,7 @@ rdconf *rdconf_get(void)
*eq = 0;
const char *k = line, *v = eq + 1;
if (!strcmp(k, "ui.shelf_layout")) { strncpy(g.shelf, v, sizeof g.shelf - 1); g.shelf[sizeof g.shelf - 1] = 0; }
else if (!strcmp(k, "ui.shelf_group")) { strncpy(g.shelf_group, v, sizeof g.shelf_group - 1); g.shelf_group[sizeof g.shelf_group - 1] = 0; }
else if (!strcmp(k, "rd.fs")) { int t = atoi(v); if (t >= 14 && t <= 40) g.fs = t; }
else if (!strcmp(k, "rd.ls")) { int t = atoi(v); if (t >= 100 && t <= 200) g.ls = t; }
else if (!strcmp(k, "rd.bg")) { strncpy(g.bg, v, sizeof g.bg - 1); g.bg[sizeof g.bg - 1] = 0; }
@@ -84,11 +86,14 @@ rdconf *rdconf_get(void)
}
/* 校验合法取值(越界回默认/回退),避免脏档破坏 UI */
if (strcmp(g.shelf, "grid") && strcmp(g.shelf, "list")) strcpy(g.shelf, "list");
if (strcmp(g.shelf_group, "folder") && strcmp(g.shelf_group, "format"))
strcpy(g.shelf_group, "format");
if (strcmp(g.bg, "black") && strcmp(g.bg, "white") &&
strcmp(g.bg, "sepia") && strcmp(g.bg, "auto")) strcpy(g.bg, "black");
if (strcmp(g.theme, "light") && strcmp(g.theme, "dark") &&
strcmp(g.theme, "auto")) strcpy(g.theme, "auto");
clamp_str(g.shelf, sizeof g.shelf);
clamp_str(g.shelf_group, sizeof g.shelf_group);
clamp_str(g.bg, sizeof g.bg);
clamp_str(g.theme, sizeof g.theme);
clamp_str(g.font, sizeof g.font);
@@ -105,6 +110,7 @@ int rdconf_persist(void)
FILE *f = fopen(path, "wb");
if (!f) return -5;
fprintf(f, "ui.shelf_layout=%s\n", c->shelf);
fprintf(f, "ui.shelf_group=%s\n", c->shelf_group);
fprintf(f, "rd.fs=%d\n", c->fs);
fprintf(f, "rd.ls=%d\n", c->ls);
fprintf(f, "rd.bg=%s\n", c->bg);