跨端: 深色模式下的品牌浅底不跟随 —— 12 处「选中/未读」底色在深色页上刺眼
## 真 bug(设备实测) 深色主题下,「我的」页**选中**的那张账号卡片仍是接近纯白的浅蓝 (实测像素 `(255,255,255)` 级别的浅底压在 `(32,34,36)` 的深色页上)。 根因:`Theme.accentSoft = '#EFF6FF'` 是**写死的浅色**,而它被当作 「选中态背景」用在 12 处(未读邮件行、选中账号、分段选中、登录页模式切换…)。 **为什么只有 WebUI 没这个问题**:它有 CSS 变量的**反转发**机制 —— `index.css:113` 的 `--c-blue-50: 239 246 255` 在 `.dark` 段(`:475`)被换成 `28 37 54`(深蓝黑)。ArkTS 的 `static readonly` **一个常量一个值**, 没有那层机制 ⇒ 静态常量必须自己提供两个取值。 ## 修法 1. `Theme.accentSoftDark = '#1C2536'`(对齐 WebUI `.dark --c-blue-50` 的 `28 37 54`) 2. `Theme.accentSoftFor(dark)` 作为**唯一入口** —— 不在页面里各自 `isDark ? a : b`:那样每处都会各写一遍,迟早漏一处 (WebUI 那条"由 test/theme.test.mjs 逐档断言"就是为防这个) 3. **深浅色从哪来**:只有 `MainPage` 算得出(它读 `resourceManager` 的 `colorMode`)。所以走 `AppStorage` 单向发布(与徽标、windowInsets 同一套): MainPage 算 → 写 `agentmail.appearance.isDark` → 各窗格 `@StorageProp` 读。 6 个文件、12 处,全部改用 `accentSoftFor(this.isDarkNow)`。 **设备实测**:深色下「我的」页账号卡片与收件箱未读行都变成深蓝底, 像素 `(32,34,36)` 与页面底一致(不再刺眼)。 ## 判据(这条是新加的,形状值得记) `cross-client-theme` 新增:**品牌浅底必须有深色变体**。断三件事: 1. 深色变体存在,且**取值从 WebUI 的 `.dark` 段反推**(不是随手挑一个深色); 2. 有按主题选值的**入口**(防"页面各自写三元"); 3. **用到它的地方真的走那个入口** —— 扫描所有 `backgroundColor(… accentSoft …)` 并排除 `accentSoftFor`,把漏改的位置**逐行报出来**。 第 3 条在我改到一半时**当场列出了剩下 9 处**(`CalendarPage:1172`、 `ComposePage:255`、`LoginPage:327`…)—— 这就是它该有的样子: 不是"断言存在某个常量",而是"断言没有一处漏改"。 ★ 写这条判据时踩了自己一次:JS 模板串里嵌了反引号包围的标识符 (`` `accentSoft` ``),直接 SyntaxError。改用字符串拼接。 ## 判据 `run-all.mjs` → `checks=506 pass=506 fail=0 skip=0 red=0 broken=0 unreported=0`。 `hvigorw assembleHap` 成功;前端重建。 **未验**:日历/登录页在深色下的观感(只逐处改了底色,没逐页截图)。
This commit is contained in:
@ -164,6 +164,14 @@ struct InboxTab {
|
||||
@Prop navReserve: number = 0;
|
||||
/** 选中邮件回调:宽屏内联到 Navigation 右栏,窄屏 push 到目标页 */
|
||||
onOpenMail: (mailId: string, accountId: string) => void = (): void => {};
|
||||
/*
|
||||
* 当前是否深色(`MainPage` 发布)—— 用来选品牌浅底的深浅变体。
|
||||
*
|
||||
* ★ 2026-09-19:深色主题下「未读」行/选中账号的**浅蓝底**在深色页面上刺眼,
|
||||
* 根因是 `Theme.accentSoft` 是写死的浅色(WebUI 靠 `.dark` 段反转发解决,
|
||||
* ArkTS 的静态常量没有那层机制)。窗格自己算不出深浅色 ⇒ 走 AppStorage 读。
|
||||
*/
|
||||
@StorageProp('agentmail.appearance.isDark') isDarkNow: boolean = false;
|
||||
@State mails: MailSummary[] = [];
|
||||
/** 按会话折叠后的列表(单封的组平铺渲染) */
|
||||
@State groups: SessionGroup[] = [];
|
||||
@ -433,7 +441,7 @@ struct InboxTab {
|
||||
.fontSize(14).fontColor(this.accountFilter === 'all' ? Theme.accent : Theme.textPrimary)
|
||||
.fontWeight(this.accountFilter === 'all' ? FontWeight.Bold : FontWeight.Normal)
|
||||
.width('100%').height(40).padding({ left: 16 })
|
||||
.backgroundColor(this.accountFilter === 'all' ? Theme.accentSoft : Theme.surface)
|
||||
.backgroundColor(this.accountFilter === 'all' ? Theme.accentSoftFor(this.isDarkNow) : Theme.surface)
|
||||
.onClick(() => {
|
||||
this.accountFilter = 'all';
|
||||
this.accountName = '全部邮箱';
|
||||
@ -454,7 +462,7 @@ struct InboxTab {
|
||||
.layoutWeight(1)
|
||||
}
|
||||
.width('100%').height(48).padding({ left: 16 })
|
||||
.backgroundColor(this.accountFilter === acct.id ? Theme.accentSoft : Theme.surface)
|
||||
.backgroundColor(this.accountFilter === acct.id ? Theme.accentSoftFor(this.isDarkNow) : Theme.surface)
|
||||
.onClick(() => {
|
||||
this.accountFilter = acct.id;
|
||||
this.accountName = acct.displayName;
|
||||
@ -535,7 +543,7 @@ struct InboxTab {
|
||||
this.MailItem(mail)
|
||||
}
|
||||
.width('100%').height(64)
|
||||
.backgroundColor(mail.status === 'unread' ? Theme.accentSoft : Theme.surface)
|
||||
.backgroundColor(mail.status === 'unread' ? Theme.accentSoftFor(this.isDarkNow) : Theme.surface)
|
||||
.borderRadius(Theme.radiusCard)
|
||||
.border({ width: 1, color: Theme.border })
|
||||
.clip(true)
|
||||
@ -626,7 +634,7 @@ struct InboxTab {
|
||||
if (this.accountFilter === 'all' && mail.source_account_name.length > 0) {
|
||||
Text(mail.source_account_name)
|
||||
.fontSize(10).fontColor(Theme.accent)
|
||||
.backgroundColor(Theme.accentSoft).borderRadius(4)
|
||||
.backgroundColor(Theme.accentSoftFor(this.isDarkNow)).borderRadius(4)
|
||||
.padding({ left: 5, right: 5, top: 1, bottom: 1 })
|
||||
.margin({ left: 6 })
|
||||
}
|
||||
@ -2170,6 +2178,14 @@ struct MainPage {
|
||||
@State currentIndex: number = 0;
|
||||
/** 宽屏模式(≥768vp):复刻 WebUI 的三栏布局(Sidebar | 内容,无底部导航条) */
|
||||
@State isWide: boolean = false;
|
||||
/**
|
||||
* "当前是否深色"的发布键(`AppStorage`)。
|
||||
*
|
||||
* 各窗格里有若干"品牌浅底"(`Theme.accentSoft`),深色下必须换深色变体。
|
||||
* 窗格自己算不出这件事(`Theme` 是静态类、拿不到 Context)⇒
|
||||
* 由 MainPage 算好发布、窗格 `@StorageProp` 读(与徽标同一套机制)。
|
||||
*/
|
||||
private readonly KEY_IS_DARK: string = 'agentmail.appearance.isDark';
|
||||
/*
|
||||
* 壁纸层(背景的**画法**在 `model/Wallpaper.ts` 里算好,这里只负责画)。
|
||||
*
|
||||
@ -2377,6 +2393,8 @@ struct MainPage {
|
||||
store.applyTheme(ctx, next);
|
||||
store.saveLocal(ctx, snap);
|
||||
this.isDarkNow = next === 'dark';
|
||||
/* 侧栏的主题快捷键也要把新状态发布出去(否则窗格里的浅底不跟着换) */
|
||||
AppStorage.setOrCreate(this.KEY_IS_DARK, this.isDarkNow);
|
||||
const client: ApiClient = ApiClient.getInstance(ctx);
|
||||
new AppearanceApi(client).put(snap, store.wallpaper !== null).catch(() => {});
|
||||
}
|
||||
@ -2479,6 +2497,14 @@ struct MainPage {
|
||||
const dark: boolean = isDarkMode(snap.theme, systemMode);
|
||||
/* 侧栏底部那个主题按钮的图标跟着它走(WebUI `ThemeToggleButton` 同口径) */
|
||||
this.isDarkNow = dark;
|
||||
/*
|
||||
* 把"当前是不是深色"**发布出去** —— 各窗格(通信/日历/联系/我的)里
|
||||
* 有若干"品牌浅底"(`Theme.accentSoft`),深色下必须换成深色变体。
|
||||
* 那些窗格自己算不出这件事(`Theme` 是静态类、拿不到 Context),
|
||||
* 所以走 `AppStorage` 单向发布(与徽标、windowInsets 同一套机制):
|
||||
* MainPage 算 → 写 → 窗格 `@StorageProp` 读。
|
||||
*/
|
||||
AppStorage.setOrCreate(this.KEY_IS_DARK, dark);
|
||||
/*
|
||||
* 侧栏头像的前两字:当前**活跃账号**的展示名(不是 `accountName`,
|
||||
* 那是收件箱筛选器选的)。拿不到就让它空着 —— 侧栏会显示 `?`。
|
||||
|
||||
Reference in New Issue
Block a user