feat: M6.40批 — 阅读器UI改版(书架list·grid+空态骨架+界面设置+App设置页+header·footer+背景黑默认) + 系统级音量翻页映射 + P1 MD3(select面板28/对话框按钮胶囊) + MeowPanel写端点护栏 + SDK公开仓·文档同步

- reader: app.c/shelf.c/reader.c 全套UI; 新增 reader_conf(reader.conf)/settings(App设置页)/reader_ipc(音量翻页IPC响应); app.json加volume_page
- launcher: keys.c meow_volpage_*门 + util.c app_id→fd映射(HELLO记fd/断开清) + app_launcher.c 前台三处接线(进入sink/按键路径volpage_key/离开clear) → 前台声明volume_page的App音量键→MSG_KEY_PAGEUP/PAGEDOWN翻页(非阅读器前台音量照旧)
- sdk: meow_select.c 底部面板28 + meow_ui_dialog.c 对话框按钮胶囊(h/2) + test_meow_ui_select.c修采样
- meowpanel: /api/net/policy·/api/power/policy 加防自锁+policy默认关两条护栏(panel.policy_enabled默认0)
- 文档: MEOW_APP_SDK.md §12.6 + meowpanel README端点表

0warning;宿主测试全过;二进制留批量批次未入库
This commit is contained in:
AskaEth committed 2026-09-04 18:13:18 +08:00
1 parent b364b6371a
commit 2826c1e905
27 files changed
+1704 -129

No files matched your search

+117
View File
@@ -0,0 +1,117 @@
/* app/reader_conf.c — 阅读器 App 私有配置实现(见 app/reader_conf.h)。 */
#include "reader_conf.h"
#include "meow_ui.h" /* meow_config_dir() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
/* 从 MEOW_DATA_DIR(<TF>/MeowData/<pkg>/data)剥掉尾 "/data",得到 <TF>/MeowData/<pkg>。 */
static void strip_data_suffix(const char *d, char *out, int outsz)
{
if (!d || !d[0]) { strncpy(out, "/tmp", (size_t)outsz - 1); out[outsz - 1] = 0; return; }
size_t n = strlen(d);
const char *suffix = "/data";
size_t sl = strlen(suffix);
size_t keep;
if (n >= sl && strcmp(d + n - sl, suffix) == 0) keep = n - sl;
else keep = n;
if (keep >= (size_t)outsz) keep = (size_t)outsz - 1;
memcpy(out, d, keep);
out[keep] = 0;
}
static void conf_path(char *out, int outsz)
{
const char *data = meow_config_dir();
char base[360];
strip_data_suffix(data ? data : "", base, sizeof base);
if (snprintf(out, (size_t)outsz, "%s/reader.conf", base) >= outsz) out[0] = 0;
/* mkdir -p base */
char tmp[400];
strncpy(tmp, base, sizeof tmp - 1); tmp[sizeof tmp - 1] = 0;
for (char *p = tmp + 1; *p; p++) {
if (*p == '/') { *p = 0; mkdir(tmp, 0755); *p = '/'; }
}
mkdir(tmp, 0755);
}
static void conf_defaults(rdconf *c)
{
c->fs = 20;
c->ls = 130;
strcpy(c->bg, "black"); /* B 定案:默认纯黑 */
strcpy(c->theme, "auto");
strcpy(c->shelf, "list"); /* A 定案:默认 list */
c->header = 1;
c->footer = 1;
c->font[0] = 0;
}
static void clamp_str(char *v, size_t sz)
{
v[sz - 1] = 0;
}
rdconf *rdconf_get(void)
{
static rdconf g;
static int loaded = 0;
if (loaded) return &g;
conf_defaults(&g);
char path[440];
conf_path(path, sizeof path);
FILE *f = path[0] ? fopen(path, "r") : NULL;
if (f) {
char line[512];
while (fgets(line, sizeof line, f)) {
line[strcspn(line, "\r\n")] = 0;
char *eq = strchr(line, '=');
if (!eq) continue;
*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, "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; }
else if (!strcmp(k, "rd.theme")) { strncpy(g.theme, v, sizeof g.theme - 1); g.theme[sizeof g.theme - 1] = 0; }
else if (!strcmp(k, "rd.header")) { g.header = atoi(v) ? 1 : 0; }
else if (!strcmp(k, "rd.footer")) { g.footer = atoi(v) ? 1 : 0; }
else if (!strcmp(k, "rd.font")) { strncpy(g.font, v, sizeof g.font - 1); g.font[sizeof g.font - 1] = 0; }
}
fclose(f);
}
/* 校验合法取值(越界回默认/回退),避免脏档破坏 UI */
if (strcmp(g.shelf, "grid") && strcmp(g.shelf, "list")) strcpy(g.shelf, "list");
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.bg, sizeof g.bg);
clamp_str(g.theme, sizeof g.theme);
clamp_str(g.font, sizeof g.font);
loaded = 1;
return &g;
}
int rdconf_persist(void)
{
rdconf *c = rdconf_get();
char path[440];
conf_path(path, sizeof path);
if (!path[0]) return -1;
FILE *f = fopen(path, "wb");
if (!f) return -5;
fprintf(f, "ui.shelf_layout=%s\n", c->shelf);
fprintf(f, "rd.fs=%d\n", c->fs);
fprintf(f, "rd.ls=%d\n", c->ls);
fprintf(f, "rd.bg=%s\n", c->bg);
fprintf(f, "rd.theme=%s\n", c->theme);
fprintf(f, "rd.header=%d\n", c->header);
fprintf(f, "rd.footer=%d\n", c->footer);
fprintf(f, "rd.font=%s\n", c->font);
fclose(f);
return 0;
}