Compare commits
4
Commits
8971f6067b
...
18014eb2b9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18014eb2b9 | ||
|
|
76a22a6a91 | ||
|
|
e8218b8ae9 | ||
|
|
a82f3f9dfa |
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -96,7 +96,7 @@ static void ncp_media_btns_create(void)
|
||||
}
|
||||
|
||||
/* 绘制三控制按钮(prev/next 固定;play/pause 按会话状态只画其一——两钮同位,改画时新圆底盖掉旧)。
|
||||
* 每次刷新播放钮底色/图标(同 now_playing np_refresh_theme:跨主题切换跟手)。 */
|
||||
* 每次刷新播放钮底色/图标(同 now_playing np_theme_widgets:跨主题切换跟手)。 */
|
||||
static void ncp_draw_media_btns(const meow_media_session_t *s)
|
||||
{
|
||||
if (!g_ncp_media_btn_init) ncp_media_btns_create();
|
||||
|
||||
@@ -101,20 +101,34 @@ static void np_apply_lyric_colors(void)
|
||||
meow_lyric_view_set_colors(g_np_lyric, g_np_cc_valid ? &g_np_cc.lyr : NULL);
|
||||
}
|
||||
|
||||
/* 竖向双色渐变填充(无 GPU,逐行整数插值;封面主题背景用)。 */
|
||||
static void np_fill_gradient(int x, int y, int w, int h, uint32_t top, uint32_t bottom)
|
||||
/* 渐变插值(无 GPU,逐行整数;封面主题背景用)。返回 [y0, y0+h) 带内屏幕行 y 的颜色。 */
|
||||
static uint32_t np_grad_row(uint32_t top, uint32_t bottom, int y0, int h, int y)
|
||||
{
|
||||
if (w <= 0 || h <= 0) return;
|
||||
int t = (h <= 1) ? 0 : (y - y0) * 255 / (h - 1);
|
||||
if (t < 0) t = 0; else if (t > 255) t = 255;
|
||||
int tr = (top >> 16) & 255, tg = (top >> 8) & 255, tb = top & 255;
|
||||
int br = (bottom >> 16) & 255, bg = (bottom >> 8) & 255, bb = bottom & 255;
|
||||
int span = h - 1;
|
||||
for (int yy = 0; yy < h; yy++) {
|
||||
int t = span > 0 ? yy * 255 / span : 0;
|
||||
int r = tr + ((br - tr) * t + 128) / 255;
|
||||
int g = tg + ((bg - tg) * t + 128) / 255;
|
||||
int b = tb + ((bb - tb) * t + 128) / 255;
|
||||
fill_rect(x, y + yy, w, 1, ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b);
|
||||
}
|
||||
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
|
||||
}
|
||||
|
||||
/* 竖向双色渐变填充(封面主题背景用;整页/局部共用 np_grad_row,保证局部重绘与整页渐变无缝)。 */
|
||||
static void np_fill_gradient(int x, int y, int w, int h, uint32_t top, uint32_t bottom)
|
||||
{
|
||||
if (w <= 0 || h <= 0) return;
|
||||
for (int yy = 0; yy < h; yy++)
|
||||
fill_rect(x, y + yy, w, 1, np_grad_row(top, bottom, y, h, y + yy));
|
||||
}
|
||||
|
||||
/* 播放页当前主题 · 页背景行色:内容区(状态栏下)屏幕行 y 的背景色。
|
||||
* 取色有效 → 取色渐变(按整页 span 插值:局部重绘进度带逐行取色与整页渐变无缝衔接);
|
||||
* 取色无效 → 返回 0(调用方回退 meow_theme 面)。 */
|
||||
static uint32_t np_page_bg_row(int y)
|
||||
{
|
||||
if (!g_np_cc_valid) return 0;
|
||||
return np_grad_row(g_np_cc.bg_top, g_np_cc.bg_bottom, SB_BAR_H, fb_yres - SB_BAR_H, y);
|
||||
}
|
||||
|
||||
#if 0 /* ================================================================
|
||||
@@ -217,23 +231,43 @@ static void np_widgets_create(void)
|
||||
g_np_init = 1;
|
||||
}
|
||||
|
||||
/* 主题刷新:播放钮底色/图标随当前主题(明暗/风格切换后跟手);批5 封面取色时随 accent。 */
|
||||
static void np_refresh_theme(void)
|
||||
/* 播放页当前主题 → 控件修饰(整页与局部重绘共用同一次派生,避免两处取色逻辑漂移)。
|
||||
* 进度条 meow_progress:opts.bg=轨道、opts.fg=填充(批5b W_PROGRESS 新增支持);
|
||||
* 控制钮 meow_iconbtn:opts.bg=圆底、opts.fg=图标墨色。
|
||||
* 取色有效(g_np_cc_valid):进度条轨道=fg_dim/填充=accent,三钮圆底=accent、图标=accent_fg;
|
||||
* 取色无效:全部清 opts 回主题默认(进度条=surfaceVariant/primary、play/pause=primary/onPrimary、
|
||||
* prev/next=surfaceContainerLow/onSurface——与创建时一致,不回归)。
|
||||
* 每次绘制前调用(np_draw_page 播放分支 / np_repaint_progress),保证主题跟手。 */
|
||||
static void np_theme_widgets(void)
|
||||
{
|
||||
if (!g_np_init) return;
|
||||
const meow_theme *th = meow_theme_get();
|
||||
meow_widget_opts op; memset(&op, 0, sizeof op);
|
||||
op.bg = g_np_cc_valid ? g_np_cc.accent : th->primary;
|
||||
op.fg = g_np_cc_valid ? g_np_cc.accent_fg : th->onPrimary;
|
||||
if (g_np_cc_valid) {
|
||||
op.bg = g_np_cc.fg_dim; op.fg = g_np_cc.accent; /* 进度条:track=fg_dim / fill=accent */
|
||||
if (g_np_prog) meow_widget_set_opts(g_np_prog, &op);
|
||||
op.bg = g_np_cc.accent; op.fg = g_np_cc.accent_fg; /* 三钮:圆底=accent / 图标=accent_fg */
|
||||
if (g_np_prev) meow_widget_set_opts(g_np_prev, &op);
|
||||
if (g_np_play) meow_widget_set_opts(g_np_play, &op);
|
||||
if (g_np_pause) meow_widget_set_opts(g_np_pause, &op);
|
||||
if (g_np_next) meow_widget_set_opts(g_np_next, &op);
|
||||
return;
|
||||
}
|
||||
/* 取色无效 → 默认主题(回退):清 prog/prev/next 的 opts,play/pause 回主题 primary。 */
|
||||
memset(&op, 0, sizeof op);
|
||||
if (g_np_prog) meow_widget_set_opts(g_np_prog, &op);
|
||||
if (g_np_prev) meow_widget_set_opts(g_np_prev, &op);
|
||||
if (g_np_next) meow_widget_set_opts(g_np_next, &op);
|
||||
if (g_np_play || g_np_pause) {
|
||||
op.bg = th->primary; op.fg = th->onPrimary; /* 主播放钮:强调动作 */
|
||||
if (g_np_play) meow_widget_set_opts(g_np_play, &op);
|
||||
if (g_np_pause) meow_widget_set_opts(g_np_pause, &op);
|
||||
}
|
||||
}
|
||||
|
||||
/* 绘制播放控制三钮(prev/next 固定;play/pause 按会话状态只画其一——两钮同位,改画时
|
||||
* 上一帧残留被新画圆底盖掉)。 */
|
||||
* 上一帧残留被新画圆底盖掉)。控件配色在调用前由 np_theme_widgets 统一挂载取色主题。 */
|
||||
static void np_draw_ctl(const meow_media_session_t *s)
|
||||
{
|
||||
np_refresh_theme();
|
||||
if (g_np_prev) { meow_widget_set_selected(g_np_prev, 0); meow_widget_draw(g_np_prev); }
|
||||
if (g_np_next) { meow_widget_set_selected(g_np_next, 0); meow_widget_draw(g_np_next); }
|
||||
int playing = (s && s->state == MEOW_MEDIA_PLAYING);
|
||||
@@ -379,6 +413,8 @@ static void np_draw_page(int redraw_sb)
|
||||
np_center_text(NP_ARTIST_Y, s->artist, 18, g_np_cc_valid ? g_np_cc.fg_dim : th->on_surface_variant, W - 60);
|
||||
if (s->album[0])
|
||||
np_center_text(NP_ALBUM_Y, s->album, 16, g_np_cc_valid ? g_np_cc.fg_dim : th->on_surface_variant, W - 80);
|
||||
/* 批5b:控件随播放页当前主题(进度条轨道/填充 + 三钮)——整页与局部重绘共用同一次派生。 */
|
||||
np_theme_widgets();
|
||||
/* 进度(SDK meow_progress) */
|
||||
uint32_t pos = meow_media_display_pos(s);
|
||||
np_draw_progress(s, pos, th);
|
||||
@@ -390,15 +426,24 @@ static void np_draw_page(int redraw_sb)
|
||||
if (redraw_sb) draw_statusbar();
|
||||
}
|
||||
|
||||
/* 仅重绘进度带 + 按钮(元数据/源变化时整页;纯进度变化时局部)。 */
|
||||
/* 仅重绘进度带 + 按钮(元数据/源变化时整页;纯进度变化时局部)。
|
||||
* 批5b:局部重绘也走播放页当前主题——进度带/按钮带底色用取色渐变(np_page_bg_row 与整页同 span
|
||||
* 无缝衔接),进度条/三钮经 np_theme_widgets 挂取色色;无取色回退 meow_theme 面/默认控件色。 */
|
||||
static void np_repaint_progress(void)
|
||||
{
|
||||
const meow_ui_theme_t *th = s_ui_theme();
|
||||
const meow_media_session_t *s = meow_media_current();
|
||||
if (!s || s->state == MEOW_MEDIA_STOPPED) return;
|
||||
np_cover_theme_update(); /* 取色当前主题(幂等,封面路径未变不重取) */
|
||||
uint32_t pos = meow_media_display_pos(s);
|
||||
/* 清进度带 + 控制带,再重绘(只脏这两带,不整屏)。 */
|
||||
/* 清进度带 + 控制带,再重绘(只脏这两带,不整屏);底色随取色渐变或主题面。 */
|
||||
if (g_np_cc_valid) {
|
||||
for (int yy = NP_TIME_Y; yy < NP_BTN_Y + NP_PLAY_R; yy++)
|
||||
fill_rect(0, yy, fb_xres, 1, np_page_bg_row(yy));
|
||||
} else {
|
||||
fill_rect(0, NP_TIME_Y, fb_xres, NP_BTN_Y + NP_PLAY_R - NP_TIME_Y, th->surface);
|
||||
}
|
||||
np_theme_widgets(); /* 进度条/按钮随取色主题(或回退默认) */
|
||||
np_draw_progress(s, pos, th);
|
||||
np_draw_ctl(s);
|
||||
meow_dirty_add(0, NP_TIME_Y, fb_xres, NP_BTN_Y + NP_PLAY_R - NP_TIME_Y);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "meow_ui_internal.h" /* meow_ui_back_buf/pitch/bpp */
|
||||
#include "np_gesture.h" /* 批4:双页方向感知手势决策(纯逻辑,宿主可单测) */
|
||||
#include "meow_lyric_view.h" /* 批2:歌词页控件(批4接入,数据批3 meow_media_lyric_*) */
|
||||
#include "meow_img_color.h" /* 批5b:封面取色主题派生(局部重绘进度条/按钮带取色用例) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -59,6 +60,8 @@ static void rd_px(int x, int y, unsigned short *p)
|
||||
else *p = (unsigned short)(*(unsigned int *)(bb + (size_t)y * line + (size_t)x * 4) >> 16);
|
||||
}
|
||||
static unsigned short px565(int x, int y) { unsigned short p; rd_px(x, y, &p); return p; }
|
||||
static unsigned short rgb565(uint32_t c)
|
||||
{ return (unsigned short)(((c >> 8) & 0xF800) | ((c >> 5) & 0x07E0) | ((c >> 3) & 0x001F)); }
|
||||
static int region_nonbg(int x, int y, int w, int h, uint32_t bg)
|
||||
{
|
||||
unsigned short bg565 = ((bg >> 8) & 0xF800) | ((bg >> 5) & 0x07E0) | ((bg >> 3) & 0x001F);
|
||||
@@ -179,6 +182,103 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* ============ R1 批5b:局部重绘取色——进度条 fill=accent/track=fg_dim + 默认回退 ============
|
||||
* 镜像 np_theme_widgets(取色有效→进度条 opts.bg=fg_dim/opts.fg=accent)+ np_draw_progress。
|
||||
* 用「直接 fill_rect 参考像素」对比,绕开 565 精度差异(同一渲染器同色 → 同 565)。 */
|
||||
printf("R1 progress cover-theme fill/track + default fallback\n");
|
||||
meow_ui_set_style(MEOW_STYLE_MD3);
|
||||
meow_theme_set_mode(MEOW_THEME_DARK);
|
||||
th = meow_theme_get();
|
||||
meow_img_color_theme cc; memset(&cc, 0, sizeof cc);
|
||||
meow_img_color_derive(0xE53935u, 0x1E88E5u, th, &cc); /* 红/蓝两色 → 派生取色主题 */
|
||||
|
||||
/* 覆盖取色:进度条 fill=accent / track=fg_dim */
|
||||
{
|
||||
meow_widget_opts op; memset(&op, 0, sizeof op);
|
||||
op.bg = cc.fg_dim; op.fg = cc.accent;
|
||||
meow_widget_set_opts(prog, &op);
|
||||
meow_ui_clear(0);
|
||||
meow_ui_fill_rect(NP_PROG_X, NP_PROG_Y, 5, 6, cc.accent); /* fill 参考 */
|
||||
unsigned short ref_fill = px565(NP_PROG_X + 2, NP_PROG_Y + 3);
|
||||
meow_ui_clear(0);
|
||||
meow_ui_fill_rect(NP_PROG_X + NP_PROG_W - 4, NP_PROG_Y, 3, 6, cc.fg_dim); /* track 参考 */
|
||||
unsigned short ref_track = px565(NP_PROG_X + NP_PROG_W - 3, NP_PROG_Y + 3);
|
||||
meow_ui_clear(0);
|
||||
meow_progress_set(prog, 50);
|
||||
meow_widget_draw(prog);
|
||||
int fill_x = NP_PROG_X + NP_PROG_W / 4; /* 50% 填充区内 */
|
||||
int track_x = NP_PROG_X + NP_PROG_W - 4; /* 尾部轨道区 */
|
||||
CHECK(px565(fill_x, NP_PROG_Y + 3) == ref_fill, "cover: progress fill == accent");
|
||||
CHECK(px565(track_x, NP_PROG_Y + 3) == ref_track, "cover: progress track == fg_dim");
|
||||
|
||||
/* 默认回退:清 opts → 回到主题 primary/surfaceVariant(无取色回退默认) */
|
||||
memset(&op, 0, sizeof op);
|
||||
meow_widget_set_opts(prog, &op);
|
||||
meow_ui_clear(0);
|
||||
meow_ui_fill_rect(NP_PROG_X, NP_PROG_Y, 5, 6, th->primary);
|
||||
unsigned short ref_pri = px565(NP_PROG_X + 2, NP_PROG_Y + 3);
|
||||
meow_ui_clear(0);
|
||||
meow_progress_set(prog, 50);
|
||||
meow_widget_draw(prog);
|
||||
CHECK(px565(fill_x, NP_PROG_Y + 3) == ref_pri, "default: progress fill == theme primary");
|
||||
CHECK(px565(fill_x, NP_PROG_Y + 3) != ref_fill, "default vs cover fill differ");
|
||||
}
|
||||
|
||||
/* ============ R2 批5b:进度/按钮带底色随取色渐变(非默认 surface) ============
|
||||
* 镜像 np_repaint_progress 的带底色分支(np_page_bg_row 按整页 span 插值)。
|
||||
* 旧 bug:本地重绘用 th->surface 清带 → 带内被刷成默认色;现应取色渐变且 != surface。 */
|
||||
printf("R2 band background uses cover gradient (not default surface)\n");
|
||||
{
|
||||
#define NP_SB_H 28
|
||||
int H = 720;
|
||||
meow_ui_clear(0);
|
||||
for (int yy = NP_TIME_Y; yy < NP_BTN_Y + NP_PLAY_R; yy++) {
|
||||
int t = (H - NP_SB_H <= 1) ? 0 : (yy - NP_SB_H) * 255 / (H - NP_SB_H - 1);
|
||||
if (t < 0) t = 0; else if (t > 255) t = 255;
|
||||
int tr = (cc.bg_top >> 16) & 255, tg = (cc.bg_top >> 8) & 255, tb = cc.bg_top & 255;
|
||||
int br = (cc.bg_bottom >> 16) & 255, bg = (cc.bg_bottom >> 8) & 255, bb = cc.bg_bottom & 255;
|
||||
int r = tr + ((br - tr) * t + 128) / 255;
|
||||
int g = tg + ((bg - tg) * t + 128) / 255;
|
||||
int b = tb + ((bb - tb) * t + 128) / 255;
|
||||
meow_ui_fill_rect(0, yy, 480, 1, ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b);
|
||||
}
|
||||
unsigned short bandpx = px565(10, NP_TIME_Y + 55);
|
||||
CHECK(bandpx != rgb565(th->surface), "cover: band bg != default surface");
|
||||
CHECK(bandpx != 0, "cover: band bg rendered");
|
||||
}
|
||||
|
||||
/* ============ R3 批5b:控制三钮(含 prev/next)随取色 accent + 默认回退 ============
|
||||
* 镜像 np_theme_widgets:取色有效→四钮 opts.bg=accent/opts.fg=accent_fg(prev/next 不再默认底色)。 */
|
||||
printf("R3 control buttons follow cover accent\n");
|
||||
{
|
||||
meow_widget_opts op; memset(&op, 0, sizeof op);
|
||||
op.bg = cc.accent; op.fg = cc.accent_fg;
|
||||
meow_widget_set_opts(prev, &op);
|
||||
meow_widget_set_opts(next, &op);
|
||||
meow_widget_set_opts(play, &op);
|
||||
meow_widget_set_opts(pause, &op);
|
||||
meow_ui_clear(0);
|
||||
meow_ui_fill_rect(NP_PREV_CX - 2, NP_BTN_Y - 18, 4, 2, cc.accent); /* accent 参考(圆底上方、图标外) */
|
||||
unsigned short ref_acct = px565(NP_PREV_CX, NP_BTN_Y - 17);
|
||||
meow_ui_clear(0);
|
||||
meow_widget_draw(prev); /* r=22,cy-17 在圆内且高于图标(cy-13) */
|
||||
CHECK(px565(NP_PREV_CX, NP_BTN_Y - 17) == ref_acct, "cover: prev bg == accent");
|
||||
meow_ui_clear(0);
|
||||
meow_widget_draw(play); /* r=30,cy-26 在圆内且高于图标(cy-18) */
|
||||
CHECK(px565(NP_PLAY_CX, NP_BTN_Y - 26) == ref_acct, "cover: play bg == accent");
|
||||
|
||||
/* 默认回退:清 prev/next opts → 回 surfaceContainerLow(无取色不回归旧形态) */
|
||||
memset(&op, 0, sizeof op);
|
||||
meow_widget_set_opts(prev, &op);
|
||||
meow_widget_set_opts(next, &op);
|
||||
meow_ui_clear(0);
|
||||
meow_ui_fill_rect(NP_PREV_CX - 2, NP_BTN_Y - 18, 4, 2, th->surfaceContainerLow);
|
||||
unsigned short ref_def = px565(NP_PREV_CX, NP_BTN_Y - 17);
|
||||
meow_ui_clear(0);
|
||||
meow_widget_draw(prev);
|
||||
CHECK(px565(NP_PREV_CX, NP_BTN_Y - 17) == ref_def, "default: prev bg == surfaceContainerLow");
|
||||
}
|
||||
|
||||
/* ============ G5 双页手势方向感知(np_gesture.h,纯逻辑) ============ */
|
||||
printf("G5 dual-page direction-aware gestures\n");
|
||||
/* 播放页:右→左滑 → 进歌词页 */
|
||||
|
||||
Binary file not shown.
@@ -1133,10 +1133,15 @@ static void audio_fill(sbuf_t *s)
|
||||
if (n <= 0 || type != MSG_AUDIO_STATE) { sA(s, "{\"available\":false}"); return; }
|
||||
buf[n] = 0;
|
||||
const char *txt = (const char *)buf;
|
||||
char app[MEOW_APP_ID_MAX + 8], fmt[32], rmode[16];
|
||||
char app[MEOW_APP_ID_MAX + 8], fmt[32], rmode[16], target[16], volctl[16], codec[32];
|
||||
audio_kv(txt, "app", app, sizeof app);
|
||||
audio_kv(txt, "fmt", fmt, sizeof fmt);
|
||||
audio_kv(txt, "route_mode", rmode, sizeof rmode);
|
||||
/* 输出目标/音量控制/蓝牙编解码器(M6.32 面板透传:audiod 已发 target/volctl/codec,
|
||||
* 前端蓝牙卡据此点亮「输出目标 DAC|蓝牙 / 音量控制 avrcp|dac / 编解码器」)。缺失时前端优雅降级「—」。 */
|
||||
audio_kv(txt, "target", target, sizeof target);
|
||||
audio_kv(txt, "volctl", volctl, sizeof volctl);
|
||||
audio_kv(txt, "codec", codec, sizeof codec);
|
||||
sA(s, "{\"available\":true,\"active\":%lld,\"app\":", audio_kv_ll(txt, "active", 0));
|
||||
sA_str(s, app);
|
||||
sA(s, ",\"sid\":%lld,\"rate\":%lld,\"ch\":%lld,\"fmt\":",
|
||||
@@ -1148,6 +1153,12 @@ static void audio_fill(sbuf_t *s)
|
||||
sA_str(s, rmode);
|
||||
sA(s, ",\"port\":%lld,\"vol\":%lld",
|
||||
audio_kv_ll(txt, "port", -1), audio_kv_ll(txt, "vol", -1));
|
||||
sA(s, ",\"target\":");
|
||||
sA_str(s, target);
|
||||
sA(s, ",\"volctl\":");
|
||||
sA_str(s, volctl);
|
||||
sA(s, ",\"codec\":");
|
||||
sA_str(s, codec);
|
||||
/* 电平监控(261):rms/peak deci-dB(-990=-inf),lvlseq=快照代际;透传时别漏(ABI 追加键)。 */
|
||||
sA(s, ",\"rms\":%lld,\"peak\":%lld,\"lvlseq\":%lld,\"vol_max\":%d}",
|
||||
audio_kv_ll(txt, "rms", -990), audio_kv_ll(txt, "peak", -990), audio_kv_ll(txt, "lvlseq", 0), audio_vol_max());
|
||||
|
||||
@@ -133,6 +133,11 @@ void appstate_load_settings(void)
|
||||
if (g_st.player_bg_mode != NCM_BG_DEFAULT && g_st.player_bg_mode != NCM_BG_POWER_SAVE)
|
||||
g_st.player_bg_mode = NCM_BG_DEFAULT;
|
||||
|
||||
/* §NEW 播放模式三态:默认列表循环;越界回落列表循环 */
|
||||
g_st.play_mode = meow_config_int("ncm.play_mode", NCM_MODE_LISTLOOP);
|
||||
if (g_st.play_mode < NCM_MODE_SHUFFLE || g_st.play_mode >= NCM_MODE_COUNT)
|
||||
g_st.play_mode = NCM_MODE_LISTLOOP;
|
||||
|
||||
ncm_cache_set_limit_gb(&g_st.ctx.cache, g_st.cache_limit_gb);
|
||||
g_st.ctx.default_level = g_st.level;
|
||||
}
|
||||
@@ -146,6 +151,8 @@ void appstate_save_settings(void)
|
||||
meow_config_set("ncm.level", b);
|
||||
snprintf(b, sizeof b, "%d", g_st.player_bg_mode);
|
||||
meow_config_set("ncm.player_bg_mode", b);
|
||||
snprintf(b, sizeof b, "%d", g_st.play_mode);
|
||||
meow_config_set("ncm.play_mode", b);
|
||||
ncm_cache_set_limit_gb(&g_st.ctx.cache, g_st.cache_limit_gb);
|
||||
g_st.ctx.default_level = g_st.level;
|
||||
/* 手动调低上限时立即按 LRU 淘汰(超上限删最旧);未超限则为无操作 */
|
||||
@@ -764,6 +771,15 @@ void autoplay_maybe(void)
|
||||
void appstate_set_queue(int src) { g_st.queue_src = src; }
|
||||
int appstate_get_queue(void) { return g_st.queue_src; }
|
||||
|
||||
/* §NEW:设播放模式并落盘(「退出后记住模式」)。仅在 UI 线程(play 模式三态按钮点击)调用;
|
||||
* play 线程读的是 g_play.play_mode(player_manager_set_play_mode 已同步运行时态)。 */
|
||||
void appstate_apply_play_mode(int m)
|
||||
{
|
||||
if (m < NCM_MODE_SHUFFLE || m >= NCM_MODE_COUNT) return;
|
||||
g_st.play_mode = m;
|
||||
appstate_save_settings();
|
||||
}
|
||||
|
||||
int appstate_queue_count(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
@@ -66,6 +66,17 @@ enum {
|
||||
#define APP_OP_W 48 /* 行右侧操作区触达宽 */
|
||||
#define APP_FOOTER_H 26
|
||||
|
||||
/* 圆角卡列表项外边距(item margin/gap):相邻卡片间可见空隙 px。SDK listview 行距(=APP_ROW_H)
|
||||
* 不变——卡片在其行高内上下对称内缩 NCM_ROW_GAP/2,故文本(SDK 按 APP_ROW_H 垂直居中)仍落卡中心;
|
||||
* 相邻卡顶间距恒=APP_ROW_H=卡高+NCM_ROW_GAP。要求偶数,保证上下对称。 */
|
||||
#define NCM_ROW_GAP 8
|
||||
/* 第 idx 行(行高 item,滚动 off,列表顶 list_y)的圆角卡:顶 y 与高 h。 */
|
||||
static inline int ncm_row_card_y(int item, int idx, int off, int list_y)
|
||||
{
|
||||
return list_y + (idx * item - off) + NCM_ROW_GAP / 2;
|
||||
}
|
||||
static inline int ncm_row_card_h(int item) { return item - NCM_ROW_GAP; }
|
||||
|
||||
/* ---- 播放页(§22 重做:封面页/歌词页双页,NCM_CACHE_DESIGN §6)----
|
||||
* 沉浸底恒 NCM_PLAYER_BG(不随系统明暗反转——「不动沉浸底」);日夜间主题配色只映射到
|
||||
* 半透明叠加层(歌词页 scrim)与 accent(红)。 */
|
||||
@@ -568,6 +579,9 @@ void ipc_media_stop(void);
|
||||
int ipc_media_nav_exit(void); /* 任务2:发 MSG_NAV{EXIT} 给 launcher 请求退后台(进程+媒体会话保留;
|
||||
launcher M4 据 background_audio+PLAYING 判保活)。0=发出/-1=失败。 */
|
||||
int ipc_media_focus_consume(void); /* 任务3:UI 线程消费「回播放页」标志(0=无;1=已消费一次) */
|
||||
/* 批3:上报当前曲歌词(lrc 原文 + tlrc 翻译)到 launcher 媒体会话(MSG_META_LYRIC 分片)。
|
||||
* 由 lyric_worker 在拉到/清一歌词后调(换歌/换词 seq 自增;lrc/tl 可为空=清词)。 */
|
||||
void ipc_media_lyric_report(const char *lrc, const char *tl);
|
||||
int ipc_act_report(int act); /* 任务4 keep_awake:向 launcher 上报当前顶层 activity(MSG_ACT_FOCUS)。
|
||||
act=ACT_* 值,映射 "login/home/playlist/player/settings/search"(对齐
|
||||
app.json awake.<act> 键);launcher fg_keep_awake 依声明判常亮。
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/* app/test/test_meow_row_gap.c — 宿主验证:圆角卡列表项外边距(item margin/gap)几何。
|
||||
*
|
||||
* 只测 app/ui 卡片几何辅助(ncm_row_card_y / ncm_row_card_h + NCM_ROW_GAP / APP_ROW_H),
|
||||
* 纯整数运算,不链 SDK / 不开设备:
|
||||
* gcc -I. -I../sdk -I../meow_launcherd -Icore \
|
||||
* -I"$ROOT/patch_v2/sdk" -I"$ROOT/patch_v2/meow_launcherd" \
|
||||
* -Ivendor/mbedtls/include -Ivendor/jsmn -Ivendor/qrcodegen/c \
|
||||
* -Ivendor/minimp3 -Ivendor/dr_flac \
|
||||
* test_meow_row_gap.c -o test_meow_row_gap && ./test_meow_row_gap
|
||||
*
|
||||
* 断言集(对应「相邻 item 顶之间 = item 高 + gap」的可见形式):
|
||||
* ① 相邻卡顶间距 = APP_ROW_H(= 卡高 + gap;SDK 行距不变);
|
||||
* ② 卡片间可见外距 = NCM_ROW_GAP;
|
||||
* ③ 卡在其行高内上下对称内缩 → SDK 文本(按 APP_ROW_H 垂直居中)落卡中心;
|
||||
* ④ 滚动偏移只整体平移,不改变上述间距/对称。
|
||||
*/
|
||||
#include "../ncm_app_internal.h" /* APP_ROW_H / NCM_ROW_GAP / ncm_row_card_y / ncm_row_card_h */
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const int item = APP_ROW_H; /* 行距(SDK listview item_h,不变) */
|
||||
const int gap = NCM_ROW_GAP;
|
||||
const int list_y = 100;
|
||||
|
||||
/* 卡顶 = 行顶 + 上下对称内缩 gap/2;卡高 = item - gap。 */
|
||||
int y0 = ncm_row_card_y(item, 0, 0, list_y);
|
||||
int y1 = ncm_row_card_y(item, 1, 0, list_y);
|
||||
int h = ncm_row_card_h(item);
|
||||
|
||||
/* ① 行顶(索引0)=list_y;卡相对行顶对称内缩 gap/2;卡高=item-gap */
|
||||
assert(y0 == list_y + gap / 2);
|
||||
assert(h == item - gap);
|
||||
assert(h + gap == item);
|
||||
|
||||
/* ① 相邻卡顶间距 = item(顶到顶 = 卡高 + gap) */
|
||||
assert(y1 - y0 == item);
|
||||
|
||||
/* ② 卡片间可见外距 = gap(卡 i 底 到 卡 i+1 顶) */
|
||||
assert(y1 - (y0 + h) == gap);
|
||||
|
||||
/* ③ 卡中心 == 行中心(SDK 文本按行高居中 → 落卡中心) */
|
||||
assert(y0 - gap / 2 + item / 2 == y0 + h / 2);
|
||||
|
||||
/* ④ 滚动偏移只平移,不改变间距/对称 */
|
||||
for (int off = 0; off <= 2 * item; off += item / 2) {
|
||||
int a2 = ncm_row_card_y(item, 2, off, list_y);
|
||||
int a3 = ncm_row_card_y(item, 3, off, list_y);
|
||||
assert(a3 - a2 == item);
|
||||
assert(a3 - (a2 + h) == gap);
|
||||
/* 顶到顶 = 卡高 + gap,且卡在行内对称(对任意 off 一致) */
|
||||
assert(a2 - (list_y + (2 * item - off)) == gap / 2); /* 行顶 = list_y + idx*item - off */
|
||||
}
|
||||
|
||||
printf("PASS row_gap=%d card_h=%d top2top=%d visible_gap=%d symmetric=1\n",
|
||||
gap, h, item, gap);
|
||||
return 0;
|
||||
}
|
||||
@@ -122,6 +122,17 @@ const char *ncm_level_name(int lv)
|
||||
}
|
||||
}
|
||||
|
||||
/* §NEW 播放模式短名(三态):随机 / 列表 / 单曲(播放页模式钮文案,2 字居中)。 */
|
||||
const char *ncm_mode_name(int m)
|
||||
{
|
||||
switch (m) {
|
||||
case NCM_MODE_SHUFFLE: return "随机";
|
||||
case NCM_MODE_SINGLE: return "单曲";
|
||||
case NCM_MODE_LISTLOOP: /* fallthrough */
|
||||
default: return "列表";
|
||||
}
|
||||
}
|
||||
|
||||
const char *ncm_level_spec(int lv)
|
||||
{
|
||||
switch (lv) {
|
||||
|
||||
@@ -91,7 +91,8 @@ static void home_row_bg(void *ctx)
|
||||
int n = tab_count(g_tab);
|
||||
if (last > n) last = n;
|
||||
for (int i = first; i < last; i++) {
|
||||
int ry = r_list.y + (i * item - off) + 1, th2 = item - 2;
|
||||
int ry = ncm_row_card_y(item, i, off, r_list.y);
|
||||
int th2 = ncm_row_card_h(item);
|
||||
if (ry < r_list.y || ry + th2 > r_list.y + r_list.h) continue; /* 只画完整落在视口内的行 */
|
||||
ncm_fill_round(r_list.x, ry, r_list.w, th2, 12, th->surfaceContainer);
|
||||
}
|
||||
@@ -170,16 +171,21 @@ static void home_draw(void *ctx)
|
||||
int n = tab_count(g_tab);
|
||||
if (last > n) last = n;
|
||||
for (int i = first; i < last; i++) {
|
||||
int ry = r_list.y + (i * item - off) + 1, th2 = item - 2;
|
||||
int ry = ncm_row_card_y(item, i, off, r_list.y);
|
||||
int th2 = ncm_row_card_h(item);
|
||||
if (ry < r_list.y || ry + th2 > r_list.y + r_list.h) continue;
|
||||
int icy = ry + (item - isz) / 2;
|
||||
int icy = ry + (th2 - isz) / 2;
|
||||
int bx = r_list.x + 16;
|
||||
ncm_fill_round(bx, icy, isz, isz, 6, pa->red);
|
||||
meow_ui_fill_rect(bx + isz / 2 - 2, icy + isz / 2 - 2, 4, 4, pa->on_red); /* 盘芯 */
|
||||
if (g_press_row == i) {
|
||||
meow_ui_fill_rect(r_list.x, ry, 4, item - 2, pa->red);
|
||||
meow_ui_fill_rect_alpha(r_list.x, ry, r_list.w, item - 2, pa->red, 26);
|
||||
meow_ui_fill_rect(r_list.x, ry, 4, th2, pa->red);
|
||||
meow_ui_fill_rect_alpha(r_list.x, ry, r_list.w, th2, pa->red, 26);
|
||||
}
|
||||
/* 擦除 z=10 的 SDK 行分隔线(现落进卡片间空隙):以页底色填空隙带;不越出列表视口底。 */
|
||||
int gy = ry + th2, gh = NCM_ROW_GAP;
|
||||
if (gy + gh > r_list.y + r_list.h) gh = r_list.y + r_list.h - gy;
|
||||
if (gh > 0) meow_ui_fill_rect(r_list.x, gy, r_list.w, gh, th->bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@ static void pl_row_bg(void *ctx)
|
||||
int first = off / item, last = (off + r_list.h) / item + 1;
|
||||
if (last > g_st.track_ids_count) last = g_st.track_ids_count;
|
||||
for (int i = first; i < last; i++) {
|
||||
int ry = r_list.y + (i * item - off) + 1, th2 = item - 2;
|
||||
int ry = ncm_row_card_y(item, i, off, r_list.y);
|
||||
int th2 = ncm_row_card_h(item);
|
||||
if (ry < r_list.y || ry + th2 > r_list.y + r_list.h) continue; /* 只画完整落在视口内的行 */
|
||||
ncm_fill_round(r_list.x, ry, r_list.w, th2, 12, th->surfaceContainer);
|
||||
}
|
||||
@@ -193,15 +194,20 @@ static void pl_draw(void *ctx)
|
||||
int first = off / item, last = (off + r_list.h) / item + 1;
|
||||
if (last > g_st.track_ids_count) last = g_st.track_ids_count;
|
||||
for (int i = first; i < last; i++) {
|
||||
int ry = r_list.y + (i * item - off) + 1, th2 = item - 2;
|
||||
int ry = ncm_row_card_y(item, i, off, r_list.y);
|
||||
int th2 = ncm_row_card_h(item);
|
||||
if (ry < r_list.y || ry + th2 > r_list.y + r_list.h) continue;
|
||||
int icy = ry + (item - isz) / 2, bx = r_list.x + 16;
|
||||
int icy = ry + (th2 - isz) / 2, bx = r_list.x + 16;
|
||||
ncm_fill_round(bx, icy, isz, isz, 6, pa->red);
|
||||
meow_ui_fill_rect(bx + isz / 2 - 2, icy + isz / 2 - 2, 4, 4, pa->on_red);
|
||||
if (g_press_row == i) {
|
||||
meow_ui_fill_rect(r_list.x, ry, 4, item - 2, pa->red);
|
||||
meow_ui_fill_rect_alpha(r_list.x, ry, r_list.w, item - 2, pa->red, 26);
|
||||
meow_ui_fill_rect(r_list.x, ry, 4, th2, pa->red);
|
||||
meow_ui_fill_rect_alpha(r_list.x, ry, r_list.w, th2, pa->red, 26);
|
||||
}
|
||||
/* 擦除 z=10 的 SDK 行分隔线(现落进卡片间空隙):以页底色填空隙带;不越出列表视口底。 */
|
||||
int gy = ry + th2, gh = NCM_ROW_GAP;
|
||||
if (gy + gh > r_list.y + r_list.h) gh = r_list.y + r_list.h - gy;
|
||||
if (gh > 0) meow_ui_fill_rect(r_list.x, gy, r_list.w, gh, th->bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,8 @@ static void q_row_bg(void *ctx)
|
||||
if (last > cnt) last = cnt;
|
||||
int cur = player_manager_playing_song();
|
||||
for (int i = first; i < last; i++) {
|
||||
int ry = r_list.y + (i * item - off) + 1, th2 = item - 2;
|
||||
int ry = ncm_row_card_y(item, i, off, r_list.y);
|
||||
int th2 = ncm_row_card_h(item);
|
||||
if (ry < r_list.y || ry + th2 > r_list.y + r_list.h) continue; /* 只画完整落在视口内的行 */
|
||||
if (i == cur) {
|
||||
/* 当前播放行:红色左条 + 红色轻染(高亮),底用 red_ctr 浅红 */
|
||||
@@ -112,6 +113,7 @@ static void q_draw(void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
if (meow_ui_activity_active() != ACT_QUEUE) return;
|
||||
const meow_theme *th = meow_theme_get();
|
||||
const ncm_pal_t *pa = ncm_palette(g_dark);
|
||||
int cnt = appstate_queue_count();
|
||||
if (cnt <= 0) return;
|
||||
@@ -120,15 +122,20 @@ static void q_draw(void *ctx)
|
||||
int first = off / item, last = (off + r_list.h) / item + 1;
|
||||
if (last > cnt) last = cnt;
|
||||
for (int i = first; i < last; i++) {
|
||||
int ry = r_list.y + (i * item - off) + 1, th2 = item - 2;
|
||||
int ry = ncm_row_card_y(item, i, off, r_list.y);
|
||||
int th2 = ncm_row_card_h(item);
|
||||
if (ry < r_list.y || ry + th2 > r_list.y + r_list.h) continue;
|
||||
int icy = ry + (item - isz) / 2, bx = r_list.x + 16;
|
||||
int icy = ry + (th2 - isz) / 2, bx = r_list.x + 16;
|
||||
ncm_fill_round(bx, icy, isz, isz, 6, pa->red);
|
||||
meow_ui_fill_rect(bx + isz / 2 - 2, icy + isz / 2 - 2, 4, 4, pa->on_red);
|
||||
if (g_press_row == i) {
|
||||
meow_ui_fill_rect(r_list.x, ry, 4, item - 2, pa->red);
|
||||
meow_ui_fill_rect_alpha(r_list.x, ry, r_list.w, item - 2, pa->red, 26);
|
||||
meow_ui_fill_rect(r_list.x, ry, 4, th2, pa->red);
|
||||
meow_ui_fill_rect_alpha(r_list.x, ry, r_list.w, th2, pa->red, 26);
|
||||
}
|
||||
/* 擦除 z=10 的 SDK 行分隔线(现落进卡片间空隙):以页底色填空隙带;不越出列表视口底。 */
|
||||
int gy = ry + th2, gh = NCM_ROW_GAP;
|
||||
if (gy + gh > r_list.y + r_list.h) gh = r_list.y + r_list.h - gy;
|
||||
if (gh > 0) meow_ui_fill_rect(r_list.x, gy, r_list.w, gh, th->bg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -49,6 +49,7 @@ int meow_btn_pressed(meow_widget *w); /* 应用在 on_tap 命中后
|
||||
/* ---- §5.8.2 Modifier 式通用 Options(轻量结构体,非链式 DSL)----
|
||||
* 经 meow_widget_set_opts 一次性挂载,作用于任意控件(标准/自定义)。全部控件共用。
|
||||
* 哨兵语义:bg/fg==0=用控件/主题默认;stroke==0=无描边;stroke_w=描边宽;
|
||||
* 控件语义:W_PROGRESS 用 bg=轨道(0=surfaceVariant)、fg=填充(0=primary);见 meow_ui_widget.c 批5b;
|
||||
* radius==-1=控件默认(如按钮 10),>=0=指定圆角(0=直角);pad/margin=0=无;
|
||||
* disabled/selected=1=置位(立即反映到状态机位)。 */
|
||||
typedef struct meow_widget_opts {
|
||||
|
||||
@@ -2069,31 +2069,35 @@ void meow_widget_draw(meow_widget *w)
|
||||
break;
|
||||
}
|
||||
case W_PROGRESS: {
|
||||
/* 批5b:轨道/填充可由 opts 覆盖(opts.bg=轨道、opts.fg=填充);opts 未设则回主题默认
|
||||
* (surfaceVariant/primary)——兼容既有调用(如 hello demo、现在播放页取色后回退默认)。 */
|
||||
uint32_t track = widget_bg(w, th, th->surfaceVariant);
|
||||
uint32_t fill = widget_fg(w, th, th->primary);
|
||||
if (w->variant == 1) { /* 圆形(几何 = 整圆像素外接框;由此解回圆心/半径) */
|
||||
int thk = MEOW_PROGRESS_ARC_THK;
|
||||
int m = MEOW_PROGRESS_ARC_MARGIN;
|
||||
int ccx = w->x + w->w / 2, ccy = w->y + w->h / 2;
|
||||
int rr = w->w / 2 - m; /* 与 create 一致:回到调用方传入的半径 r */
|
||||
if (rr <= 0) break;
|
||||
meow_gfx_ring_arc(ccx, ccy, rr, thk, 0, 360, th->surfaceVariant);
|
||||
meow_gfx_ring_arc(ccx, ccy, rr, thk, 0, 360, track);
|
||||
if (w->value < 0) { /* 不定:按时间推进一段弧(App 在 on_tick 里重绘驱动) */
|
||||
int start = (int)((meow_ui_time_ms() / 30) % 360);
|
||||
meow_gfx_ring_arc(ccx, ccy, rr, thk, start - 90, 90, th->primary);
|
||||
meow_gfx_ring_arc(ccx, ccy, rr, thk, start - 90, 90, fill);
|
||||
} else if (w->value > 0) {
|
||||
int sweep = w->value * 360 / 100;
|
||||
if (sweep > 0) meow_gfx_ring_arc(ccx, ccy, rr, thk, -90, sweep, th->primary);
|
||||
if (sweep > 0) meow_gfx_ring_arc(ccx, ccy, rr, thk, -90, sweep, fill);
|
||||
}
|
||||
} else { /* 线性 */
|
||||
int thk = w->h > 0 ? w->h : 4;
|
||||
int yy = w->y + w->h / 2 - thk / 2;
|
||||
meow_ui_fill_rect(w->x, yy, w->w, thk, th->surfaceVariant);
|
||||
meow_ui_fill_rect(w->x, yy, w->w, thk, track);
|
||||
if (w->value < 0) { /* 不定:移动块 */
|
||||
int fw = w->w / 3;
|
||||
int pos = (int)((meow_ui_time_ms() / 12) % (w->w + fw)) - fw;
|
||||
meow_ui_fill_rect(w->x + pos, yy, fw, thk, th->primary);
|
||||
meow_ui_fill_rect(w->x + pos, yy, fw, thk, fill);
|
||||
} else if (w->value > 0) {
|
||||
int fw = w->value * w->w / 100;
|
||||
if (fw > 0) meow_ui_fill_rect(w->x, yy, fw, thk, th->primary);
|
||||
if (fw > 0) meow_ui_fill_rect(w->x, yy, fw, thk, fill);
|
||||
}
|
||||
}
|
||||
if (disabled) meow_ui_fill_rect_alpha(w->x, w->y, w->w, w->h, th->onSurface, 90);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
# ---- 用户态/服务守护二进制(usr/bin,全部 chmod 755 静态 MIPS)----
|
||||
patch_v2/bootmenu/meow_bootmenu|/usr/bin/meow_bootmenu|8de51144538d698c3ff82ee6651b8b1a|引导选单 M6.25(开机菜单/第二屏亮度按用户设置恢复:显示前读 settings.conf 写回,方案A)
|
||||
patch_v2/meow_launcherd/meow_launcherd|/usr/bin/meow_launcherd|0cdf940f58d1e26e7529df226689ab9c|M6.31 歌词页封面修复(np_draw_lyric_coverbg封面背景+1s整页重绘,修批5歌词页无封面/scrim逐秒压黑)+播放页右滑返回+批3歌词数据源+批4双页歌词+批5封面双色取色+蓝牙P1子页
|
||||
patch_v2/meow_launcherd/meow_launcherd|/usr/bin/meow_launcherd|513d7603ff4b8203af3927ff88569d21|M6.32 全局播放页进度条/按钮局部重绘回退默认色修复(agent-408取色主题抽共用np_grad_row/np_page_bg_row/np_theme_widgets,1s局部重绘也接取色,进度条fill=accent/track=fg_dim/四钮accent)+重编SDK W_PROGRESS读opts.bg/fg(meow_ui.a 86af4d29)+链sdk meow_lyric/lyric_view/meow_img_color
|
||||
patch_v2/meow_watchdog/meow_watchdog|/usr/bin/meow_watchdog|34ddbf0275526eaf9be988134845c3af|应用看门狗 M6.23(亮屏亮度按用户设置 display.brightness 恢复,修 panel ON 固定60跳变)
|
||||
patch_v2/meow_svcd/meow_svcd|/usr/bin/meow_svcd|605646c4cc93f2baf29071ea6bc870ea|服务管理器 M2.77(+崩溃上报 meow_crash agent-187)
|
||||
mips-repo/bins/meow_mdns/bin/meow_mdns|/usr/bin/meow_mdns|d6b0151bda26768f19952dae1342610d|mDNS 应答器 M2.78(启动竞态+换IP重检 agent-194)
|
||||
|
||||
Reference in new issue
Block a user