跨端: 顶栏不再自己铺白条 + 日历改左右两栏 + 常驻窗格动画真的会播(用户三处实测指出)
用户三条反馈,逐条对应:
① 「底栏数字为什么显示在图标下面?」
WebUI 的徽标是 `absolute top-1 right-[22%]`(脱离文档流、浮在图标右上角),
我写成了 `Column` 的第三个子节点 ⇒ 参与竖向布局、掉到文字下面。
改用 `Stack({ alignContent: Alignment.TopEnd })` 锚在**图标**上。
(顺带撞了 skill 里明写的坑:Stack 没有 `.justifyContent()`。)
② 「一个横着过去的白条,我真的服了」/「期望:融进背景」
WebUI 的顶栏**自身没有底色** —— 只有 `border-b border-gray-200`
(`ContactPanel.tsx:64`、`CommTabs.tsx:40`、`CalendarView.tsx:295`),
底色由所在面板给;壁纸开启时那层面板是玻璃色(`index.css:876`)。
鸿蒙三个窗格顶栏写死了 `Theme.surface`(实心白)⇒ 无论壁纸开没开,
顶上都是一条不通明白带。改成与**页面底**同一口径
(`bgActive ? Transparent : surface`)+ 补下边框。
③ 「日历页面和webui布局完全不同」
WebUI 是**左右两栏**(`CalendarView.tsx:452-457`):左 `flex-1` 网格、
右 `400px` 常驻面板(日程 / 编辑器 / 小时网格三态互斥)。
鸿蒙原来是**单栏竖堆**。重搭为两栏,`paneWide` 由 `.onAreaChange`
量本页**自己的**宽度(不是屏幕宽度 —— 宽屏下这一页已被侧栏占掉一截);
编辑器改占右栏位置(不再整页盖掉正在看的那个月)。
④ 「最严重的动画问题你一点也不该改」
日历是**常驻挂载**(`visibility` 控制,因为它里面 today 要随时间重算、
也要保住"正在看哪个月"),而 `.transition()` 只在**挂载/卸载**时触发
(SDK 原话 \"when it **appears and disappears**\")⇒ 挂在它上面的
`.transition(paneRiseIn())` **一帧也不会播**,切过去是硬弹。
WebUI 踩过同一个坑并把错法写进了 `index.css:1305-1320`
(「只挂了类,却没让触发窗口出现 ⇒ 类挂着、动画永远不播」),
它的解法是 `html.view-switch` 重放窗口。ArkUI 对应物是
`animateTo` + 显式 `calPaneIn` 属性(`opacity` + `translate`)。
★ reset 必须在 `animateTo` **外**:写进回调里会与同帧的 1 相抵,
渲染层只看得见最终值 ⇒ 动画退化成一个瞬移。
顺带修:
· 宽屏侧栏 = 3 项(通信/日历/**联系**)+ 底部一簇(头像/主题/退出),
与底栏的四项(含「我的」)**不是同一份清单** —— WebUI 的 Sidebar 与
NarrowNav 本就不同(`Sidebar.tsx:26-44` vs `NarrowNav.tsx:37-40`+143)。
新增 `NAV_SIDEBAR_ITEMS` / `ME_PANE_INDEX` / `SIDEBAR_ITEM_*`。
· 退出登录抽成 `api/Logout.ets` 的 `performLogout()`:侧栏底簇与「我的」页
两个入口必须做同一件事(尤其"先注销推送 token"那一步),复制一份就会不一致。
· 徽标 `'plain'` 档底色:WebUI 是石板灰 `--c-chrome-600`(#475569),
我写成与未读共用红色 ⇒ 「联系」的徽标看起来像"有未读"。
· 主题快捷开关(侧栏底簇):对齐 `ThemeToggleButton` —— 从 `system` 翻转时
落到**当前生效值的反面**(不是回 system;那可能毫无变化、让按钮看起来坏了)。
· 「浓度」→「压暗」+ 数值带单位(原先屏上印 `56.000000`;WebUI 是 `suffix="%"`)。
判据(8 个套件全绿:logic 28 / nav 18 / widescreen 7 / window 9 /
arkts 5 / contacts 5 / calendar 30 / system-api 5):
· `harmony-widescreen` ② 重写:**回读 `Sidebar.tsx` 数 `short:` 的个数**
要求鸿蒙同数,并断言底部一簇三键真的被调用(`this.onToggleTheme()` ——
第一版写成 `/onToggleTheme/`,变异测试当场证明它不咬:属性**声明**还在,
正则照样匹上)。新增 ⑧:三档色调各自底色,期望值从 `--c-chrome-600` 读出。
· `harmony-nav` 动画条重写:改判**机制真的存在且被驱动**
(旧断言 `.visibility(...).transition(...)` 锁的正是那个 bug ——
判据引自己写的注释当依据,就会把错误锁死)。新增 reset-在-animateTo-外
这条断言(否则动画退化成瞬移)。
· `harmony-nav` 设备条:`navItemsOf` 的宽屏过滤从"左边缘靠左 1/6"
改成"**整个盒子在侧栏轨道内**" —— 旧条件把日历网格的格子
(实测 `[229,511][366,794]`)也当成导航项,一屏数出 11~12 个。
新增 `navRailItemsOf`:导航轨贴顶、底部簇在屏底,按位置切一刀。
· `harmony-logic` 两处:从 `NAV_ITEMS` / `NAV_SIDEBAR_ITEMS`
**各自的数组**里取 label —— 原先把全文件 `label:` 一网打尽,
得到 7 个(4+3 混在一起),任何一边改对了它都会红。
设备实测(HATriple 三折叠,3184×2232):侧栏 3 项 + 底簇 / 底栏徽标回到
图标右上角 / 日历左右两栏与 WebUI 并排同构。
server/go.mod:补 2da38bb 漏提交的 lunar-go 依赖。
This commit is contained in:
@ -911,6 +911,58 @@ rc (原返回处):blind/unreadable/baseline-unrunnable|unknown 排第一
|
||||
| ② 让自检断言 `staticDetail` **变量**内容完整 | 只删掉那句 `console.log` | **4b 照样报 ok**,而真实输出里播报段 **0 次** |
|
||||
| ③ 断言源码里有 `${staticDetail}` 这个形状 | 同上 | **仍报 ok** —— 因为**锚点写在这段自检自己的注释里**,`includes` 命中的是注释 |
|
||||
| ④ 剥注释后再数 `+ staticDetail);` 的命中 | 删 print | **4b 红 ✓**("可执行代码里没有任何一处把 `staticDetail` 拼进输出") |
|
||||
| ⑤ **同一处改成"记录那次调用真的送了什么"(4c)** | 删 print | **4c 红 ✓** |
|
||||
| ⑤ | **把 print 包进恒假条件**(`if (false)` / `while (false)` / `false ? … : 0`) | **4c 红 ✓,而 4b 仍报 ok**(三种写法都实测过) |
|
||||
|
||||
#### ★★ 4b 的漏格:它扫的是**文本**,而"那一跳"是**一次调用**(pi 报,dsh 2026-09-19 复现并修)
|
||||
|
||||
④ 只解决了"print 被删"。但 4b 的证据是**源码里存在那个锚文本** —— 于是**锚文本还在、
|
||||
而那次调用根本不发生**时,它照样报 ok。**pi 报的正是这一格**,我完整跑复现:
|
||||
|
||||
```
|
||||
baseline : 播报段出现 1 次 4b = ok
|
||||
变异体 : 播报段出现 0 次 4b = ok ← 红清单与 baseline **逐条相同**
|
||||
```
|
||||
|
||||
根因是**自检先于打印**:4b 在 `:1613` 跑(`staticDetail` 定义之后、打印之前),
|
||||
打印在 `:3129` ⇒ 它**物理上到不了**那次调用,只能读文本。
|
||||
⇒ **"验了那个形状"与"验了那件事发生"仍然是两件事**(§16.1 那条缝的又一格)。
|
||||
|
||||
**修法(4c)**:不再猜源码,改成**记录这次调用真的往 `console.log` 送了什么** ——
|
||||
锚点落在「**实际发生的那次调用**」上,这是源码文本够不着的东西:
|
||||
|
||||
```js
|
||||
const staticBroadcastSeen = [];
|
||||
{ const realLog = console.log;
|
||||
console.log = (...a) => { staticBroadcastSeen.push(a.join(' ')); realLog(...a); };
|
||||
console.log(`…` + staticDetail);
|
||||
console.log = realLog; }
|
||||
if (!staticBroadcastSeen.some(t => STATIC_ONLY.every(([f, why]) => t.includes(f) && t.includes(why))))
|
||||
reds.push('(自检)4c:…没有真的进 console.log…');
|
||||
```
|
||||
|
||||
实测(完整跑,每次一个变异体):
|
||||
|
||||
| 变异 | 播报段 | 4b | 4c |
|
||||
|---|---|---|---|
|
||||
| 无(对照) | 1 | ok | 不红 ✓(红清单与改前**逐条相同**) |
|
||||
| `if (false)` 包裹 | 0 | **仍 ok** | **红 ✓** |
|
||||
| `while (false)` 包裹 | 0 | **仍 ok** | **红 ✓** |
|
||||
| `false ? … : 0` | 0 | 红 | **红 ✓** |
|
||||
| 删掉 print | 0 | **红 ✓** | **红 ✓**(不回归) |
|
||||
|
||||
★ 两条可复用教训:
|
||||
|
||||
1. **"文本里有" ≠ "那次调用发生了"** —— 只要判据读源码,`if (false)` 就是一个
|
||||
**既保留文本、又取消行为**的通用逃逸。凡"必须真的发生"的那一跳,锚点要落在
|
||||
**运行时观测**上,不能落在源码形状上。
|
||||
2. **自检的位置本身就是判据的一部分**:4b 读的那个值定义在它之前、而**使用**在它之后
|
||||
⇒ 它对"使用"这一跳永远只能读文本。**"自检跑在它守的那件事之前"是一类结构性盲区**,
|
||||
不是这一条的偶然。
|
||||
|
||||
⚠️ 4c **不能**做成 `SELFTESTS` 的一条:快入口 `--only-selftest=<名>` 在
|
||||
`:2503` 就 `process.exit` 了,那条路径**永远到不了** `:3129` 的打印 ⇒
|
||||
它只会"看不见"而**不会红**(把它挂在那里等于又造一个 4b)。
|
||||
|
||||
★ 三条教训(都可复用):
|
||||
|
||||
@ -928,6 +980,8 @@ rc (原返回处):blind/unreadable/baseline-unrunnable|unknown 排第一
|
||||
(Y 变 0 而 X 仍是 6 ⇒ 一眼看得出)。
|
||||
- **每次运行都全表播报** `STATIC_ONLY`(文件 + 原因 + 是否到期**并排**)⇒ 第 2 列有了读者。
|
||||
- **自检 4b** 钉住"那一跳真的存在"(剥注释后数锚点 + 内容完整 + 反空转长度)。
|
||||
- **自检 4c** 钉住"**那一跳真的发生了**"(运行时记录 `console.log` 的实际参数)——
|
||||
4b 管"源码里有",4c 管"调用发生了";**两条合起来才等价于"到达"**。
|
||||
|
||||
★ **通用规则**(本节定稿):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user