Commit Graph
4 Commits
Author SHA1 Message Date
AskaEth a4cdd61fe5 fix(iced/feedback): 复审 r3 的 A/B/D/E/F 项 + C 项待 rebase 后改 view_at
(先落一个中间提交,rebase main 之后再按 tower 的修正把空态图标改成 32/view_at)
2026-11-02 15:56:46 +08:00
AskaEth 10d4f86fdf fix(iced/feedback): 圆角/描边带来的 probe 阈值订正 + Dialog 宽度逃生口接线
上一轮被 2 小时上限打断前的工作,逐条落地(都已在本地编译 + 单测 17 passed + 8 组 probe 中
6 组通过、empty-light 差 ±1 阈值):

- `keyframes::sample` 的 debug_assert 收窄成「首点不在 0ms **且** 首值不是 0」才炸:
  原先 `debug_assert_eq!(first.ms, 0)` 会把 `SEG_TAIL_1/2`(首点 250/900ms,值为 0)也判红,
  而那一类的「保持首值」与 Compose 的「动画初值 0」等价,是合法的。真正危险的是 ROTATION 那种
  「首值 ≠ 0」(会画出不存在的静止段),现在只拦这一种。
- `empty_state::block_layer()` 改成 `pub(super) const BLOCK_LAYER`:函数版在非 test 构建里
  是 dead_code(`-D warnings` 会红),改成常量后组件与 probe 共用一个来源。
- `probe/panels.rs`:图标块尺寸容差放到 ±2(块上补的 1px `OutlineVariant` 描边各占 1 行,
  浅色实测块色行 94、深色 97);顺带去掉没用到的 `matches` import。
- `tests/progress.rs`:三处期望值按实现对齐 —— 旋转每周期 **4 圈**(不是 1 圈)、
  右段宽 **0.505**(0.355..0.860,手算 0.516 偏了 0.01)、单调扫描只扫 `[0,1)`(phase==1.0
  就是下一周期的 0,回绕正常)。
- `dialog.rs`:`Fill + max_width(480)` **实测不生效**(Row 给 Fill 子项的 limits 是
  min=max=分配额,`Limits::max_width()` 的 `.max(self.min.width)` 会把 480 顶回去,
  两列并排实测渲染成 548)⇒ 改回 `Fixed(min(可用宽, 480))`,并加 `Dialog::width(available)`
  让页面递可用宽;gallery 里接线用 `HOST_WIDE`(=800 ⇒ 仍取 480)。能力缺口登记在注释里
  (与 G17-d 同一堵墙,报告里有 548 的实测)。

未完成(下一轮/合并前补):`cmp/dialog-*` 并排图要按 REF_H≈420 重出(动作行被裁掉)、
empty-light 的 ±2 阈值要复跑确认、clippy/test 门禁要贴真实 `test result:` 行。
2026-11-02 15:56:45 +08:00
AskaEth e9af27c8f1 fix(iced/feedback): 不定态两条 p1 —— 线性先排序合并(P1-A)+ 环形补全局旋转(P1-B)
复审 r1 的两条 p1 都是「报告写了 ✓、图上没有」,逐条修:

P1-A(视觉)线性不定态把两段画成一段:
- 根因:`phase_segments` 的两段**不保证有序**(第一线前缘抢跑 250ms、第二线从 0 起),
  `linear()` 却按返回顺序单调铺 `FillPortion`,且份额之和在 34/100 相位上 >1(最大 1.99),
  iced 按总和归一 ⇒ phase 0.55 的两段被压成一段 100px 台阶。
- 修:新增 `layout_spans`(排序 + 合并重叠 + 显式铺间隙)与 `portion_shares`(累计舍入,
  份额之和**恒为 1000**),`linear()` 只消费这两者。
