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:
1 parent
b364b6371a
commit
2826c1e905
27 files changed
+1704
-129
No files matched your search
@@ -0,0 +1,250 @@
|
||||
/* app/settings.c — 全局设置页(C,书架顶栏「设置」入口 → 独立页 ACT_SETTINGS)。
|
||||
*
|
||||
* 配置项(MVP,见 READER_UI_DESIGN §4.3):默认字号/默认行距/默认背景(黑白米黄)/主题(亮暗跟随
|
||||
* 全局)/书架布局(list-grid)/页头条/页底条。全部存 App 私有 reader.conf(rdconf),不进系统
|
||||
* settings.conf。UI:meow_topappbar(返回+标题) + meow_listview 行(每行 label + 当前值尾部箭头,
|
||||
* 点行开 meow_dialog(SELECT) 单选;值即改即存)。
|
||||
*/
|
||||
#include "../reader_internal.h"
|
||||
#include "progress.h"
|
||||
#include "reader_conf.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SET_X 0
|
||||
#define SET_W 480
|
||||
#define SET_APPBAR_H 56
|
||||
|
||||
static meow_widget *g_appbar;
|
||||
static meow_widget *g_list;
|
||||
static int g_active;
|
||||
|
||||
/* 行项枚举(顺序 = 列表顺序) */
|
||||
enum { ITEM_FS = 0, ITEM_LS, ITEM_BG, ITEM_THEME, ITEM_SHELF, ITEM_HDR, ITEM_FTR, ITEM_COUNT };
|
||||
static const char *const g_labels[ITEM_COUNT] = {
|
||||
"默认字号", "默认行距", "默认背景", "主题", "书架布局", "页头条", "页底条"
|
||||
};
|
||||
static void settings_redraw(void);
|
||||
|
||||
static const char *bg_label(const rdconf *c)
|
||||
{
|
||||
if (!c) return "黑";
|
||||
if (!strcmp(c->bg, "white")) return "白";
|
||||
if (!strcmp(c->bg, "sepia")) return "米黄";
|
||||
if (!strcmp(c->bg, "auto")) return "自动";
|
||||
return "黑";
|
||||
}
|
||||
static const char *theme_label(const rdconf *c)
|
||||
{
|
||||
if (!c) return "跟随系统";
|
||||
if (!strcmp(c->theme, "light")) return "日";
|
||||
if (!strcmp(c->theme, "dark")) return "夜";
|
||||
return "跟随系统";
|
||||
}
|
||||
static const char *shelf_label(const rdconf *c)
|
||||
{
|
||||
if (!c) return "列表";
|
||||
return (!strcmp(c->shelf, "grid")) ? "宫格" : "列表";
|
||||
}
|
||||
|
||||
/* 当前行值(subtitle)。 */
|
||||
static void item_value(int item, char *out, int outsz)
|
||||
{
|
||||
const rdconf *c = rdconf_get();
|
||||
if (!c) { snprintf(out, (size_t)outsz, "-"); return; }
|
||||
switch (item) {
|
||||
case ITEM_FS: snprintf(out, (size_t)outsz, "%d", c->fs); break;
|
||||
case ITEM_LS: snprintf(out, (size_t)outsz, "%d", c->ls); break;
|
||||
case ITEM_BG: snprintf(out, (size_t)outsz, "%s", bg_label(c)); break;
|
||||
case ITEM_THEME: snprintf(out, (size_t)outsz, "%s", theme_label(c)); break;
|
||||
case ITEM_SHELF: snprintf(out, (size_t)outsz, "%s", shelf_label(c)); break;
|
||||
case ITEM_HDR: snprintf(out, (size_t)outsz, "%s", c->header ? "显示" : "隐藏"); break;
|
||||
case ITEM_FTR: snprintf(out, (size_t)outsz, "%s", c->footer ? "显示" : "隐藏"); break;
|
||||
default: snprintf(out, (size_t)outsz, "-"); break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- listview 行源(src2:每次绘制读最新 rdconf 值) ---- */
|
||||
static int settings_src(int idx, meow_list_item *out, void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
if (idx < 0 || idx >= ITEM_COUNT) return 0;
|
||||
static char valbuf[16];
|
||||
item_value(idx, valbuf, sizeof valbuf);
|
||||
out->icon_kind = MEOW_LIST_ICON_NONE;
|
||||
out->title = g_labels[idx];
|
||||
out->subtitle = valbuf;
|
||||
out->right = MEOW_LIST_RIGHT_ARROW;
|
||||
out->on = 0;
|
||||
out->enabled = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 由当前值求 SELECT 对话框的选中下标。 */
|
||||
static int idx_for(int item, const char *const *opts, int n, const rdconf *c)
|
||||
{
|
||||
if (item == ITEM_FS) { for (int i = 0; i < n; i++) if (atoi(opts[i]) == c->fs) return i; return 0; }
|
||||
if (item == ITEM_LS) { for (int i = 0; i < n; i++) if (atoi(opts[i]) == c->ls) return i; return 0; }
|
||||
if (item == ITEM_BG) {
|
||||
for (int i = 0; i < n; i++) if (!strcmp(opts[i], bg_label(c))) return i;
|
||||
return 0;
|
||||
}
|
||||
if (item == ITEM_THEME) {
|
||||
for (int i = 0; i < n; i++) if (!strcmp(opts[i], theme_label(c))) return i;
|
||||
return 0;
|
||||
}
|
||||
if (item == ITEM_SHELF) {
|
||||
for (int i = 0; i < n; i++) if (!strcmp(opts[i], shelf_label(c))) return i;
|
||||
return 0;
|
||||
}
|
||||
if (item == ITEM_HDR) return c->header ? 0 : 1;
|
||||
if (item == ITEM_FTR) return c->footer ? 0 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 选完整数数组项(字号/行距);写回 rdconf。 */
|
||||
static void apply_fs_ls(int item, const char *sel)
|
||||
{
|
||||
rdconf *c = rdconf_get();
|
||||
if (!c) return;
|
||||
int v = atoi(sel);
|
||||
if (item == ITEM_FS) { if (v >= 14 && v <= 40) c->fs = v; }
|
||||
else if (item == ITEM_LS) { if (v >= 100 && v <= 200) c->ls = v; }
|
||||
rdconf_persist();
|
||||
}
|
||||
|
||||
static void apply_choice(int item, int sel)
|
||||
{
|
||||
rdconf *c = rdconf_get();
|
||||
if (!c) return;
|
||||
switch (item) {
|
||||
case ITEM_BG:
|
||||
if (sel < 0) sel = 0;
|
||||
if (sel > 3) sel = 3;
|
||||
if (sel == 0) strcpy(c->bg, "black");
|
||||
else if (sel == 1) strcpy(c->bg, "white");
|
||||
else if (sel == 2) strcpy(c->bg, "sepia");
|
||||
else strcpy(c->bg, "auto");
|
||||
break;
|
||||
case ITEM_THEME:
|
||||
if (sel < 0) sel = 0;
|
||||
if (sel > 2) sel = 2;
|
||||
if (sel == 0) strcpy(c->theme, "auto");
|
||||
else if (sel == 1) strcpy(c->theme, "light");
|
||||
else strcpy(c->theme, "dark");
|
||||
break;
|
||||
case ITEM_SHELF:
|
||||
shelf_set_view(sel ? 1 : 0); /* 写 rdconf + 重建书架 */
|
||||
return;
|
||||
case ITEM_HDR: c->header = sel ? 0 : 1; break; /* 0 显示 1 隐藏 */
|
||||
case ITEM_FTR: c->footer = sel ? 0 : 1; break;
|
||||
default: return;
|
||||
}
|
||||
rdconf_persist();
|
||||
}
|
||||
|
||||
/* 打开一个 SELECT 对话框并应用。 */
|
||||
static void settings_open_choice(int item)
|
||||
{
|
||||
const rdconf *c = rdconf_get();
|
||||
if (!c) return;
|
||||
const char *title = g_labels[item];
|
||||
meow_dialog *d = meow_dialog_create(MEOW_DLG_SELECT, title);
|
||||
if (!d) return;
|
||||
const char *opts[16]; int n = 0; int cur = 0;
|
||||
static char numopts[16][8];
|
||||
if (item == ITEM_FS) {
|
||||
for (int v = 14; v <= 40; v += 2) { snprintf(numopts[n], sizeof numopts[n], "%d", v); opts[n] = numopts[n]; n++; }
|
||||
} else if (item == ITEM_LS) {
|
||||
for (int v = 100; v <= 200; v += 10) { snprintf(numopts[n], sizeof numopts[n], "%d", v); opts[n] = numopts[n]; n++; }
|
||||
} else if (item == ITEM_BG) {
|
||||
static const char *b[4] = { "黑", "白", "米黄", "自动" };
|
||||
for (int i = 0; i < 4; i++) opts[n++] = b[i];
|
||||
} else if (item == ITEM_THEME) {
|
||||
static const char *t[3] = { "跟随系统", "日", "夜" };
|
||||
for (int i = 0; i < 3; i++) opts[n++] = t[i];
|
||||
} else if (item == ITEM_SHELF) {
|
||||
static const char *s[2] = { "列表", "宫格" };
|
||||
for (int i = 0; i < 2; i++) opts[n++] = s[i];
|
||||
} else if (item == ITEM_HDR || item == ITEM_FTR) {
|
||||
static const char *h[2] = { "显示", "隐藏" };
|
||||
for (int i = 0; i < 2; i++) opts[n++] = h[i];
|
||||
}
|
||||
cur = idx_for(item, opts, n, c);
|
||||
meow_dialog_set_items(d, opts, n, cur);
|
||||
meow_dialog_show(d);
|
||||
int res = meow_dialog_result(d);
|
||||
meow_dialog_free(d);
|
||||
if (res < 0 || res >= n) return; /* 取消 */
|
||||
if (item == ITEM_FS || item == ITEM_LS) apply_fs_ls(item, opts[res]);
|
||||
else apply_choice(item, res);
|
||||
settings_redraw();
|
||||
}
|
||||
|
||||
static void settings_redraw(void)
|
||||
{
|
||||
const meow_theme *th = meow_theme_get();
|
||||
meow_ui_clear(th->bg);
|
||||
if (g_appbar) meow_widget_draw(g_appbar);
|
||||
if (g_list) meow_widget_draw(g_list);
|
||||
meow_ui_flush();
|
||||
}
|
||||
|
||||
/* view 生命周期 */
|
||||
static void settings_on_create(meow_view *v, void *ctx) { (void)v; (void)ctx; }
|
||||
static void settings_on_enter(meow_view *v, void *ctx)
|
||||
{
|
||||
(void)v; (void)ctx;
|
||||
g_active = 1;
|
||||
int sbh = meow_ui_statusbar_height();
|
||||
if (g_appbar) { meow_widget_free(g_appbar); g_appbar = NULL; }
|
||||
g_appbar = meow_topappbar_create(0, sbh, 480, SET_APPBAR_H, "阅读设置");
|
||||
if (g_appbar) meow_topappbar_set_back(g_appbar, 1);
|
||||
if (g_list) { meow_widget_free(g_list); g_list = NULL; }
|
||||
int ly = sbh + SET_APPBAR_H + 8;
|
||||
g_list = meow_listview_create(SET_X, ly, SET_W, 720 - ly, ITEM_COUNT,
|
||||
settings_src, NULL, MEOW_LIST_SEL_SINGLE);
|
||||
if (g_list) {
|
||||
meow_listview_set_container(g_list, 1);
|
||||
meow_listview_set_item_tier(g_list, 2);
|
||||
}
|
||||
settings_redraw();
|
||||
}
|
||||
static void settings_on_leave(meow_view *v, void *ctx) { (void)v; (void)ctx; g_active = 0; }
|
||||
static void settings_on_destroy(meow_view *v, void *ctx)
|
||||
{
|
||||
(void)v; (void)ctx;
|
||||
if (g_list) { meow_widget_free(g_list); g_list = NULL; }
|
||||
if (g_appbar) { meow_widget_free(g_appbar); g_appbar = NULL; }
|
||||
}
|
||||
|
||||
meow_view *settings_view_create(void)
|
||||
{
|
||||
static meow_view_hooks hooks = { settings_on_create, settings_on_enter, settings_on_leave,
|
||||
settings_on_destroy, NULL, NULL, NULL };
|
||||
return meow_view_create(ACT_SETTINGS, MEOW_VIEW_ACTIVITY, &hooks, NULL);
|
||||
}
|
||||
|
||||
int settings_is_active(void) { return g_active; }
|
||||
|
||||
void settings_reload(void) { if (g_active) settings_redraw(); }
|
||||
|
||||
int settings_on_tap(int x, int y)
|
||||
{
|
||||
/* 顶栏返回 */
|
||||
if (g_appbar) {
|
||||
int bi = meow_topappbar_hit(g_appbar, x, y);
|
||||
if (bi == MEOW_TOPBAR_BACK) { meow_view_page_pop(); return 1; }
|
||||
if (bi >= 0) return 1;
|
||||
}
|
||||
if (g_list) {
|
||||
int idx = meow_listview_tap_at(g_list, x, y);
|
||||
if (idx >= 0 && idx < ITEM_COUNT) {
|
||||
settings_open_choice(idx);
|
||||
return 1;
|
||||
}
|
||||
if (idx >= 0) { settings_redraw(); return 1; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user