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:
AskaEth committed 2026-09-03 12:16:01 +08:00
1 parent c2ee7626a4
commit 3d70a3dd2c
176 files changed
+15507 -597

No files matched your search

+157
View File
@@ -0,0 +1,157 @@
/*
* meow_select.c — §5.8.6 枚举/预设选择器(M7.2 设置页缺口 #4)。
*
* 封装 = BottomSheet(标题 + 选项列表)+ meow_listview(SINGLE) 单选列表。选项用 meow_listview
* 渲染(单选高亮 primaryContainer、可滚动 meow_scroll 惯性);外层模态复用 meow_ui_modal_*
* + meow_ui_modal_capture/restore(与 meow_dialog 同源:scrim 只叠一层/关闭无残影)。
* 阻塞式(meow_input_pop 轮询);打开前排空残留触摸;点面板外/左缘返回 = 取消;点选项 = 选中 +
* 关闭 + on_change 回调。选项数组定长(≤MEOW_SELECT_MAX_ITEMS)。
*/
#include "meow_ui.h"
#include "include/meow_select.h"
#include "meow_ui_internal.h" /* meow_input_pop/drain + meow_ui_modal_capture/restore */
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define MEOW_SELECT_ROW 48 /* 选项行高(px) */
struct meow_select {
char title[96];
char items[MEOW_SELECT_MAX_ITEMS][64];
int nitems;
int cur; /* 初始/当前选中项 */
int result; /* 选中下标 / -1=取消 */
int done;
int h; /* 面板高度(0=自动) */
meow_select_fn cb;
void *ctx;
};
/* meow_listview src2 数据源:填 title=options[idx](右尾件无;enabled=1)。 */
static int select_src2(int idx, meow_list_item *out, void *ctx)
{
meow_select *s = (meow_select *)ctx;
if (idx < 0 || idx >= s->nitems) return 0;
memset(out, 0, sizeof *out);
out->title = s->items[idx];
out->right = MEOW_LIST_RIGHT_NONE;
out->enabled = 1;
return 1;
}
meow_select *meow_select_create(const char *title, int cur)
{
meow_select *s = (meow_select *)calloc(1, sizeof *s);
if (!s) return NULL;
if (title) { strncpy(s->title, title, sizeof s->title - 1); s->title[sizeof s->title - 1] = '\0'; }
s->cur = cur; s->result = -1; s->done = 0;
return s;
}
int meow_select_add_item(meow_select *s, const char *label)
{
if (!s || s->nitems >= MEOW_SELECT_MAX_ITEMS) return -1;
if (label) { strncpy(s->items[s->nitems], label, 63); s->items[s->nitems][63] = '\0'; }
int idx = s->nitems;
s->nitems++;
return idx;
}
void meow_select_set_on_change(meow_select *s, meow_select_fn cb, void *ctx)
{ if (s) { s->cb = cb; s->ctx = ctx; } }
int meow_select_open(meow_select *s)
{
if (!s || s->nitems <= 0) return -1;
const meow_theme *th = meow_theme_get();
meow_input_start();
meow_input_drain(); /* 排空残留触摸(goodix 长尾) */
s->done = 0; s->result = -1;
int W = meow_ui_width(), H = meow_ui_height();
int sb = meow_ui_statusbar_height(); if (sb < 0) sb = 0;
int pad = 24;
int title_h = meow_ui_text_height(th->font_title);
int rowh = MEOW_SELECT_ROW;
int avail = H - sb - 20;
int min_h = pad + title_h + 12 + rowh + 20;
int want = (s->h > 0) ? s->h : min_h;
int est = pad + title_h + 12 + s->nitems * rowh + 20;
if (est > want) want = est;
if (want > avail) want = avail;
if (want < min_h) want = (min_h < avail) ? min_h : avail;
int ph = want, py = H - ph; /* 底部面板(顶部圆角) */
int list_y = py + pad + title_h + 12;
int list_h = ph - (list_y - py) - pad; /* 底部余量 */
if (list_h < rowh) list_h = rowh;
/* 选项列表(meow_listview[SINGLE]:单选高亮 + 可滚动)。open 时创建,close 释放(冷路径)。 */
meow_widget *lv = meow_listview_create(0, list_y, W, list_h, s->nitems,
select_src2, s, MEOW_LIST_SEL_SINGLE);
if (!lv) return -1;
meow_listview_set_item_h(lv, rowh);
/* 定位初始选中项在视口内。 */
int target = s->cur * rowh - (list_h - rowh) / 2;
int maxs = meow_listview_max_scroll(lv);
if (target < 0) target = 0;
if (target > maxs) target = maxs;
meow_listview_set_scroll(lv, target);
meow_listview_set_sel(lv, s->cur);
meow_scroll *sc = meow_scroll_wrap(lv, 1); /* 惯性滚动(fling/snap) */
/* §6.4 模态作用域 + 背景快照(关闭即还原,无残影/不叠黑)。 */
meow_ui_modal *m = meow_ui_modal_begin();
meow_ui_modal_capture();
/* 首次绘制:遮罩 + 底部面板(顶部圆角)+ 标题 + 选项列表。 */
meow_ui_fill_rect_alpha(0, 0, W, H, 0x000000, 150);
meow_gfx_fill_round(0, py, W, ph, th->radius_card, th->surfaceContainerHighest);
meow_ui_text(pad, py + pad, s->title, th->font_title, th->onSurface);
meow_widget_draw(lv);
meow_ui_flush();
int dy_start = 0, down = 0;
while (!s->done) {
meow_input_ev e;
while (meow_input_pop(&e)) {
meow_ui_activity_ping(); /* 模态期间交互也重置息屏计时 */
if (e.type == MEOW_EV_TOUCH_DOWN) { down = 1; dy_start = e.b; }
else if (e.type == MEOW_EV_TOUCH_MOVE) {
if (down && sc) {
meow_scroll_track(sc, e.b - dy_start, meow_ui_time_ms());
dy_start = e.b;
}
} else if (e.type == MEOW_EV_TAP) {
int x = e.a, y = e.b;
if (y < py) { s->done = 1; s->result = -1; break; } /* 点面板外 = 取消 */
int idx = meow_listview_tap_at(lv, x, y); /* 单选高亮 = 选中 */
if (idx >= 0) {
s->result = idx; s->cur = idx;
if (s->cb) s->cb(idx, s->ctx); /* 关闭即回调 */
s->done = 1;
}
/* 面板内但未命中项:保持打开(等下一次点击)。 */
} else if (e.type == MEOW_EV_SWIPE) {
if (e.a == MEOW_SWIPE_LEFT) { s->done = 1; s->result = -1; } /* 返回 = 取消 */
else if (sc) meow_scroll_fling(sc);
}
}
meow_anim_tick(); /* 推进 fling */
if (!s->done) usleep(16000);
}
meow_ui_modal_end(m);
meow_ui_modal_restore();
if (sc) meow_scroll_free(sc);
meow_widget_free(lv);
return s->result;
}
void meow_select_free(meow_select *s) { if (s) free(s); }
int meow_select_show(const char *title, const char *const *opts, int n, int cur)
{
if (!opts || n <= 0) return -1;
meow_select *s = meow_select_create(title, cur);
if (!s) return -1;
for (int i = 0; i < n && i < MEOW_SELECT_MAX_ITEMS; i++) meow_select_add_item(s, opts[i]);
int r = meow_select_open(s);
meow_select_free(s);
return r;
}