Files
MeowOS-For-R3P2/patch_v2/sdk/meow_ui_theme.c
T
MeowOS 7300fc0a13 状态栏正确闭环(agent-142): 系统进程统一渲染+App不画+覆盖叠加+数据唯一+MD3图标式+主题换图标
- meow_ui_sys_set_system_mode: launcher置1才渲染, App默认0→不画状态栏; app_overlay_statusbar在launch_app循环~1s叠加28px顶条(不SIGSTOP App)
- 数据源唯一(launcher g_sys→meow_ui_sys_feed; wifi_level/batt/vol/bri/clock), 根治"launcher有亮度App没有"
- 右侧=MD3图标+变量值(statusbar_right_str文本退役→图标簇, 复用sb_icons.h/MEOW_SB_ICON_*/meow_gfx_blit_icon); 颜色随meow_theme
- ui.style换图标集(meow_ui_style/set_style读ui.style md3/miuix, MIUIx暂MD3占位)
- hello最小改动(redraw非全屏只清inset=28之下, 不冲系统顶条); 开放点: App不SIGSTOP/inset28/MIUIx占位/set_statusbar系统模式门
- meow_ui.a=3da5af7b launcher=a2b1c096 hello=67075741 0warning; 宿主test_sb_statusbar ALL PASS + render PPM目检(左时钟右亮度/WiFi/蓝牙/音量/电量)
- 遗留: 真机验证(无双画/数据一致/顶条叠加/inset/ui.style); 运行时fullscreen沉浸叠画待M3; MIUIx图标占位
2026-08-30 19:32:40 +08:00

