跨端: 壁纸遮盖色改用页面底色系(mask 两套主题都深,浅色下方向与 WebUI 相反);模态遮罩保持 mask
pi 提了一个**方向性**疑问,让我先把值读出来再定 —— 读完确认**他是对的**,而且这是"机制上确定不同"。
## 实测(两张 SDK 表交叉验证,不靠记忆)
`ets/build-tools/ets-loader/sysResource.js` 给名字→id,`previewer/.../resources.txt` 给 id→值:
| 令牌 | 浅色主题 | 深色主题 |
|---|---|---|
| `ohos_id_color_mask_regular`(原 `Theme.overlay`) | `#99182431` **深蓝灰** | `#b2000000` 黑 |
| `ohos_id_color_background` | `#ffffffff` **白** | `#ff18181a` 近黑 |
⇒ mask 的 light/regular/thick 是**浓度档**(同一深色的三个 alpha),不是深浅两套值:
它在**两套主题下都是深色**(模态遮罩语义)。而 WebUI 的 `--bg-scrim` 浅色是**白**
(原话「浅色下用白把花哨的图案洗淡」)—— 壁纸遮盖用 mask 就是**反方向**:
浅色主题下把预设压暗,而 WebUI 是把它洗淡。
## 改法
- 新增 `Theme.wallpaperScrim = $r('sys.color.ohos_id_color_background')`(页面底色系:
浅色白、深色近黑,**自动换向**,与"朝底色淡化"同一意图);预设档与图片档的遮盖层都用它。
- `Theme.overlay`(mask)**只留给模态弹层**(那里语义确实是压暗背后)。
- 不复用 `pageBg` 的原因写进注释:页面底在背景开启时会被换成**透明**
(`bgActive ? Color.Transparent : Theme.pageBg`),而遮盖层**永远要一个真实颜色** ——
两个用途生命周期不同,共用一个名字迟早坏一头(这个仓库撞过四次的模式)。
## 判据(从 SDK 读真值再判,不写死结论)
断言「mask 两套主题都深」「页面底色系浅白深黑」「WebUI 的 `--bg-scrim` 浅色是白」,
再落到代码:两处遮盖层必须用 `wallpaperScrim`、弹层仍用 `overlay`、两个令牌不许混用。
**这样"令牌选错方向"以后不能靠记性避免。**
变异:遮盖退回 mask → 红 1 条;只改一层 → 红 2 条。
## 文档
§7.17b-2 记这次读数(表格 + 两张表怎么读 + 为什么不复用 pageBg + 变异结果);
§7.12 有意差异表加一行(遮盖色令牌:两个语义两个令牌,"不允许混用")。
## 验证
`hvigorw assembleHap` BUILD SUCCESSFUL;`npm test` 退出码 0
(12 个判据文件全绿 + vitest 258/258;harmony-appearance 23 → 24 条)。
This commit is contained in:
@ -380,7 +380,12 @@ test('★ 页面真的把背景画出来了(这一条是补漏:P4 第一版
|
||||
assert.match(main, /Image\(this\.wallpaperImage\)/, '图片档要真的把图渲染出来');
|
||||
assert.match(main, /\.objectFit\(ImageFit\.Cover\)/, '图片要铺满(不是拉伸变形或留白)');
|
||||
// 压暗用系统遮罩色 + 服务端浓度
|
||||
assert.match(main, /\.backgroundColor\(Theme\.overlay\)[\s\S]{0,80}?\.opacity\(this\.bgPlan\.scrim\)/, '压暗层要用系统遮罩色与算出来的浓度');
|
||||
/*
|
||||
* 遮盖层:用**页面底色系**的 `Theme.wallpaperScrim`(不是模态遮罩 mask)——
|
||||
* 浅色主题下 mask 是深色(#99182431),会把预设压暗,而 WebUI 是把预设洗淡(--bg-scrim 是白)。
|
||||
* 这一条与下面那条"遮盖色方向"是同一件事的两个面:这里钉"层在不在、浓度接没接上"。
|
||||
*/
|
||||
assert.match(main, /\.backgroundColor\(Theme\.wallpaperScrim\)[\s\S]{0,80}?\.opacity\(this\.bgPlan\.scrim\)/, '遮盖层要用页面底色系令牌与算出来的浓度');
|
||||
// 背景在主界面这一层:Tabs 之上不该再有不透明的底色把背景盖死
|
||||
assert.match(main, /Stack\(\) \{[\s\S]{0,120}?this\.WallpaperLayer\(\)/, '背景要铺在内容之下(Stack 的底层)');
|
||||
});
|
||||
@ -585,7 +590,7 @@ test('★ 预设档的遮盖:两档同一个浓度(WebUI 的 --bg-dim 不区
|
||||
assert.match(bgStore, /--bg-dim|setProperty\('--bg-dim'/, 'WebUI 要无条件写 --bg-dim(这是"两档都压"的依据)');
|
||||
const main = read('pages/MainPage.ets');
|
||||
// 两档各有一处遮盖层(都用系统遮罩色 + 算出来的浓度)
|
||||
const scrims = [...main.matchAll(/\.backgroundColor\(Theme\.overlay\)\s*\n\s*\.opacity\(this\.bgPlan\.scrim\)/g)];
|
||||
const scrims = [...main.matchAll(/\.backgroundColor\(Theme\.wallpaperScrim\)\s*\n\s*\.opacity\(this\.bgPlan\.scrim\)/g)];
|
||||
assert.ok(scrims.length >= 2, `预设档与图片档各要有一层遮盖(实际 ${scrims.length} 处)`);
|
||||
});
|
||||
|
||||
@ -647,3 +652,89 @@ test('★ 主题变化时**我们自己算的值**要跟着重算(pi 的规则
|
||||
const sdk = readFileSync(join(CLT, 'sdk/default/openharmony/ets/api/@ohos.app.ability.EnvironmentCallback.d.ts'), 'utf8');
|
||||
assert.match(sdk, /onConfigurationUpdated\(config: Configuration\): void/, 'SDK 里回调是 onConfigurationUpdated(别写错名字)');
|
||||
});
|
||||
|
||||
// ───────── 遮盖色方向:从 SDK 两张表读出真值再判(pi 2026-09-14 的方向性疑问) ─────────
|
||||
|
||||
/** 从 SDK 读出 `sys.color.ohos_id_color_*` 的真实值(名字→id 取编译器那张表,id→值取预览器那张) */
|
||||
function sdkSystemColors() {
|
||||
const sysRes = readFileSync(join(CLT, 'sdk/default/openharmony/ets/build-tools/ets-loader/sysResource.js'), 'utf8');
|
||||
const resTxt = readFileSync(join(CLT, 'sdk/default/openharmony/previewer/common/resources/entry/resources.txt'), 'utf8');
|
||||
const name2id = new Map();
|
||||
for (const m of sysRes.matchAll(/'?(ohos_id_color_[a-z_]+)'?:\s*(\d+)/g)) {
|
||||
if (!name2id.has(m[1])) name2id.set(m[1], Number(m[2]));
|
||||
}
|
||||
const id2val = new Map();
|
||||
for (const m of resTxt.matchAll(/id:(\d+),\s*'([^']*)'/g)) {
|
||||
const id = Number(m[1]);
|
||||
if (!id2val.has(id)) id2val.set(id, m[2]);
|
||||
}
|
||||
const out = {};
|
||||
for (const [name, id] of name2id) if (id2val.has(id)) out[name] = id2val.get(id);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** '#AARRGGBB' → 亮度(0=黑 1=白);只用于判"深还是浅" */
|
||||
function luminanceOf(argb) {
|
||||
const r = parseInt(argb.slice(3, 5), 16) / 255;
|
||||
const g = parseInt(argb.slice(5, 7), 16) / 255;
|
||||
const b = parseInt(argb.slice(7, 9), 16) / 255;
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
}
|
||||
|
||||
test('★ 遮盖色方向:`mask_*` 两套主题下都是**深色**(模态遮罩),壁纸遮盖必须用**页面底色系**', () => {
|
||||
/*
|
||||
* pi 的疑问原话:「系统那三个 mask —— 名字里的 light/regular/thick 是**浓度档**
|
||||
* (同一个色的三个 alpha),不是深浅主题的两套值。它们的用途是**模态遮罩**(弹层背后压暗),
|
||||
* 所以两套主题下通常都是深色。如果预设/图片的遮盖层用 mask 色,**浅色主题下会把预设压暗,
|
||||
* 而 WebUI 是把预设洗淡**:方向相反,而且这是"机制上确定不同",不是观感。」
|
||||
*
|
||||
* 他让我先把值读出来再定 —— 这里就是那次读数,做成判据(免得以后凭记忆选令牌)。
|
||||
*/
|
||||
let colors;
|
||||
try {
|
||||
colors = sdkSystemColors();
|
||||
} catch (e) {
|
||||
assert.fail(`读不到 SDK 的系统色表(这条判据无从判起):${e.message}`);
|
||||
}
|
||||
const maskRegular = colors['ohos_id_color_mask_regular'];
|
||||
const maskDark = colors['ohos_id_color_mask_regular_dark'];
|
||||
const bg = colors['ohos_id_color_background'];
|
||||
const bgDark = colors['ohos_id_color_background_dark'];
|
||||
assert.ok(maskRegular && maskDark && bg && bgDark, '系统色表里这几个令牌都要有值');
|
||||
|
||||
// 事实一:mask 在浅色主题下也是深色(#99182431)—— 所以它是模态遮罩语义
|
||||
assert.ok(luminanceOf(maskRegular) < 0.2,
|
||||
`mask_regular 在浅色主题下应当是深色(实测 ${maskRegular})—— 若是浅色,这条判据的前提要重写`);
|
||||
assert.ok(luminanceOf(maskDark) < 0.2, `mask 深色主题下也应当是深色(实测 ${maskDark})`);
|
||||
|
||||
// 事实二:页面底色系随主题换向(浅色白、深色近黑)—— 这才是"朝底色淡化"
|
||||
assert.ok(luminanceOf(bg) > 0.8, `ohos_id_color_background 浅色主题下应当是白(实测 ${bg})`);
|
||||
assert.ok(luminanceOf(bgDark) < 0.2, `ohos_id_color_background_dark 应当近黑(实测 ${bgDark})`);
|
||||
|
||||
// 事实三:WebUI 的遮罩方向是"朝底色淡化"(浅色白、深色黑)—— 与页面底色系同向、与 mask 反向
|
||||
const webCss = readFileSync(join(ROOT, 'client/electron/src/index.css'), 'utf8');
|
||||
const scrimLight = /--bg-scrim:\s*(\d+)\s+(\d+)\s+(\d+);/.exec(webCss);
|
||||
assert.ok(scrimLight, 'CSS 里要有 --bg-scrim');
|
||||
assert.deepEqual([scrimLight[1], scrimLight[2], scrimLight[3]], ['255', '255', '255'],
|
||||
'WebUI 浅色下的遮罩是**白**(把图案洗淡);这是"必须用页面底色系"的依据');
|
||||
|
||||
// 结论落到代码:壁纸遮盖用页面底色系令牌,且**不是** mask
|
||||
const theme = readFileSync(join(HARMONY_ETS, 'common/Theme.ets'), 'utf8');
|
||||
assert.match(theme, /static readonly wallpaperScrim: Resource = \$r\('sys\.color\.ohos_id_color_background'\)/,
|
||||
'壁纸遮盖色要用页面底色系(ohos_id_color_background)');
|
||||
assert.match(theme, /static readonly overlay: Resource = \$r\('sys\.color\.ohos_id_color_mask_regular'\)/,
|
||||
'overlay(模态遮罩)保持 mask');
|
||||
const main = read('pages/MainPage.ets');
|
||||
const scrims = [...main.matchAll(/\.backgroundColor\(Theme\.(\w+)\)\s*\n\s*\.opacity\(this\.bgPlan\.scrim\)/g)];
|
||||
assert.equal(scrims.length, 2, '预设档与图片档各一层遮盖');
|
||||
for (const s of scrims) {
|
||||
assert.equal(s[1], 'wallpaperScrim',
|
||||
'壁纸遮盖层的颜色必须用 wallpaperScrim(页面底色系)。用 mask 会在浅色主题下把预设压暗,与 WebUI 反向');
|
||||
}
|
||||
// 两个语义不许共用一个令牌(这个仓库撞过四次的那个模式)
|
||||
assert.notEqual('wallpaperScrim', 'overlay');
|
||||
// 模态弹层仍然用 mask(那里的语义确实是"压暗背后")
|
||||
const settings = read('pages/SettingsPage.ets');
|
||||
assert.match(settings, /Theme\.overlay/, '自绘弹层的遮罩仍然用 mask(那里的语义是压暗背后)');
|
||||
assert.ok(!/wallpaperScrim/.test(settings), '弹层不该用壁纸遮盖色(两个语义别混)');
|
||||
});
|
||||
|
||||
@ -62,6 +62,34 @@ export class Theme {
|
||||
*/
|
||||
static readonly overlay: Resource = $r('sys.color.ohos_id_color_mask_regular');
|
||||
|
||||
/**
|
||||
* 壁纸遮盖层的颜色 —— **不是** `overlay`(那是模态遮罩),两者语义不同。
|
||||
*
|
||||
* pi 2026-09-14 提出的方向性疑问,我按他说的去 SDK 里把值读出来了
|
||||
* (`ets/build-tools/ets-loader/sysResource.js` 给 名字→id,
|
||||
* `previewer/common/resources/entry/resources.txt` 给 id→值,两张表交叉验证):
|
||||
*
|
||||
* | 令牌 | 浅色主题 | 深色主题 |
|
||||
* |---|---|---|
|
||||
* | `ohos_id_color_mask_regular`(= `overlay`) | `#99182431` **深蓝灰** | `#b2000000` 黑 |
|
||||
* | `ohos_id_color_background` | `#ffffffff` **白** | `#ff18181a` 近黑 |
|
||||
*
|
||||
* 也就是说 **`mask_*` 在两套主题下都是深色**(它的 light/regular/thick 是**浓度档**,
|
||||
* 不是深浅两套值),用途是**模态遮罩**(弹层背后压暗)。
|
||||
* 而 WebUI 的 `--bg-scrim` 在 `:root` 是**白**、`.dark` 才是黑,注释原话是
|
||||
* 「浅色下用白把花哨的图案洗淡,深色下用黑压暗」—— 它做的是"**朝页面底色淡化**"。
|
||||
*
|
||||
* 所以壁纸遮盖若用 `mask`:**浅色主题下会把预设压暗,而 WebUI 是把它洗淡 —— 方向相反**。
|
||||
* 这是"机制上确定不同",不是观感。改用**页面底色系**:那才是"朝底色淡化"的系统对应物,
|
||||
* 浅色=白底方向、深色=深底方向,自动换向,与 WebUI 是同一个意图。
|
||||
*
|
||||
* ⚠️ 为什么不干脆复用 `pageBg`(值一样是 `ohos_id_color_background`):
|
||||
* 页面底在背景开启时会被换成语义上的**透明**(`bgActive ? Color.Transparent : Theme.pageBg`),
|
||||
* 而遮盖层**永远需要一个真实颜色**。两个用途的生命周期不同,共用一个名字迟早坏一头
|
||||
* —— 这正是这个仓库撞过四次的模式(`text-white` vs `bg-white`、`--c-*` vs `--s-*`)。
|
||||
*/
|
||||
static readonly wallpaperScrim: Resource = $r('sys.color.ohos_id_color_background');
|
||||
|
||||
/**
|
||||
* 导航/浮层的材质档次。**不再有 `#B8FFFFFF` / `#B80F172A` 这种手写玻璃 alpha** ——
|
||||
* 那两个值等于"我们替系统猜了深色该怎么做",与"用系统方案"直接冲突;
|
||||
|
||||
@ -1652,7 +1652,8 @@ struct MainPage {
|
||||
*/
|
||||
Column()
|
||||
.width('100%').height('100%')
|
||||
.backgroundColor(Theme.overlay)
|
||||
// 遮盖色 = **页面底色系**(朝底色淡化),不是模态遮罩 mask(浅色下那会压暗,方向相反)
|
||||
.backgroundColor(Theme.wallpaperScrim)
|
||||
.opacity(this.bgPlan.scrim)
|
||||
}
|
||||
.width('100%').height('100%')
|
||||
@ -1664,7 +1665,8 @@ struct MainPage {
|
||||
// 压暗用**系统遮罩色** + 服务端给的浓度:换向(浅色洗白/深色压黑)由系统负责
|
||||
Column()
|
||||
.width('100%').height('100%')
|
||||
.backgroundColor(Theme.overlay)
|
||||
// 遮盖色 = **页面底色系**(朝底色淡化),不是模态遮罩 mask(浅色下那会压暗,方向相反)
|
||||
.backgroundColor(Theme.wallpaperScrim)
|
||||
.opacity(this.bgPlan.scrim)
|
||||
}
|
||||
.width('100%').height('100%')
|
||||
|
||||
@ -517,6 +517,7 @@ deb 也不必从 targets 里摘。已写进 `client/electron/BUILD.md`(含排
|
||||
| 遮罩 | 自声明 `--bg-scrim` + `--bg-dim` 两段式 | 系统 `sys.color.ohos_id_color_mask_regular` | 遮罩要随主题换向(浅色洗白/深色压黑),这件事系统已经做了 |
|
||||
| **品牌色** | `--c-blue-600: 37 99 235` | `Theme.accent = '#2563EB'` | **不允许差异** —— 两个客户端是同一个产品 |
|
||||
| **本地外观缓存的键** | 全局常量 `agentmail.background` | **按账号**:`appearance.<accountId>` | **鸿蒙是对的,不许为"对齐"退回全局键** —— 全局键的后果是切到服务端没有记录的账号时,`saved=false` 分支会把**上一个账号的外观** push 上去(新账号"继承"了外观,而且写进了服务端)。pi 2026-09-14 确认这条记在 WebUI 侧为开项(换键,或至少在把继承来的值当"本地的"推给从未有记录的账号前停一下) |
|
||||
| **遮盖色的令牌** | `--bg-scrim`(浅色白 / 深色黑,"朝底色淡化") | `Theme.wallpaperScrim` = `sys.color.ohos_id_color_background`(同向);`Theme.overlay` = mask **只用于模态弹层** | **不允许混用** —— mask 两套主题下都是深色(浅色 `#99182431`),拿它当壁纸遮盖会在浅色主题下压暗(与 WebUI 反向)。两个语义两个令牌,理由与实测值见 §7.17b-2 |
|
||||
| **遮罩浓度的默认值** | 两套:store 的 `dim=24/blur=8` 与 `lib/appearance.ts` 的 `clamp(...,12,4)` | 12 / 4(只有一套) | 服务端**缺字段**时真正落地的是 `clamp` 的默认值,所以按 12/4 对齐;WebUI 那两套值迟早要统一(pi 记在他那边) |
|
||||
|
||||
**关于 `overlayColor` / `overlayAlpha` 消失**(pi 要求把删除理由记在这里,否则下一个人会当成漏改补回来):
|
||||
@ -826,6 +827,40 @@ SDK 锚点(免得后人凭记忆写):回调接口是 `@ohos.app.ability.En
|
||||
踩过两个编译错:`Configuration.colorMode` 是**枚举 | undefined**,字段写成 `number` 直接报错;
|
||||
`ApplicationContext.on('environment')` 返回的是 **number 型 callbackId**(不是 void)。
|
||||
|
||||
### 7.17b-2 遮盖色的**方向**:模态遮罩 ≠ 壁纸遮盖(pi 的方向性疑问,按实测改)
|
||||
|
||||
pi 的疑问:「系统那三个 `mask_*` —— light/regular/thick 是**浓度档**(同一个色的三个 alpha),
|
||||
不是深浅两套值;用途是**模态遮罩**(弹层背后压暗),所以两套主题下通常都是深色。
|
||||
如果壁纸遮盖用 mask 色,**浅色主题下会把预设压暗,而 WebUI 是把预设洗淡**:方向相反。」
|
||||
|
||||
他让我先把值读出来再定。读数方式(两张 SDK 表交叉验证,不靠记忆):
|
||||
`ets/build-tools/ets-loader/sysResource.js` 给**名字→id**,
|
||||
`previewer/common/resources/entry/resources.txt` 给 **id→值**:
|
||||
|
||||
| 令牌 | 浅色主题 | 深色主题 |
|
||||
|---|---|---|
|
||||
| `ohos_id_color_mask_regular`(= 原 `Theme.overlay`) | `#99182431` **深蓝灰** | `#b2000000` 黑 |
|
||||
| `ohos_id_color_mask_thick` / `_light` | `#cc182431` / `#66182431` 深 | 同为深 |
|
||||
| `ohos_id_color_background` | `#ffffffff` **白** | `#ff18181a` 近黑 |
|
||||
|
||||
⇒ **pi 是对的,而且这是"机制上确定不同"**:mask 在两套主题下都是深色(它是模态遮罩),
|
||||
而 WebUI 的 `--bg-scrim` 浅色是**白**(把花哨的图案洗淡)、深色才是黑。
|
||||
壁纸遮盖用 mask = 浅色下把预设压暗,方向与 WebUI 相反。
|
||||
|
||||
**改法**:新增 `Theme.wallpaperScrim = $r('sys.color.ohos_id_color_background')`
|
||||
(页面底色系:浅色白、深色近黑,自动换向,与"朝底色淡化"同一意图),
|
||||
壁纸两档的遮盖层都改用它;`Theme.overlay`(mask)**只留给模态弹层**(那里的语义确实是压暗背后)。
|
||||
|
||||
**为什么不再复用 `pageBg`**(值一样是 `ohos_id_color_background`):页面底在背景开启时会被换成
|
||||
语义上的**透明**(`bgActive ? Color.Transparent : Theme.pageBg`),而遮盖层**永远要一个真实颜色**。
|
||||
两个用途生命周期不同,共用一个名字迟早坏一头 —— 就是这个仓库撞过四次的模式
|
||||
(`text-white` vs `bg-white`、`--c-*` vs `--s-*`、掩码 vs 遮罩)。
|
||||
|
||||
**判据**:从 SDK 两张表读出真值,断言「mask 两套主题都深」「页面底色系浅白深黑」
|
||||
「WebUI 的 `--bg-scrim` 浅色是白」,再落到代码(两处遮盖层都必须用 `wallpaperScrim`、
|
||||
弹层仍用 `overlay`)。变异:遮盖退回 mask → 红 1 条;只改一层 → 红 2 条。
|
||||
**这样"令牌选错方向"以后不能再靠记性避免。**
|
||||
|
||||
### 7.17c 手写色清册升级成**跨文件按类扫**(pi 建议)
|
||||
|
||||
原来的 A2 只保护 `Theme.ets`;而 `Wallpaper.ts` 也有手写色(14 个预设色)。
|
||||
|
||||
Reference in New Issue
Block a user