feat: M6.10–M6.19 批量收编 + M6.19 推卡验收
- M7 launcher 重写 5 期(虚拟化宫格/meow_theme 单一权威/横幅动画/自定义 PIN 键盘) - OOM 通用化(cachegov 上收 SDK)、自动切歌根治、meowpanel jv_free 泄漏修复、Hello 滚动卡顿修复 - ncm 歌词 UI / 媒体通知封面 / 封面分辨率 640 - 5 bug 修复:ncm 后台化 UI 叠层+点击穿透、再进 ncm 桌面叠层、播放页新旧 UI 叠层抢刷脏区(meow_ui_gfx 恢复边沿整帧重画)、PIN 亮屏亮度跳(keys.c meow_panel_on 按 settings_brightness_clamped 恢复)、通知中心封面显歌单封面(cover.c save_cover_raw 加 is_song + 命中块守卫) - 四 App 统一重链新 meow_ui.a 51caee4a;M6.19=0.8.19 固件 2d2331f2 推卡自刷验收全绿
This commit is contained in:
1 parent
c2ee7626a4
commit
3d70a3dd2c
176 files changed
+15507
-597
No files matched your search
@@ -1,9 +1,9 @@
|
||||
/* subpage.c — MeowOS launcher 独立子页面(WiFi/蓝牙)统一脚手架(M2.76)。
|
||||
/* subpage.c — MeowOS launcher 独立子页面(WiFi/蓝牙/锁屏 PIN)统一脚手架(M2.76)。
|
||||
*
|
||||
* 安卓风子页骨架:顶栏(标题 + 返回 + 右上开关)+ 分组列表(组标题/行/开关/动作)
|
||||
* + 滚动(跟手,方向沿用设置页 input.swipe_invert 语义)+ 左缘左滑返回 + 底部返回。
|
||||
* + 滚动 + 左缘左滑返回。
|
||||
*
|
||||
* 由页面(wifi_page.c / bt_page.c)通过 sub_page_t 提供:
|
||||
* 由页面(wifi_page.c / bt_page.c / lock_settings.c)通过 sub_page_t 提供:
|
||||
* - title 顶栏标题
|
||||
* - top_sw 顶栏开关(0=不显示;1=显示并回写当前值)
|
||||
* - top_sw_set 开关切换(写设置 + 生效 + 触发重扫)
|
||||
@@ -12,7 +12,18 @@
|
||||
* - detail 点普通行(如当前连接详情、网络/设备详情)
|
||||
* - live 1=驻留时周期性(约2s)重扫行(蓝牙附近扫描等动态数据)
|
||||
*
|
||||
* 与设置页同主题(s_ui_theme,MD3 语义色,明暗自动);局部刷新不整屏重绘;
|
||||
* ================================================================
|
||||
* M7.1a 渲染层迁移:脚手架手绘(顶栏 + 分组列表 + 跟手滚动 + 手绘 switch/chevron)
|
||||
* 改走 SDK 控件(单一 meow_theme 权威):
|
||||
* - 顶栏 → meow_topappbar(标题 + 返回箭头 + 底部分隔线);
|
||||
* - 顶部开关 → meow_switch(叠顶栏右缘,保留开/关视觉与命中);
|
||||
* - 分组列表 → meow_listview(virtualized set_vsource 固定 item 池 + section 段头
|
||||
* + right=SWITCH/ARROW 尾件 + 选中/按压态);
|
||||
* - 滚动 → meow_scroll(跟手 track 采样松手 fling + snap 到行边界)。
|
||||
* wifi/bt/lock_settings 的「数据 + 动作」逻辑(netmgr IPC / bluetoothctl / 设置契约)
|
||||
* 全部保留在 launcher 逻辑层,仅换渲染。旧手绘路径整体保留 #if 0 作回退位(M7 红线)。
|
||||
*
|
||||
* 与设置页同主题(s_ui_theme → SDK meow_theme 单一权威,MD3/MIUIx×明暗自动);
|
||||
* 模态弹窗交给 launcher 既有 s_dd_modal(点外关闭不穿透),本脚手架在回调返回后
|
||||
* 彻底排空本页 tfd + 重置触摸基线(复刻 run_settings_page 后置排空,防穿透)。
|
||||
*
|
||||
@@ -22,16 +33,28 @@
|
||||
#include "meow_launcher_internal.h"
|
||||
|
||||
|
||||
/* ---- 布局常量(顶栏/内容区;全屏内容区延用设置页 surface_variant 整屏底)---- */
|
||||
/* ---- 布局常量(顶栏/内容区;全屏内容区延用设置页 surface 整屏底)----
|
||||
* note:SUB_CONT_TOP 与旧版一致(96),顶栏底缘分隔线由 SDK topappbar 绘制(y=95)。 */
|
||||
#define SUB_TB_Y SB_BAR_H /* 28:顶栏顶缘(状态栏下) */
|
||||
#define SUB_TB_H 68 /* 顶栏高 28..96 */
|
||||
#define SUB_TB_BOT (SUB_TB_Y + SUB_TB_H) /* 96:顶栏底缘 / 分隔线 */
|
||||
#define SUB_CONT_TOP (SUB_TB_BOT + 6) /* 102:内容区顶缘 */
|
||||
#define SUB_TB_BOT (SUB_TB_Y + SUB_TB_H) /* 96:顶栏底缘 */
|
||||
#define SUB_CONT_TOP (SUB_TB_BOT) /* 96:内容区顶缘(topappbar 分隔线下) */
|
||||
#define SUB_FOOT_H 44 /* 底部版本信息带(右对齐) */
|
||||
#define SUB_ITEM_H 56 /* MD3 行高(双行富 item:主/副标题) */
|
||||
#define SUB_PAD_X 16 /* 水平内边距(顶开关右缘留白用) */
|
||||
#define SUB_SW_H 32 /* 顶开关高(meow_switch 固定 56×32) */
|
||||
|
||||
|
||||
#if 0 /* ================================================================
|
||||
* M7.1a 退役:子页旧手绘脚手架(顶栏 + 分组列表 + 跟手无惯性滚动 + 手绘
|
||||
* s_draw_switch/s_draw_chevron + 自算行前缀和 + 自算命中)。改走 SDK 控件
|
||||
* (meow_topappbar + meow_listview + meow_scroll),命中/布局/状态/滚动/主题
|
||||
* 全由 SDK 接管。本块保留作回退位(删除 #if 0 行并删下方「M7.1a SDK 路径」段
|
||||
* 即可恢复旧手绘)。以下全部内容与迁移前 subpage.c 逐字一致。
|
||||
* ================================================================ */
|
||||
#define SUB_ROW_H 58 /* 行高(对齐 SROW_H,便于触摸) */
|
||||
#define SUB_HDR_H 40 /* 组标题行高 */
|
||||
#define SUB_PAD_X 16 /* 水平内边距 */
|
||||
#define SUB_SW_W 48 /* 开关宽(s_draw_switch) */
|
||||
#define SUB_SW_H 28
|
||||
#define SUB_BTN_X 8 /* 底部返回按钮左缘 */
|
||||
#define SUB_BTN_W 120 /* 底部返回按钮宽 */
|
||||
|
||||
@@ -502,3 +525,510 @@ subdone:
|
||||
logmsg("subpage '%s' closed", p->title ? p->title : "");
|
||||
return 0;
|
||||
}
|
||||
#endif /* M7.1a 退役:旧手绘子页脚手架回退位 */
|
||||
|
||||
|
||||
/* ==================================================================
|
||||
* M7.1a 子页渲染层迁移(SDK 控件化):
|
||||
* - 顶栏 → meow_topappbar(标题 + 返回箭头 + 底部分隔线);
|
||||
* - 顶部开关 → meow_switch(叠顶栏右缘,保留开/关视觉 + 命中);
|
||||
* - 分组列表 → meow_listview(virtualized set_vsource 固定 item 池 + section 段头
|
||||
* + right=SWITCH/ARROW 尾件 + 选中/按压态,SDK 语义色);
|
||||
* - 滚动 → meow_scroll(跟手 meow_scroll_track 采样 + 松手 fling ease-out 惯性停;
|
||||
* 刻意不 set_snap——SDK snap 以 fling 起点为吸附目标会往回拉,见 sp_widgets_create 注)。
|
||||
* 控件 lazy 创建一次(owner=SUB_SENTINEL_ACT 哨兵),跨多次进入复用;meow_subpage_run()
|
||||
* 进入 push 哨兵、退出 pop(owner 闸门使控件命中生效)。数据/动作回调(rows/act/detail/
|
||||
* top_sw_*)仍由各子页提供,逻辑层不动,仅渲染层替换。
|
||||
* ================================================================== */
|
||||
#define SUB_SENTINEL_ACT 0x52 /* 子页哨兵 activity(不与 launcher 其它页冲突) */
|
||||
|
||||
static sub_page_t *g_sp; /* 当前运行子页(rows/act/detail/top_sw 回调入口) */
|
||||
static sub_row_t g_rows[SUB_ROWS_MAX]; /* 行缓冲:rows() 一次性填满,listview bind 只读 */
|
||||
static int g_nrows = 0; /* 当前行数(listview vsource count 实时读) */
|
||||
static int g_top_sw_en = 0; /* 本页是否显示顶开关 */
|
||||
static int g_top_on = 0; /* 顶开关当前值 */
|
||||
|
||||
static meow_widget *g_tb = NULL; /* topappbar */
|
||||
static meow_widget *g_sw = NULL; /* 顶开关(仅在有顶开关的页创建/使用) */
|
||||
static meow_widget *g_lv = NULL; /* listview */
|
||||
static meow_scroll *g_sc = NULL; /* 滚动物理 */
|
||||
static int g_sp_init = 0;
|
||||
|
||||
/* 列表视口矩形(内容区,去掉底部版本带) */
|
||||
static void sp_lv_rect(int *x, int *y, int *w, int *h)
|
||||
{
|
||||
if (x) *x = 0;
|
||||
if (y) *y = SUB_CONT_TOP;
|
||||
if (w) *w = fb_xres;
|
||||
if (h) { *h = fb_yres - SUB_CONT_TOP - SUB_FOOT_H; if (*h < 0) *h = 0; }
|
||||
}
|
||||
|
||||
/* ---- 行缓冲 → meow_lv_item(虚拟化 bind;每行轻量填充,不做 IO §5.5)---- */
|
||||
static int sp_lv_count(void *ctx) { (void)ctx; return g_nrows; }
|
||||
static void sp_lv_bind(int idx, meow_lv_item *out, void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
memset(out, 0, sizeof *out);
|
||||
out->icon_kind = MEOW_LIST_ICON_NONE;
|
||||
out->enabled = 1;
|
||||
if (idx < 0 || idx >= g_nrows) { out->title = ""; return; }
|
||||
const sub_row_t *r = &g_rows[idx];
|
||||
switch (r->kind) {
|
||||
case SUB_HDR: /* 段头占位行(非粘性):default renderer 特殊绘制 */
|
||||
out->section = 1; out->title = r->label ? r->label : "";
|
||||
out->right = MEOW_LIST_RIGHT_NONE; out->enabled = 0; break;
|
||||
case SUB_ROW: /* 普通信息行 */
|
||||
out->title = r->label ? r->label : "";
|
||||
out->subtitle = r->sub; out->right = MEOW_LIST_RIGHT_NONE; break;
|
||||
case SUB_SW: /* 开关行:右尾件 SWITCH */
|
||||
out->title = r->label ? r->label : "";
|
||||
out->subtitle = r->sub; out->right = MEOW_LIST_RIGHT_SWITCH; out->on = r->on; break;
|
||||
case SUB_ACT: /* 动作行:右尾件 ARROW */
|
||||
out->title = r->label ? r->label : "";
|
||||
out->subtitle = r->sub; out->right = MEOW_LIST_RIGHT_ARROW; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- meow_scroll 回调(包 listview)---- */
|
||||
static void sp_sc_set(void *ctx, int off) { (void)ctx; if (g_lv) meow_listview_set_scroll(g_lv, off); }
|
||||
static int sp_sc_max(void *ctx) { (void)ctx; return g_lv ? meow_listview_max_scroll(g_lv) : 0; }
|
||||
static int sp_sc_get(void *ctx) { (void)ctx; return g_lv ? meow_listview_scroll(g_lv) : 0; }
|
||||
|
||||
/* 列表区重绘(含背景 + listview),供 fling 每帧/滚动局部刷。ctx 为 meow_scroll 回调用。 */
|
||||
static void sp_redraw_region(void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
int lvx, lvy, lvw, lvh;
|
||||
sp_lv_rect(&lvx, &lvy, &lvw, &lvh);
|
||||
if (lvh <= 0) return;
|
||||
const meow_theme *mt = meow_theme_get();
|
||||
meow_ui_fill_rect(lvx, lvy, lvw, lvh, mt->surface); /* 内容底 surface */
|
||||
if (g_lv) meow_widget_draw(g_lv);
|
||||
meow_dirty_add(lvx, lvy, lvw, lvh);
|
||||
meow_ui_flush();
|
||||
}
|
||||
|
||||
/* 创建子页控件集(owner=SUB_SENTINEL_ACT;仅首进创建一次,跨页复用)。 */
|
||||
static void sp_widgets_create(void)
|
||||
{
|
||||
meow_ui_activity_push(SUB_SENTINEL_ACT);
|
||||
g_tb = meow_topappbar_create(0, SUB_TB_Y, fb_xres, SUB_TB_H, "");
|
||||
if (g_tb) meow_topappbar_set_back(g_tb, 1);
|
||||
int lvx, lvy, lvw, lvh;
|
||||
sp_lv_rect(&lvx, &lvy, &lvw, &lvh);
|
||||
g_lv = meow_listview_create(lvx, lvy, lvw, lvh, 0, NULL, NULL, MEOW_LIST_SEL_NONE);
|
||||
if (g_lv) {
|
||||
meow_listview_set_vsource(g_lv, sp_lv_count, sp_lv_bind, NULL);
|
||||
/* 双行富 item + 无左图标 + 右尾件(SWITCH/ARROW);行高 56 */
|
||||
meow_listview_set_item_renderer(g_lv, 2, 0, 1);
|
||||
meow_listview_set_item_h(g_lv, SUB_ITEM_H);
|
||||
}
|
||||
/* 注:刻意不 set_snap —— SDK meow_scroll 的 snap 以「fling 起点」为吸附目标,快速滑动时会
|
||||
* 从自然停点往回拉一整行(实测 697→336),UX 不佳;默认 ease-out 惯性停(无 snap)更顺滑。
|
||||
* 若后续 SDK 修正 snap 到「自然停点」,可恢复 meow_scroll_set_snap(g_sc, SUB_ITEM_H)。 */
|
||||
g_sc = meow_scroll_create(sp_sc_set, sp_sc_max, sp_sc_get, sp_redraw_region, NULL);
|
||||
meow_ui_activity_pop();
|
||||
g_sp_init = 1;
|
||||
}
|
||||
|
||||
/* 逐页配置:topappbar 标题 + 顶开关(按需创建/置态)+ listview 行数。 */
|
||||
static void sp_configure_page(const sub_page_t *p, int top_sw_en, int top_on)
|
||||
{
|
||||
if (p->title && g_tb) meow_topappbar_set_title(g_tb, p->title);
|
||||
g_top_sw_en = top_sw_en;
|
||||
g_top_on = top_on;
|
||||
if (top_sw_en) {
|
||||
if (!g_sw) {
|
||||
meow_ui_activity_push(SUB_SENTINEL_ACT); /* owner 钉哨兵(命中闸门) */
|
||||
int swx = fb_xres - SUB_PAD_X - 56; /* meow_switch 固定 56×32 */
|
||||
int swy = SUB_TB_Y + (SUB_TB_H - SUB_SW_H) / 2;
|
||||
g_sw = meow_switch_create(swx, swy, top_on);
|
||||
meow_ui_activity_pop();
|
||||
} else if (g_sw) {
|
||||
meow_switch_set(g_sw, top_on);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 整页绘制(进 back_buf;调用方 meow_dirty_full + flush 上屏)。 */
|
||||
static void sp_paint_page(void)
|
||||
{
|
||||
const meow_theme *mt = meow_theme_get();
|
||||
int W = fb_xres, H = fb_yres;
|
||||
meow_ui_fill_rect(0, 0, W, H, mt->surface); /* 全屏底 surface */
|
||||
draw_statusbar();
|
||||
if (g_tb) meow_widget_draw(g_tb); /* topappbar(含底部分隔线) */
|
||||
if (g_sw && g_top_sw_en) meow_widget_draw(g_sw); /* 顶开关(叠顶栏右缘) */
|
||||
int lvx, lvy, lvw, lvh;
|
||||
sp_lv_rect(&lvx, &lvy, &lvw, &lvh);
|
||||
meow_ui_fill_rect(lvx, lvy, lvw, lvh, mt->surface); /* 内容底 surface */
|
||||
if (g_lv) meow_widget_draw(g_lv); /* 分组列表 */
|
||||
/* 底部版本信息(右对齐 dim) */
|
||||
char ver[32];
|
||||
snprintf(ver, sizeof ver, "MeowOS v%s", g_meowos_version);
|
||||
ui_draw(W - 8 - ui_width(ver, 18), H - SUB_FOOT_H + 10, ver,
|
||||
s_ui_theme()->outline, 18);
|
||||
}
|
||||
|
||||
/* 顶部开关切换:写设置 + 生效 + 触发重扫 + 重填行。 */
|
||||
static void sp_top_sw_toggle(void)
|
||||
{
|
||||
if (!g_sp || !g_sp->top_sw_set) return;
|
||||
g_sp->top_sw_set(g_sp->ctx, !g_top_on);
|
||||
g_top_on = !g_top_on;
|
||||
if (g_sw) meow_switch_set(g_sw, g_top_on);
|
||||
if (g_sp->rows) {
|
||||
g_nrows = g_sp->rows(g_sp->ctx, g_rows, SUB_ROWS_MAX);
|
||||
if (g_nrows > SUB_ROWS_MAX) g_nrows = SUB_ROWS_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
/* 动作后重扫行(act/detail 已变更数据):重填行并 clamp 滚动。 */
|
||||
static void sp_refresh_rows(void)
|
||||
{
|
||||
if (g_sp && g_sp->rows) {
|
||||
g_nrows = g_sp->rows(g_sp->ctx, g_rows, SUB_ROWS_MAX);
|
||||
if (g_nrows > SUB_ROWS_MAX) g_nrows = SUB_ROWS_MAX;
|
||||
}
|
||||
if (g_lv) {
|
||||
int ms = meow_listview_max_scroll(g_lv);
|
||||
if (meow_listview_scroll(g_lv) > ms) meow_listview_set_scroll(g_lv, ms);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 运行子页(阻塞到返回;返回 0)---- */
|
||||
int meow_subpage_run(sub_page_t *p)
|
||||
{
|
||||
struct keypoll kp_power, kp_keys;
|
||||
kp_open(&kp_power, DEV_POWER); kp_open(&kp_keys, DEV_KEYS);
|
||||
struct kd_state kd_vold, kd_volu, kd_play, kd_pwr;
|
||||
memset(&kd_vold, 0, sizeof kd_vold); memset(&kd_volu, 0, sizeof kd_volu);
|
||||
memset(&kd_play, 0, sizeof kd_play); memset(&kd_pwr, 0, sizeof kd_pwr);
|
||||
int m_prev_vold = 0, m_prev_volu = 0, m_prev_play = 0, m_prev_pwr = 0;
|
||||
for (int w = 0; w < KEYBUF_WORDS; w++) {
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_VOLUMEDOWN % 32))) m_prev_vold = 1;
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_VOLUMEUP % 32))) m_prev_volu = 1;
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_PLAYPAUSE % 32))) m_prev_play = 1;
|
||||
if (kp_power.cur[w] & (1UL << (KEY_POWER % 32))) m_prev_pwr = 1;
|
||||
}
|
||||
int tfd = open(DEV_TOUCH, O_RDONLY | O_NONBLOCK);
|
||||
if (tfd >= 0) { unsigned char ev[16]; while (read(tfd, ev, sizeof ev) == 16) {} }
|
||||
unsigned long long touch_cooldown_until = now_ms() + 300;
|
||||
unsigned long long last_tick = now_ms();
|
||||
unsigned long long last_act = now_ms();
|
||||
unsigned long long last_live = now_ms();
|
||||
int after_modal = 0; /* 子页内模态关闭后:覆盖过状态栏,需整帧重绘还原 */
|
||||
|
||||
/* 触摸状态 */
|
||||
int td = 0, td_ok = 0, tdx = -1, tdy = -1, tlx = -1, tly = -1;
|
||||
int scroll_drag = 0, scroll_invert = 0, drag_last_y = 0;
|
||||
int wake_suppress = 0;
|
||||
unsigned long long pwr_hold_at = 0;
|
||||
int pwr_menu_state = 0, pwr_woke = 0, pwr_suppress_click = 0;
|
||||
|
||||
/* 顶栏开关初始值 */
|
||||
int top_on = 0, top_sw_en = 0;
|
||||
if (p->top_sw) top_sw_en = p->top_sw(p->ctx, &top_on);
|
||||
|
||||
/* 首填行 + lazy 建控件 + 配置 + 首绘 */
|
||||
g_sp = p;
|
||||
g_nrows = p->rows ? p->rows(p->ctx, g_rows, SUB_ROWS_MAX) : 0;
|
||||
if (g_nrows > SUB_ROWS_MAX) g_nrows = SUB_ROWS_MAX;
|
||||
if (!g_sp_init) sp_widgets_create();
|
||||
sp_configure_page(p, top_sw_en, top_on);
|
||||
|
||||
meow_ui_activity_push(SUB_SENTINEL_ACT); /* 控件 owner 闸门打开(hit 生效) */
|
||||
sp_paint_page();
|
||||
meow_dirty_full(); meow_ui_flush();
|
||||
|
||||
for (;;) {
|
||||
unsigned long long now = now_ms();
|
||||
if (sigterm_flag) break;
|
||||
int need_paint = 0;
|
||||
|
||||
/* ---- 自动息屏态:留在子页,等待任意输入唤醒,恢复后重绘(不丢上下文)---- */
|
||||
if (meow_auto_slept && !meow_screen_on) {
|
||||
kp_poll(&kp_power, NULL, NULL); kp_poll(&kp_keys, NULL, NULL);
|
||||
int wake = 0;
|
||||
for (int w = 0; w < KEYBUF_WORDS; w++) {
|
||||
if (kp_power.cur[w] & (1UL << (KEY_POWER % 32))) wake = 1;
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_VOLUMEDOWN % 32))) wake = 1;
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_VOLUMEUP % 32))) wake = 1;
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_PLAYPAUSE % 32))) wake = 1;
|
||||
}
|
||||
if (!wake && screen_off_mode == 1 && tfd >= 0) {
|
||||
struct pollfd spfd = { tfd, POLLIN, 0 };
|
||||
if (poll(&spfd, 1, 0) > 0) {
|
||||
unsigned char ev[16];
|
||||
while (read(tfd, ev, sizeof ev) == 16) {
|
||||
uint16_t type = *(uint16_t *)(ev + 8), code = *(uint16_t *)(ev + 10);
|
||||
int32_t val = *(int32_t *)(ev + 12);
|
||||
if (type == EV_KEY && code == BTN_TOUCH && val) wake = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wake) {
|
||||
meow_panel_on();
|
||||
meow_auto_slept = 0;
|
||||
wake_suppress = 1;
|
||||
last_act = now;
|
||||
memset(&kd_pwr, 0, sizeof kd_pwr); memset(&kd_vold, 0, sizeof kd_vold);
|
||||
memset(&kd_volu, 0, sizeof kd_volu); memset(&kd_play, 0, sizeof kd_play);
|
||||
kp_poll(&kp_power, NULL, NULL); kp_poll(&kp_keys, NULL, NULL);
|
||||
m_prev_pwr = kp_is_down(&kp_power, KEY_POWER);
|
||||
m_prev_vold = kp_is_down(&kp_keys, KEY_VOLUMEDOWN);
|
||||
m_prev_volu = kp_is_down(&kp_keys, KEY_VOLUMEUP);
|
||||
m_prev_play = kp_is_down(&kp_keys, KEY_PLAYPAUSE);
|
||||
touch_cooldown_until = now_ms() + 300;
|
||||
td = 0; td_ok = 0; scroll_drag = 0; drag_last_y = 0; tlx = tly = -1;
|
||||
after_modal = 1;
|
||||
sp_paint_page();
|
||||
meow_dirty_full(); meow_ui_flush();
|
||||
}
|
||||
usleep(POLL_MS * 1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ---- 按键(与旧版逐字一致:音量=系统音量/播放=媒体预留/电源=系统级语义)---- */
|
||||
kp_poll(&kp_power, NULL, NULL); kp_poll(&kp_keys, NULL, NULL);
|
||||
int vold = 0, volu = 0, play = 0, pwr = 0;
|
||||
for (int w = 0; w < KEYBUF_WORDS; w++) {
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_VOLUMEDOWN % 32))) vold = 1;
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_VOLUMEUP % 32))) volu = 1;
|
||||
if (kp_keys.cur[w] & (1UL << (KEY_PLAYPAUSE % 32))) play = 1;
|
||||
if (kp_power.cur[w] & (1UL << (KEY_POWER % 32))) pwr = 1;
|
||||
}
|
||||
(void)kd_tick(&kd_vold, vold); (void)kd_tick(&kd_volu, volu);
|
||||
(void)kd_tick(&kd_play, play); (void)kd_tick(&kd_pwr, pwr);
|
||||
vold = kd_vold.stable; volu = kd_volu.stable;
|
||||
play = kd_play.stable; pwr = kd_pwr.stable;
|
||||
if (wake_suppress) {
|
||||
if (!pwr && !vold && !volu && !play) wake_suppress = 0;
|
||||
} else {
|
||||
if (vold && !m_prev_vold) { settings_volume_adj(-settings_volume_step); need_paint = 1; }
|
||||
if (volu && !m_prev_volu) { settings_volume_adj(+settings_volume_step); need_paint = 1; }
|
||||
if (play && !m_prev_play) { logmsg("subpage: play key caught (media-reserved)"); last_act = now; }
|
||||
if (pwr && !m_prev_pwr) {
|
||||
pwr_hold_at = now; pwr_menu_state = 0;
|
||||
pwr_suppress_click = 0;
|
||||
last_act = now;
|
||||
if (meow_auto_slept && !meow_screen_on) pwr_woke = 1;
|
||||
}
|
||||
if (pwr && pwr_hold_at) {
|
||||
if (now - pwr_hold_at >= (unsigned long long)power_forceoff_ms && !pwr_menu_state) {
|
||||
if (sim_no_exec) { logmsg("subpage pm: [sim-no-exec] POWER HOLD -> force poweroff"); }
|
||||
else { logmsg("subpage pm: POWER HOLD -> force poweroff"); meow_power_action(POWER_SHUTDOWN); }
|
||||
} else if (now - pwr_hold_at >= (unsigned long long)power_longpress_menu_ms && !pwr_menu_state) {
|
||||
pwr_menu_state = 1;
|
||||
logmsg("subpage pm: POWER HOLD -> show power menu");
|
||||
show_power_menu();
|
||||
last_act = now_ms();
|
||||
pwr_hold_at = 0; pwr_menu_state = 0; pwr_woke = 0;
|
||||
pwr_suppress_click = 1;
|
||||
memset(&kd_pwr, 0, sizeof kd_pwr);
|
||||
memset(&kd_vold, 0, sizeof kd_vold);
|
||||
memset(&kd_volu, 0, sizeof kd_volu);
|
||||
memset(&kd_play, 0, sizeof kd_play);
|
||||
kp_poll(&kp_power, NULL, NULL); kp_poll(&kp_keys, NULL, NULL);
|
||||
m_prev_pwr = kp_is_down(&kp_power, KEY_POWER);
|
||||
m_prev_vold = kp_is_down(&kp_keys, KEY_VOLUMEDOWN);
|
||||
m_prev_volu = kp_is_down(&kp_keys, KEY_VOLUMEUP);
|
||||
m_prev_play = kp_is_down(&kp_keys, KEY_PLAYPAUSE);
|
||||
after_modal = 1;
|
||||
need_paint = 1;
|
||||
goto sub_keys_seeded;
|
||||
}
|
||||
}
|
||||
if (!pwr && m_prev_pwr) {
|
||||
if (pwr_suppress_click) {
|
||||
logmsg("subpage pm: power release after menu -> no toggle");
|
||||
} else if (pwr_hold_at && (now - pwr_hold_at < (unsigned long long)power_longpress_menu_ms) &&
|
||||
!pwr_menu_state && !pwr_woke) {
|
||||
logmsg("subpage pm: power single-click -> toggle panel");
|
||||
meow_toggle_panel();
|
||||
meow_auto_slept = 0;
|
||||
last_act = now_ms();
|
||||
need_paint = 1;
|
||||
} else if (pwr_woke) {
|
||||
logmsg("subpage pm: power release after auto wake -> no toggle");
|
||||
}
|
||||
pwr_hold_at = 0; pwr_menu_state = 0; pwr_woke = 0;
|
||||
pwr_suppress_click = 0;
|
||||
}
|
||||
}
|
||||
if (vol_ramp_dir != 0) {
|
||||
int held = (vol_ramp_dir > 0) ? volu : vold;
|
||||
(void)vol_ramp_tick(held);
|
||||
g_sys.vol = settings_volume_get();
|
||||
paint_sb_right();
|
||||
need_paint = 1;
|
||||
}
|
||||
m_prev_vold = vold; m_prev_volu = volu; m_prev_play = play; m_prev_pwr = pwr;
|
||||
sub_keys_seeded:
|
||||
;
|
||||
|
||||
/* ---- 触摸(SDK 控件命中:topappbar/顶开关/listview + meow_scroll 滚动)---- */
|
||||
if (tfd >= 0 && meow_screen_on) {
|
||||
struct pollfd pfd = { tfd, POLLIN, 0 };
|
||||
if (poll(&pfd, 1, 0) > 0) {
|
||||
unsigned char ev[16];
|
||||
while (read(tfd, ev, sizeof ev) == 16) {
|
||||
uint16_t type = *(uint16_t *)(ev + 8), code = *(uint16_t *)(ev + 10);
|
||||
int32_t val = *(int32_t *)(ev + 12);
|
||||
if (type == EV_ABS) {
|
||||
if (code == ABS_X || code == ABS_MT_POSITION_X) tlx = val;
|
||||
else if (code == ABS_Y || code == ABS_MT_POSITION_Y) tly = val;
|
||||
if (td && !td_ok && tlx >= 0 && tly >= 0) {
|
||||
tdx = tlx; tdy = tly; td_ok = 1;
|
||||
meow_input_touch_set(1, tdx, tdy, 0); /* 喂 SDK 输入态(按压态渲染) */
|
||||
drag_last_y = tdy;
|
||||
if (g_lv && meow_widget_hit(g_lv, tlx, tly)) /* 按压态即时反馈 */
|
||||
sp_redraw_region(NULL);
|
||||
}
|
||||
if (td_ok && !scroll_drag) {
|
||||
int ddy = tly - drag_last_y;
|
||||
if (ddy >= S_SCROLL_SLOP || ddy <= -S_SCROLL_SLOP) {
|
||||
scroll_drag = 1;
|
||||
meow_settings_get_bool("input.swipe_invert", &scroll_invert);
|
||||
meow_input_touch_set(0, 0, 0, 0); /* 滚动中不压行(清按压态) */
|
||||
drag_last_y = tly; /* 从此增量(跨 slop 无跳变,对齐旧版补偿) */
|
||||
}
|
||||
}
|
||||
if (scroll_drag && td_ok) {
|
||||
int dydt = tly - drag_last_y; /* 本次位移增量(跟手) */
|
||||
drag_last_y = tly;
|
||||
int scdy = scroll_invert ? dydt : -dydt;
|
||||
if (g_sc && scdy) meow_scroll_track(g_sc, scdy, now);
|
||||
sp_redraw_region(NULL); /* 列表区重绘(新 offset) */
|
||||
need_paint = 1;
|
||||
}
|
||||
} else if (type == EV_KEY && code == BTN_TOUCH) {
|
||||
if (val && !td) {
|
||||
if (now_ms() < touch_cooldown_until) { tlx = tly = -1; }
|
||||
else { td = 1; td_ok = 0; tlx = -1; tly = -1; scroll_drag = 0;
|
||||
meow_input_touch_set(0, 0, 0, 0); }
|
||||
} else if (!val && td) {
|
||||
td = 0;
|
||||
meow_input_touch_set(0, 0, 0, 0); /* 抬手:清 SDK 按压态 */
|
||||
if (scroll_drag) {
|
||||
scroll_drag = 0;
|
||||
if (g_sc) meow_scroll_fling(g_sc); /* 松手 fling(速度采样) */
|
||||
} else if (td_ok) {
|
||||
int dx = tlx - tdx, dyy = tly - tdy;
|
||||
/* 左缘左滑返回(全局手势语义) */
|
||||
if (meow_edge_back(tdx, dx, dyy)) {
|
||||
if (tfd >= 0) { unsigned char e[16]; while (read(tfd, e, sizeof e) == 16) {} }
|
||||
goto subdone;
|
||||
}
|
||||
int adx = dx < 0 ? -dx : dx, ady = dyy < 0 ? -dyy : dyy;
|
||||
if (adx < 60 && ady < 60) {
|
||||
int tx = tlx, ty = tly;
|
||||
/* 顶栏:返回箭头(topappbar hit)/ 顶开关(meow_switch hit) */
|
||||
int tb_hit = g_tb ? meow_topappbar_hit(g_tb, tx, ty) : -1;
|
||||
if (tb_hit == MEOW_TOPBAR_BACK) {
|
||||
if (tfd >= 0) { unsigned char e[16]; while (read(tfd, e, sizeof e) == 16) {} }
|
||||
goto subdone;
|
||||
}
|
||||
if (g_top_sw_en && g_sw && meow_widget_hit(g_sw, tx, ty)) {
|
||||
sp_top_sw_toggle();
|
||||
last_act = now;
|
||||
need_paint = 1;
|
||||
if (tfd >= 0) { unsigned char e[16]; while (read(tfd, e, sizeof e) == 16) {} }
|
||||
continue;
|
||||
}
|
||||
/* 列表行命中(SDK 命中:含滚动换算 + 越界/禁用行不响应) */
|
||||
int row_hit = g_lv ? meow_listview_hit(g_lv, tx, ty) : -1;
|
||||
if (row_hit >= 0) {
|
||||
sub_kind_t kind = g_rows[row_hit].kind;
|
||||
if (kind == SUB_SW || kind == SUB_ACT) {
|
||||
if (g_sp->act) g_sp->act(g_sp->ctx, row_hit, g_rows[row_hit].act);
|
||||
} else if (kind == SUB_ROW) {
|
||||
if (g_sp->detail) g_sp->detail(g_sp->ctx, row_hit, g_rows[row_hit].act);
|
||||
}
|
||||
/* 动作后重扫行 + clamp 滚动 */
|
||||
sp_refresh_rows();
|
||||
}
|
||||
/* 仅命中行(回调可能开模态)才做后置排空/触摸基线重置/整帧重绘
|
||||
* (对齐旧版 idx>=0 分支;空白区点按不重绘不排空,置 td_ok=0 即可)。 */
|
||||
if (row_hit >= 0) {
|
||||
if (tfd >= 0) {
|
||||
unsigned char e[16];
|
||||
while (read(tfd, e, sizeof e) == 16) {}
|
||||
usleep(40000);
|
||||
while (read(tfd, e, sizeof e) == 16) {}
|
||||
}
|
||||
td = 0; td_ok = 0; scroll_drag = 0;
|
||||
drag_last_y = 0;
|
||||
tdx = tdy = tlx = tly = -1;
|
||||
touch_cooldown_until = now_ms() + 300;
|
||||
memset(&kd_pwr, 0, sizeof kd_pwr);
|
||||
memset(&kd_vold, 0, sizeof kd_vold);
|
||||
memset(&kd_volu, 0, sizeof kd_volu);
|
||||
memset(&kd_play, 0, sizeof kd_play);
|
||||
kp_poll(&kp_power, NULL, NULL); kp_poll(&kp_keys, NULL, NULL);
|
||||
m_prev_pwr = kp_is_down(&kp_power, KEY_POWER);
|
||||
m_prev_vold = kp_is_down(&kp_keys, KEY_VOLUMEDOWN);
|
||||
m_prev_volu = kp_is_down(&kp_keys, KEY_VOLUMEUP);
|
||||
m_prev_play = kp_is_down(&kp_keys, KEY_PLAYPAUSE);
|
||||
after_modal = 1;
|
||||
need_paint = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
td_ok = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 周期性重扫(live 页:蓝牙附近扫描等驻留更新)---- */
|
||||
if (g_sp && g_sp->live && now - last_live >= 2000) {
|
||||
last_live = now;
|
||||
int new_n = g_sp->rows ? g_sp->rows(g_sp->ctx, g_rows, SUB_ROWS_MAX) : 0;
|
||||
if (new_n > SUB_ROWS_MAX) new_n = SUB_ROWS_MAX;
|
||||
if (new_n != g_nrows) {
|
||||
g_nrows = new_n;
|
||||
int ms = g_lv ? meow_listview_max_scroll(g_lv) : 0;
|
||||
if (g_lv && meow_listview_scroll(g_lv) > ms) meow_listview_set_scroll(g_lv, ms);
|
||||
last_act = now;
|
||||
need_paint = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 重绘(整帧/内容区局部;fling 由 meow_scroll redraw 回调自刷)---- */
|
||||
if (need_paint) {
|
||||
last_act = now;
|
||||
sp_paint_page();
|
||||
if (after_modal) { meow_dirty_full(); after_modal = 0; }
|
||||
else meow_dirty_add(0, SUB_TB_Y, fb_xres, fb_yres - SUB_TB_Y); /* 含顶栏(开关/返回/标题) */
|
||||
meow_ui_flush();
|
||||
}
|
||||
|
||||
/* ---- 自动息屏(空闲超时关屏,留在子页,等输入唤醒)---- */
|
||||
if (screen_off_timeout > 0 && meow_screen_on && !meow_auto_slept &&
|
||||
(unsigned long long)(now - last_act) >= (unsigned long long)screen_off_timeout * 1000) {
|
||||
meow_panel_off();
|
||||
meow_auto_slept = 1;
|
||||
wake_suppress = 1;
|
||||
logmsg("subpage: idle %ds -> auto screen-off (stay)", screen_off_timeout);
|
||||
}
|
||||
/* ~1s 状态栏时钟刷新 */
|
||||
if (now - last_tick >= 1000) {
|
||||
last_tick = now;
|
||||
draw_clock();
|
||||
fb_norm_buf0();
|
||||
meow_ui_flush();
|
||||
}
|
||||
/* M7.1a: 推进 fling/回弹/snap 动画(无动画零开销) */
|
||||
meow_anim_tick();
|
||||
usleep(POLL_MS * 1000);
|
||||
}
|
||||
subdone:
|
||||
meow_input_touch_set(0, 0, 0, 0); /* 防残留按压态 */
|
||||
meow_ui_activity_pop(); /* 关 owner 闸门(控件 owner 仍钉哨兵,复用) */
|
||||
if (tfd >= 0) close(tfd);
|
||||
kp_close(&kp_power); kp_close(&kp_keys);
|
||||
logmsg("subpage '%s' closed", p->title ? p->title : "");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user