239 lines
9.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* meow_ui_theme.c — 主题/配置(B1.5 / M2.46)。
*
* 内置日间/夜间两套色板;模式跟随系统设置键 display.theme_mode + display.theme
* (/usr/data/meow/settings.conf,与 launcher meow_settings 同源)。
* 判定与 launcher 的 s_ui_theme() 完全对齐(避免两套逻辑漂移):
* - display.theme_mode = manual:直读 display.theme(dark/light)决定深浅。
* - display.theme_mode = auto:按深色时段 display.theme_dark_start/end(分钟 0-1439),
* 半开区间 [start,end);start>end 跨午夜;start==end 视为未配置 → 回退 manual(display.theme)。
* 读取缺失/非法一律回退深色(与 launcher 默认一致)。
* 切换即广播 listener。AUTO 解析只在查询时按当前系统时间计算(不缓存)。
*/
#include "meow_ui.h"
#include "meow_ui_internal.h" /* meow_theme_reload() 定义(供 launcher 逼重读 settings) */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define MEOW_SETTINGS_FILE "/usr/data/meow/settings.conf"
static meow_theme g_light = {
0xE8EAF0, 0x1A1A2A, 0x2A5A8A, 0x4A4F5A, 28, 20
};
static meow_theme g_dark = {
0x141824, 0xFFFFFF, 0x4A6A9A, 0x9AA4C8, 28, 20
};
static meow_theme_mode g_mode = MEOW_THEME_DARK; /* 配置生效的判定模式(默认深色,与 launcher 默认一致) */
static meow_theme_mode g_manual = MEOW_THEME_DARK; /* display.theme 解析出的手动深浅;auto 未配置时段时回退用之 */
static int g_dark_start = 0; /* 深色时段开始(分钟 0-1439) */
static int g_dark_end = 0; /* 深色时段结束(分钟 0-1439) */
static int g_loaded = 0;
static int g_style = MEOW_STYLE_MD3; /* 顶级主题风格族(§8.1.2):默认 MD3 */
static meow_theme_listener g_listeners[8];
static int g_nlisteners = 0;
/* ---- 读 /usr/data/meow/settings.conf 的 key=value(兼容 "key = value" 带空格形式)----
* 与 launcher meow_settings_import 同款解析:按 '=' 切分,key/value 各自去首尾空白,
* 精确匹配 key(避免 display.theme 误匹配 display.theme_mode)。返回 0=命中,-1=未命中。 */
static int get_setting_str(const char *key, char *buf, int buflen)
{
FILE *f = fopen(MEOW_SETTINGS_FILE, "r");
if (!f || buflen <= 0) return -1;
char line[160];
int kl = (int)strlen(key);
int found = 0;
while (fgets(line, sizeof line, f)) {
char *eq = strchr(line, '=');
if (!eq) continue;
/* key = 行首到 '=',去尾空白 */
char *k = line;
while (*k == ' ' || *k == '\t') k++;
int n = (int)(eq - k);
while (n > 0 && (k[n-1] == ' ' || k[n-1] == '\t')) n--;
if (n != kl || strncmp(k, key, (size_t)kl) != 0) continue;
/* value = '=' 后,去首尾空白 / 行尾 CRLF */
const char *v = eq + 1;
while (*v == ' ' || *v == '\t') v++;
int m = 0;
while (*v && *v != '\n' && *v != '\r' && m < buflen - 1) buf[m++] = *v++;
while (m > 0 && (buf[m-1] == ' ' || buf[m-1] == '\t')) m--;
buf[m] = 0;
found = 1;
break;
}
fclose(f);
return found ? 0 : -1;
}
static int get_setting_int(const char *key, int *out)
{
char buf[32];
if (get_setting_str(key, buf, sizeof buf) != 0) return -1;
*out = atoi(buf);
return 0;
}
/* 解析 display.theme 的值(dark/light,非索引)→ LIGHT/DARK;未知/缺失回退 DARK(launcher 默认)。 */
static meow_theme_mode parse_manual(const char *v)
{
while (*v == ' ' || *v == '\t') v++;
if (!strncmp(v, "light", 5)) return MEOW_THEME_LIGHT;
return MEOW_THEME_DARK; /* "dark" / 未知 → 深色 */
}
static void load_settings(void)
{
char buf[64];
g_manual = MEOW_THEME_DARK;
g_mode = MEOW_THEME_DARK;
g_dark_start = 0;
g_dark_end = 0;
/* display.theme:手动深浅(auto 未配置时段时也回退这里) */
if (get_setting_str("display.theme", buf, sizeof buf) == 0)
g_manual = parse_manual(buf);
/* display.theme_mode:manual=读 display.theme;auto=时段。缺失/非法 → manual */
if (get_setting_str("display.theme_mode", buf, sizeof buf) == 0) {
if (!strcmp(buf, "auto")) g_mode = MEOW_THEME_AUTO;
else g_mode = g_manual; /* manual(含 "light"/"dark"/未知)→ 读 display.theme */
} else {
g_mode = g_manual; /* 无 theme_mode 键 → 默认 manual → display.theme */
}
get_setting_int("display.theme_dark_start", &g_dark_start);
get_setting_int("display.theme_dark_end", &g_dark_end);
/* 顶级主题风格族(§8.1.2 minimal):ui.style 的 md3/miuix。读取缺失/未知 → 回退 MD3。
* 决定状态栏右侧图标集(§3.1 同一个状态栏);配色日/夜仍由 display.theme 现有解析管。 */
g_style = MEOW_STYLE_MD3;
if (get_setting_str("ui.style", buf, sizeof buf) == 0) {
const char *v = buf;
while (*v == ' ' || *v == '\t') v++;
if (!strncmp(v, "miuix", 5) || !strncmp(v, "miui", 4)) g_style = MEOW_STYLE_MIUIX;
}
}
/* 当前本地时刻的「当天第几分钟」(tm_hour*60+tm_min);供时段判定用(与 launcher s_now_min_of_day 一致)。 */
static int now_min_of_day(void)
{
time_t t = time(NULL);
struct tm tm;
localtime_r(&t, &tm);
return tm.tm_hour * 60 + tm.tm_min;
}
/* 深色时段判定(与 launcher theme_should_dark 完全一致):now_min ∈ [start,end) → 深色。
* - start==end 视为未配置,返回 -1(由调用方决定回退策略)。
* - start<end:非跨天(如 720→1080 = 12:00→18:00)。
* - start>end:跨午夜(如 1140→420 = 19:00→次日07:00)。
* - 边界:end 半开(恰好 end 分回到浅色),start 闭(恰好 start 分进入深色)。 */
static int theme_should_dark(int now_min, int start, int end)
{
if (start == end) return -1; /* 未配置 */
if (start < end)
return (now_min >= start && now_min < end) ? 1 : 0;
return (now_min >= start || now_min < end) ? 1 : 0; /* 跨午夜 */
}
static meow_theme_mode resolve_mode(meow_theme_mode m)
{
if (m != MEOW_THEME_AUTO) return m;
int d = theme_should_dark(now_min_of_day(), g_dark_start, g_dark_end);
if (d < 0) return g_manual; /* 时段未配置:回退 display.theme 手动深浅 */
return d ? MEOW_THEME_DARK : MEOW_THEME_LIGHT;
}
static void broadcast(void)
{
for (int i = 0; i < g_nlisteners; i++)
if (g_listeners[i]) g_listeners[i](g_mode);
}
const meow_theme *meow_theme_get(void)
{
if (!g_loaded) {
load_settings();
g_loaded = 1;
}
return resolve_mode(g_mode) == MEOW_THEME_DARK ? &g_dark : &g_light;
}
meow_theme_mode meow_theme_get_mode(void)
{
if (!g_loaded) { load_settings(); g_loaded = 1; }
return g_mode;
}
void meow_theme_set_mode(meow_theme_mode m)
{
if (!g_loaded) { load_settings(); g_loaded = 1; }
if (m < MEOW_THEME_LIGHT || m > MEOW_THEME_AUTO) return;
if (m == g_mode) return;
g_mode = m;
broadcast();
}
/* 重置缓存:下一次 meow_theme_get()/get_mode()/defaults() 重读 settings.conf。
* launcher 在 statusbar 刷新前调用,让 SDK 全局状态栏(其主题缓存于 g_loaded)跟手
* launcher 侧主题变更(settings.conf 被改后立即反映),避免「界面已换肤、状态栏滞留旧主题」。 */
void meow_theme_reload(void)
{
g_loaded = 0;
}
meow_theme meow_theme_defaults(meow_theme_mode m)
{
switch (resolve_mode(m)) {
case MEOW_THEME_DARK: return g_dark;
case MEOW_THEME_LIGHT:
default: return g_light;
}
}
/* ---- §8.1.2 顶级主题风格族(minimal)----
* meow_ui_style() 返回当前 ui.style(读取走 load_settings,随 meow_theme_reload() 重读,
* 故 launcher 改 settings.conf 后经 sb_sdk_refresh→theme_reload 即跟手)。
* meow_ui_set_style() 记录 style(越界 clamp;同值忽略)并触发 reload/broadcast——供需要
* 显式切换的调用方(后续 launcher 设置页切换可改走此路径);状态栏图标集据此换集。 */
int meow_ui_style(void)
{
if (!g_loaded) { load_settings(); g_loaded = 1; }
return g_style;
}
void meow_ui_set_style(int style)
{
if (style < MEOW_STYLE_MD3) style = MEOW_STYLE_MD3;
if (style > MEOW_STYLE_MIUIX) style = MEOW_STYLE_MIUIX;
if (style == g_style) return;
g_style = style;
/* 触发下一帧按新 style 重绘:清 settings 缓存(下次 get 重读)不必要(style 已记录),
* 仅广播主题 listener(沿用 theme 广播机制,让控件/状态栏下一帧用新 style 重绘)。 */
broadcast();
}
void meow_theme_add_listener(meow_theme_listener cb)
{
if (!cb) return;
if (g_nlisteners >= (int)(sizeof g_listeners / sizeof g_listeners[0])) return;
for (int i = 0; i < g_nlisteners; i++) if (g_listeners[i] == cb) return;
g_listeners[g_nlisteners++] = cb;
}
void meow_theme_remove_listener(meow_theme_listener cb)
{
for (int i = 0; i < g_nlisteners; i++) {
if (g_listeners[i] == cb) {
g_listeners[i] = g_listeners[g_nlisteners - 1];
g_nlisteners--;
return;
}
}
}