Files
Unlucky-Launcher/crates/app-iced/src/app/state/toast_shot.rs
T
AskaEth 97768b7e3f fix(launch): M298 收尾失败不再静默、Toast 接上渲染点
三条提示通道各漏一半,用户才会「启动失败但找不到崩溃日志」:

1) 收尾失败静默不弹:finish() 报错那条出口把 LaunchFinished.session 发成真实
   会话,而它登记的现场走 before_start 写死空串 ⇒ dialog.rs 的并发守卫
   (!finished.session.is_empty() && report.session != finished.session)成立后
   return。改成**会话归属单一来源**:before_start 新增可选 SessionAttribution,
   presenter 的 publish_before_start 把它写进报告后**返回同一个值**给 DTO;
   两处不可能再各写一遍。守卫原样保留(A 场的现场不许解释 B 场,有用例钉住)。

2) Toast 只 push 不渲染:新增 app/view/toast.rs 覆盖层(MD3E 胶囊 =
   ShapeScale::Full,底部居中,InverseSurface 底),接在页面树之上、模态之下;
   过期仍走 clock.rs 的 expire;进/出过渡复用模态那一对腿(motion::modal_spec /
   modal_scale / scaled),时间轴在 update 侧由 state/toast.rs 采样,关掉动效时
   恒为终值(出图可复现)。两个拷贝路径补上 view_dirty(推了不置脏要等下一次事件)。

3) 三个贴线文件先拆再改(纯搬移 + pub use 保路径,机器核对:搬出的 14 个函数体
   逐行相同):crash_report.rs 394→318(+context.rs / slot.rs)、
   host/launch.rs 399→233(+build.rs)、app/dialog.rs 390→178(+model.rs)。

证据:DevDocs/artifacts/m298/toast-capsule.png(--screenshot + ULL_TOAST_FIXTURE,
图上可见「游戏崩溃 · 12.0 秒」胶囊)。
2026-11-13 13:18:11 +08:00

49 lines
1.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 出图取证用的 Toast 夹具(`ULL_TOAST_FIXTURE`;产品路径零影响)。
//!
//! # 它解决什么
//!
//! M298 的交付图要证明「提示真的画在窗口底部」,而产品路径的 toast 由事件推出来
//! (安装取消 / 启动收尾 / 复制成功),截图通道在第 3 帧就出图:等不到那条事件。
//! 处理方式与 `mods_shot` / `saves_shot` 一致——**状态注入**,注在「快照 → 页面模型」之前,
//! 于是覆盖层、胶囊几何、i18n 文案走的都是产品代码。
//!
//! # 边界(不要把它读成产品能力)
//!
//! - 只在环境变量存在时生效(`ULL_TOAST_FIXTURE` 非空且不为 `0`);
//! - 推的是**一条真实形状的提示**:文案由产品函数 `launch_toast` 按**生效语言**现求,
//! 不是夹具里写死的一句中文;
//! - 剩余寿命走 `ToastCenter` 的默认 TTL(4 s),过期仍由 `app/update/clock.rs` 的 `expire` 管。
use unlucky_presenter::dto::{LaunchFinished, LogOutcome};
use unlucky_presenter::toast::ToastKind;
use super::App;
/// 夹具开关是否打开(`ULL_TOAST_FIXTURE` 非空且不为 `0`)。
fn enabled() -> bool {
std::env::var("ULL_TOAST_FIXTURE")
.map(|value| {
let value = value.trim();
!value.is_empty() && value != "0"
})
.unwrap_or(false)
}
/// 推一条「游戏崩溃」的收尾提示(就是用户在真机上看到的那一句)。
pub(super) fn seed(app: &mut App) {
if !enabled() {
return;
}
// 形状取自真实收尾事件:崩溃 + 退出码 1 + 跑了 12 秒。
let finished = LaunchFinished {
id: "survival".to_string(),
session: String::new(),
outcome: LogOutcome::Crashed,
exit_code: Some(1),
uptime_ms: 12_000,
failure: None,
};
let text = crate::app::view::instances::launch_toast(&finished, app.lang());
app.state.toasts.push(ToastKind::Error, text);
}