/* ui/common/chrome.c — dev.player.ncm 共享 chrome(TopAppBar 建置 / 几何 / 空态&页脚 / 底部提示条)。 * * 与 files_app/ui/common/chrome.c 同理:把「页面 chrome 固定不随内容重建」分出去。绘制全部读 * meow_theme_get() 语义色(§8.1),不硬编码配色。topbar 由 meow_topappbar 建,自动注册进绘制物 * 注册表(§6.2),owner=创建时 active activity。 */ #include "../ncm_app_internal.h" #include int ncm_statusbar(void) { int sb = meow_ui_statusbar_height(); return sb < 0 ? 0 : sb; } ncm_rect_t ncm_topbar_rect(void) { int sb = ncm_statusbar(); return NR(0, sb, meow_ui_width(), APP_TOPBAR_H); } ncm_rect_t ncm_content_rect(void) { int sb = ncm_statusbar(); int y = sb + APP_TOPBAR_H; int h = meow_ui_height() - y; if (h < 0) h = 0; return NR(0, y, meow_ui_width(), h); } meow_widget *ncm_topbar_create(const char *title, int back, const char *action_label) { ncm_rect_t r = ncm_topbar_rect(); meow_widget *tb = meow_topappbar_create(r.x, r.y, r.w, r.h, title); meow_topappbar_set_back(tb, back); if (action_label) meow_topappbar_add_action(tb, action_label); meow_widget_set_z(tb, 999); /* chrome 置顶(§6.2:> 一切自动 z) */ return tb; } /* 空态/错误:居中两行(kind 大字 + what 小字)。kind 用品牌红(§3.1 品牌元素走 App 调色板)。 */ void ncm_draw_empty(ncm_rect_t r, const char *kind, const char *what) { const meow_theme *th = meow_theme_get(); const ncm_pal_t *pa = ncm_palette(g_dark); int cy = r.y + r.h / 2; meow_ui_text_center(r.x + r.w / 2, cy - 34, kind ? kind : "", 28, pa->red); if (what && what[0]) meow_ui_text_center(r.x + r.w / 2, cy + 4, what, 20, th->onSurfaceVariant); } /* 底部信息(右对齐 dim)。 */ void ncm_draw_footer(ncm_rect_t r, const char *text) { const meow_theme *th = meow_theme_get(); if (!text || !text[0]) return; meow_ui_text_right(r.x + r.w - APP_PAD, r.y + r.h - 26, text, 20, th->dim); } /* 底部提示条(非阻塞):画在内容区底部之上,2s 后由 tick 清除。 * 只画一次并标脏;g_snack_until 为过期时间(0=无)。 */ static char s_snack[192]; static uint64_t s_snack_until; /* monotonic ms 过期时刻 */ static ncm_rect_t s_snack_r; static int s_snack_id; /* <0=未注册 */ static void snack_draw(void *ctx) { (void)ctx; if (meow_ui_time_ms() >= s_snack_until && s_snack_until != 0) { meow_ui_invalidate(s_snack_r.x, s_snack_r.y, s_snack_r.w, s_snack_r.h); s_snack_until = 0; return; } const meow_theme *th = meow_theme_get(); /* 深色底 + 白字 */ meow_ui_fill_rect(s_snack_r.x, s_snack_r.y, s_snack_r.w, s_snack_r.h, th->inverseSurface); meow_ui_text_center(s_snack_r.x + s_snack_r.w / 2, s_snack_r.y + (s_snack_r.h - 26) / 2 + 4, s_snack, 20, th->inverseOnSurface); } void ncm_snack(const char *text) { if (!text) return; strncpy(s_snack, text, sizeof s_snack - 1); s_snack[sizeof s_snack - 1] = 0; s_snack_until = meow_ui_time_ms() + 2000; int w = meow_ui_width() - 2 * APP_PAD; s_snack_r = NR(APP_PAD, meow_ui_height() - 56, w, 40); if (s_snack_id < 0) s_snack_id = meow_draw_custom_register(999, s_snack_r.x, s_snack_r.y, s_snack_r.w, s_snack_r.h, snack_draw, NULL); else meow_draw_set_z(s_snack_id, 999); meow_ui_invalidate(s_snack_r.x, s_snack_r.y, s_snack_r.w, s_snack_r.h); } /* 周期检查:snack 到期清除。可由各页 tick 调。 */ void chrome_tick(void) { if (s_snack_until && meow_ui_time_ms() >= s_snack_until) { meow_ui_invalidate(s_snack_r.x, s_snack_r.y, s_snack_r.w, s_snack_r.h); s_snack_until = 0; } } /* ---- §20 音质档位显示名/规格(八档 UI 权威口径,NCM_CACHE_DESIGN §3;settings/player 共用)---- * 档位中文名以我方设计文档为准(BIZ_NOTES §2.1:CNMPlayer 标签只做 level 串对齐参考)。 */ const char *ncm_level_name(int lv) { switch (lv) { case NCM_LEVEL_SURROUND: return "沉浸环绕声"; case NCM_LEVEL_SKY: return "臻音全景声"; case NCM_LEVEL_JYMASTER: return "超清母带"; case NCM_LEVEL_JYEFFECT: return "高清臻音"; case NCM_LEVEL_DOLBY: return "杜比全景声"; /* 映射保留,不进 UI 清单 */ case NCM_LEVEL_HIRES: return "Hi-Res"; case NCM_LEVEL_LOSSLESS: return "无损 SQ"; case NCM_LEVEL_EXHIGH: return "极高 HQ"; case NCM_LEVEL_HIGHER: return "较高"; /* 仅降级链中间档,不进 UI */ default: return "标准"; } } /* §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) { case NCM_LEVEL_SURROUND: return "5.1 声道"; case NCM_LEVEL_SKY: return "Audio Vivid"; case NCM_LEVEL_JYMASTER: return "192kHz/24bit"; case NCM_LEVEL_JYEFFECT: return "96kHz/24bit"; case NCM_LEVEL_DOLBY: return "Dolby Atmos"; case NCM_LEVEL_HIRES: return "192kHz/24bit"; case NCM_LEVEL_LOSSLESS: return "48kHz/16bit"; case NCM_LEVEL_EXHIGH: return "≤320kbps"; case NCM_LEVEL_HIGHER: return "192kbps"; default: return "128kbps"; } }