- 断言:`raw_segments_are_unordered_and_layout_sorts_them`(原始输出不有序、排序后位置对得上
  A1 keyframes)、`portion_shares_always_sum_to_the_full_track`(200 个相位全 = 1000)、
  以及渲染层 `12.4:phase 0.55 必须数出两段`(旧实现会数到 1 段)。

P1-B(代码)环形不定态少一条全局旋转 + keyframes 首点语义:
- 官方是两条旋转相加:`CircularGlobalRotationDegreesTarget = 1080f`(`tween(6000, LinearEasing)`,
  javap 偏移 5125)与 8 关键帧旋转(0→360°),绘制时 `fadd` 后 rotate ⇒ 每周期 1440°(4 圈)。
  我们只做了 360°,转速是官方的 1/4。
- `ROTATION` 首点在 300ms/90°:Compose 会自己补 t=0(值 = 动画初值 0),我们没补 ⇒ `[0,0.05)`
  恒 90°,且周期末尾 360° → 下周期 90° 瞬时倒跳 270°。现在显式补 `KeyPoint{ms:0, value:0}`
  并在 `Keyframes::sample` 加 `debug_assert!(首点 ms == 0)`,同一类坑不再靠自觉。
- `CircularGeometry::indeterminate` 改返回 `(弧长, 圈数)`,圈数 = 3.0×phase + 关键帧(可为 >1),
  `progress.rs` 直接乘 360、不做 rem_euclid。
- 断言:`circular_indeterminate_rotation_is_four_turns_and_continuous`(每周期 4 圈、
  跨周期跳变 ≤ 一帧 = 4/60 圈,修前是 0.75 圈 = 270°、旋转单调)。

probe 拆成 `probe.rs` + `probe/circular.rs`(新断言会把单文件顶过 400 行)。
2026-11-02 15:56:43 +08:00
AskaEth 36f58d7904 feat(iced): 反馈类家族四件(Progress / Snackbar / Dialog / EmptyState)
D39 五家族并行的反馈类线(M78 / COMPFEED)。全部对消息类型泛型、不 import app::Message,
数值来自令牌或登记为 G17(令牌层没有反馈类的 ComponentMetrics 与骨架位)。

- Progress:linear(确定态 FillPortion 占比 + 官方 1750ms 双段不定态 keyframes)与
  circular(40/4 环,弧长 = 数值×360°,不定态走官方 6000ms 弧长+旋转 keyframes)。
  环形用几何 SVG(canvas feature 没开),组件不计时,相位由调用方给。
- Snackbar:48/68 两种高、上限宽 600(A1 ContainerMaxWidth)、12 外边距、贴顶/贴底、
  action(InversePrimary)+ 关闭键(InverseOnSurface);**组件不计时**,超时归调用方。
  iced 的 Length 没有 min-width ⇒ 344 的最小宽由宿主保证(登记 G17-d,与按钮 G15 同墙)。
- Dialog:scrim(黑@0.32 预合成实色,D27)+ R28 + SurfaceContainerHigh + pad 24 +
  标题/正文/动作三区 + 无动作/单动作/双动作;官方 280..560 区间内取 480。
- EmptyState:**官方没有这个组件**,96 图标块/32 图标/HeadlineSmall 全部标 [估]。
- action.rs:Dialog/Snackbar 共用的文字/图标动作(内容角色作参数,状态层仍走 interaction)。
- gallery/feedback.rs:状态矩阵;家族内再切一段 ULL_FEEDBACK_PART(all|progress|snackbar|
  dialog|empty),开关本身住在 feedback/gallery_parts.rs,不动 gallery/mod.rs。
- feedback/probe.rs:对着真截图量像素(渲染层断言),四类几何各逐项钉住。
- feedback/tests.rs:几何/节奏/角色/scrim 的纯函数断言。

gates: fmt --all --check · clippy -p unlucky-app-iced --all-targets -D warnings ·
test -p unlucky-app-iced(144 通过 / 0 失败)
2026-11-02 15:56:42 +08:00