feat(app-iced): 页面切换按导航深度定向 + 模态缩放淡入(M256 MOTION1)

- transition.rs:唯一一张动效表。同级换页走水平(±12 / 旧页 ∓8)、进深层走纵向
  (新页 +16 上浮 / 旧页 -8),进腿 medium2/medium1(300/250),退腿 short4→medium1(更短),
  进用 Standard、退用 StandardAccelerate。幅度全部取自 Space 令牌。
- pump.rs:Slot 三互斥槽 → Kind(Boot/Peer{forward}/Push/Pop)+ 两腿轨道;新增模态状态机
  (Opening/Open/Closing,展开后不占帧,退场走完交回一次 take_modal_closed)。
- components/motion/zoom.rs:绕中心缩放的自绘控件(renderer.with_transformation,
  tiny-skia 与 wgpu 都实现了,文字也真的跟着缩放);scale==1.0 时不套变换 ⇒ 出图基线不变。
- pages/mod.rs:page_with_settings_transition(ui, current, previous, …) 叠
  stack![opaque(旧页@退场位移), 新页@进场位移];旧函数只剩一句委托(blast radius 不变)。
- App.previous_view:换页时用 std::mem::replace **移动**旧模型(冻结快照),过渡结束当拍
  置 None(不随换页次数增长)。
- 模态:逻辑状态当拍关(state.dialogs 立刻空),画面多留 150ms;退场期间弹窗消息被闸门吞掉。
- platform/motion.rs:系统「减少动效」三态探针(Windows=SystemParametersInfoW,
  Linux/macOS=子进程+300ms 超时),OnceLock 缓存;Unknown **不降级**(探针失败不静默关动效)。
- MotionScale::HALF 语义核清并写进 design 文档:是**时长减半**(更快),不是半速。
This commit is contained in:
AskaEth committed 2026-11-12 10:50:02 +08:00
1 parent 5a182e80de
commit b1c09c4c91
21 files changed
+2168 -658

No files matched your search

+20
View File
@@ -8,6 +8,15 @@
//!
//! **CPU / 减少动效路径**:把 [`MotionScale`] 设成 [`MotionScale::NONE`],
//! 所有时长归零、`Easing::sample` 仍返回 0/1 端值(适配层按 `t >= 1` 直接落终态)。
//!
//! ## [`MotionScale::HALF`] 是什么(读实现的结论,不是注释的措辞)
//!
//! `MotionScale` 只有一个 `factor`,`ms(token) = token.ms() * factor`(见 `spring` 模块的
//! `motion_scale_scales_or_kills_duration`),所以 `HALF` 的语义是**时长减半**(同一段位移在
//! 一半的时间里走完 ⇒ 观感上**更快**,不是"半速")。`spring_ms` 同理:收敛时间减半。
//!
//! `spring.rs` 里 `HALF` 的行内注释写作「半速」,那是**措辞错误**(MOTION1 核清):本行文档是
//! 事实口径,改 `spring.rs` 的注释不在 M256 的 scope 内,已作为 finding 报给 tower。
mod spring;
@@ -19,6 +28,17 @@ pub use spring::{
SPRING_STANDARD_SPATIAL_SLOW,
};
/// 模态(对话框 / 危险确认)**进场**的起始缩放:`0.96 → 1.0`。
///
/// 出处:`DevDocs/PlanDoc/14-motion-and-animation.md` §3 的 A3 行——「遮罩淡入 + 卡片
/// scale 0.96→1(**不弹跳**)」。**退场走同一条线反向**(1.0 → 0.96),所以只需要这一个常量。
///
/// 为什么不是 0.8 或 0.9:0.9 以下的缩放会让卡片里的正文在动画期间小到读不清(对话框是
/// 「必须读」的界面,不是装饰);0.96 是 M3 里 dialog 的形变幅度口径,也让「它在放大」这件事
/// 恰好可察觉而不夸张。**不弹跳**:曲线只取单调段(`*Decelerate` / `*Accelerate`),
/// 弹簧类曲线不用于模态。
pub const DIALOG_ENTER_SCALE: f32 = 0.96;
/// 动效时长档位(M3 动效令牌,单位毫秒)。
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DurationToken {