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

+89
View File
@@ -212,3 +212,92 @@ void load_config(void)
menu_bg, seq_len, seq_codes[0], seq_gap_ms);
}
/* =========================================================================
* 系统级音量键翻页门(READER_UI_DESIGN §E;用户 2026-09-04 拍板)。
*
* 语义:音量键是系统资源(默认调音量)。本门在「当前台 App 为其 app.json 声明
* volume_page 的应用(MVP:os.meow.reader)」时,把 VOL_UP/VOL_DOWN 转换成系统翻页
* 信号(MSG_KEY_PAGEUP/PAGEDOWN,meow_ipc.h)经 IPC 下发给该前台 App;其余情况一概
* 放行(return 0),音量基本行为/插孔消抖/音量反转等绝不破坏。
*
* 职责分离(关键,且最小侵入):
* - 本模块只提供「判定 + 门」:meow_volpage_app_allows() 读 app.json 声明;
* meow_volpage_key() 在「已武装 sink 且按下 VOL」时消费并发下发;
* - 武装(sink 注册)= 前台应用进入体积页声明 app 时调用 meow_volpage_sink()
* (应用存在连接后其 fd 生效);离开/退出时 meow_volpage_sink_clear()。
* 该接线落在「前台会话的按键路径」(app_launcher.c / meow_launcherd.c 主循环),
* 属主会话统一收编范围,此处不越界改动。
*
* 声明字段(app.json):`"volume_page": true`(或 1)。未来其它 App 可声明复用。
* ========================================================================= */
/* 前台翻页 sink(本模块私有;单写者=前台会话上下文,读=按键门)。 */
static char g_volpage_app[MEOW_APP_ID_MAX] = "";
static int g_volpage_fd = -1;
void meow_volpage_sink_clear(void); /* 前向声明(sink 内调用) */
/* 读 <MEOWAPPS>/<app_id>/app.json 是否声明 volume_page=true|1。1=声明;0=否/读不到。 */
int meow_volpage_app_allows(const char *app_id)
{
if (!app_id || !app_id[0]) return 0;
char path[320];
snprintf(path, sizeof path, "%s/%s/app.json", MEOWAPPS, app_id);
FILE *f = fopen(path, "r");
if (!f) return 0;
/* 轻量扫描:找 "volume_page" → 跳过空白 → true/1。app.json 为紧凑 JSON。 */
char buf[1024];
buf[0] = 0;
size_t rd = fread(buf, 1, sizeof buf - 1, f);
buf[rd] = 0;
fclose(f);
const char *p = buf;
while ((p = strstr(p, "volume_page")) != NULL) {
p += strlen("volume_page");
while (*p == ' ' || *p == '\t' || *p == ':' || *p == '"') p++;
if (strncmp(p, "true", 4) == 0) return 1;
if (*p == '1' && (p[1] < '0' || p[1] > '9')) return 1;
/* 未命中则继续找(防字段重复);跳过本段 */
while (*p && *p != ',' && *p != '}') p++;
}
return 0;
}
/* 武装/清除 sink。app_id 非空且 fd>=0 → 记录;否则清除。幂等(同 app_id+fd 不重复记日志,
* 供前台会话循环每圈安全重调,也兼容断线重连换 fd)。 */
void meow_volpage_sink(const char *app_id, int fd)
{
if (!app_id || !app_id[0] || fd < 0) { meow_volpage_sink_clear(); return; }
if (g_volpage_fd == fd && !strcmp(g_volpage_app, app_id)) return; /* 同 app_id+fd:幂等 */
snprintf(g_volpage_app, sizeof g_volpage_app, "%s", app_id);
g_volpage_fd = fd;
logmsg("volpage: sink armed app=%s fd=%d", g_volpage_app, g_volpage_fd);
}
void meow_volpage_sink_clear(void)
{
if (g_volpage_fd >= 0)
logmsg("volpage: sink cleared app=%s", g_volpage_app[0] ? g_volpage_app : "?");
g_volpage_app[0] = 0;
g_volpage_fd = -1;
}
int meow_volpage_armed(void) { return g_volpage_fd >= 0; }
/* 按键门:按下 VOL_UP/DOWN 且 sink 已武装 → 下发翻页信号并消费(返回 1)。
* 未武装 / 非 VOL / 抬起 → 返回 0(放行给音量路径)。 */
int meow_volpage_key(int code, int is_down)
{
if (!is_down) return 0; /* 只响应按下边沿 */
if (g_volpage_fd < 0) return 0; /* 未武装:音量照旧 */
if (code == KEY_VOLUMEUP) {
(void)meow_ipc_send_pub(g_volpage_fd, MSG_KEY_PAGEUP, 1, NULL, 0);
return 1;
}
if (code == KEY_VOLUMEDOWN) {
(void)meow_ipc_send_pub(g_volpage_fd, MSG_KEY_PAGEDOWN, 1, NULL, 0);
return 1;
}
return 0;
}