- 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;宿主测试全过;二进制留批量批次未入库
118 lines
4.1 KiB
C
118 lines
4.1 KiB
C
/* 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;
|
||
}
|