① update.auto_check / update.channel 登记进 core setting schema(1.6.0)
- 新增 setting/keys/update.rs(两键 + UPDATE_CHANNELS,只允许 stable);
SettingSchema 加 with_all 供域键表批量登记。
- 新增 setting/update_prefs.rs:cache/update/prefs.json → launcher.json 的一次性迁移。
四条硬约束:源指纹闸门(幂等)、不丢 false、新值胜出、旧文件改名 .migrated 后不再被读;
主配置不可写时不动旧文件。收据 config/update-prefs-migration.json。
- presenter Runtime 建会话时迁一次并把结局留在 migration();prefs 字段换成
auto_check + 每次派发从主配置读 channel(不再硬编码 Channel::Stable)。
保留旧字段 auto_check 的真实来源(原有测试 cases 会断言)。
- CLI config get/set/dump 先跑同一次迁移(幂等),输出里给 migration 段与收据路径。
② presenter/dto/events.rs 的「本次会话不再弹提示条」注释改成真实语义
(记的是版本号:同版本压住、更高版本照弹、手动检查清掉)。
③ 检查/下载进行中按钮禁用:pages/update/busy.rs 的 busy/can_check/can_apply;
设置页两颗按钮改画禁用(不是消失),app 层 on_update_action 再挡一道
(忙碌时 CheckNow/Apply 不派发);新增两条用例(含「忙完恢回可点」)。
④ 内容库低高度:content_layout::MIN_BODY_HEIGHT=460 + BodyMode(按固定件+三整行算出来,
用例守着算式);frame::body_height 从 Ui::metrics 算正文可用高,pages::Model 带 window_height。
≥460 列表自己滚;<460 主列整列一个滚动条、列表按自然高度铺开。
⑤ 启动错误文案本地化:presenter 删掉 launch_summary / 「启动失败:」前缀 / 五条中文阶段前缀,
改发 LaunchFailureView{stage,detail};LaunchFinished 改带 exit_code/uptime_ms/failure,
Toast 由 app 层按 i18n key 现求(与 install_cancelled 同构)。InstancesFailed 拆成
InstancesFailedStage(列表单行)+ LaunchStageFailed(详情/Toast 全文)。
⑥ 导入结果块:ImportReportView 加 failure_stage(NotStarted/RolledBack/RollbackIncomplete,
由 core 的 rollback 机器位推出);标题、图标、底色三处分档,预检失败不再说「已回滚」。
顺带:六处注释/文档漂移(update.rs 的分工表与偏好落点、pack 的「已整包回滚」、
build_request 的 Errors、settings/update 的按钮禁用说明等),
以及为守 400 行把 update/cli-config/core-keys/presenter-dto/presenter-launch/i18n-golden
里贴线或越线的文件按模块拆开(纯搬移,行为不变)。
71 lines
4.4 KiB
Rust
71 lines
4.4 KiB
Rust
//! 启动结局文案:一句话 = 一个 key(原来 UI 把 `"Launch failed"` 与 core 的「静默失败」拼成一句话)。
|
||
//!
|
||
//! 域文件的形状见 [`crate::catalog`] 的「域装配」一节。
|
||
|
||
macro_rules! launch_entries {
|
||
($next:ident, $($rest:ident,)* { $($acc:tt)* }) => {
|
||
$next! { $($rest,)* {
|
||
$($acc)*
|
||
// ── 启动结局(原来 UI 把 "Launch failed" 与 core 的「静默失败」拼成一句话,现在一句话 = 一个 key)
|
||
LaunchOutcomeNormal => ("Finished normally", "正常结束"),
|
||
LaunchOutcomeCrash => ("The game crashed", "游戏崩溃"),
|
||
LaunchOutcomeSilent => (
|
||
"Suspected silent failure: exit code 0, but the game never really started",
|
||
"疑似静默失败:退出码 0,但游戏没真正跑起来"
|
||
),
|
||
LaunchFailedWithCode => ("Launch failed (exit {code}): {reason}", "启动失败(退出码 {code}):{reason}"),
|
||
// M161:启动失败的**阶段**词表。presenter 只给稳定 slug
|
||
// (`LaunchFailureStage`),界面在这里选词——此前这些前缀是 presenter 里拼的中文
|
||
// (「读版本 JSON 失败」「隔离目录派生失败」…),英文界面上原样露出来。
|
||
LaunchStageVersionManifest => ("Reading the version file", "读版本文件"),
|
||
LaunchStageInheritance => ("Resolving the inheritance chain", "解析继承链"),
|
||
LaunchStageInstanceConfig => ("Reading the instance settings", "读实例设置"),
|
||
LaunchStageIsolation => ("Preparing the isolated game folder", "准备隔离游戏目录"),
|
||
LaunchStageIdentity => ("Preparing the account", "准备账户"),
|
||
LaunchStageSpawn => ("Starting the game process", "启动游戏进程"),
|
||
LaunchStageFailed => ("Launch failed · {stage}: {detail}", "启动失败 · {stage}:{detail}"),
|
||
LaunchToastEnded => ("{outcome} · {seconds}s", "{outcome} · {seconds} 秒"),
|
||
// M117:微软轨的 client id 没配是**配置缺失**,不是「本期未支持」。这句话是那条
|
||
// 启动失败文案的**双语口径**(真源在 `core::auth::microsoft` 的
|
||
// `MISSING_CLIENT_ID_MESSAGE`,中文逐字一致;英文这条给 En 界面用)。
|
||
// 判据:中英都点名 `ULL_MSA_CLIENT_ID` 并给出构建期注入这条路,且**不许**出现
|
||
// 「unsupported / 未支持」——用户实跑就是被那句误导读成「功能没做」。
|
||
LaunchMsaNotConfigured => (
|
||
"Microsoft sign-in is not configured: it needs an Azure public client id (the login flow itself is implemented). Build with ULL_MSA_CLIENT_ID=<id>, or set that environment variable before launching.",
|
||
"微软登录未配置:缺少 Azure 公共客户端 id(登录功能已实现,只差这一项配置)。构建时注入:ULL_MSA_CLIENT_ID=<id> cargo build;或启动前设置同名环境变量 ULL_MSA_CLIENT_ID=<id>。"
|
||
),
|
||
} }
|
||
};
|
||
}
|
||
|
||
pub(crate) use launch_entries;
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use crate::{Catalog, Key, Lang};
|
||
|
||
#[test]
|
||
fn msa_not_configured_copy_is_accurate_in_both_languages() {
|
||
// 抓得住:文案退回「本期未支持」这类说法(M117 用户实跑踩到的原 bug),
|
||
// 以及两条译文只剩一句「需要 id」却不给怎么配。
|
||
// 抓不住:读起来顺不顺——那要靠 review 与截图。
|
||
let en = Catalog::of(Lang::En).text(Key::LaunchMsaNotConfigured);
|
||
let zh = Catalog::of(Lang::ZhCn).text(Key::LaunchMsaNotConfigured);
|
||
|
||
for (tag, text) in [("en", en), ("zh-CN", zh)] {
|
||
assert!(text.contains("ULL_MSA_CLIENT_ID"), "{tag}: {text}");
|
||
}
|
||
assert!(en.contains("client id"), "{en}");
|
||
assert!(en.contains("not configured"), "{en}");
|
||
assert!(!en.to_lowercase().contains("unsupported"), "{en}");
|
||
assert!(!en.to_lowercase().contains("not implemented"), "{en}");
|
||
|
||
assert!(zh.contains("客户端 id"), "{zh}");
|
||
assert!(zh.contains("未配置"), "{zh}");
|
||
assert!(!zh.contains("未支持"), "{zh}");
|
||
assert!(!zh.contains("未实现"), "{zh}");
|
||
// 硬约束:词条里只许出现 `<id>` 占位,不出现真 id(repo 任何文件都不许带)。
|
||
assert!(en.contains("<id>") && zh.contains("<id>"));
|
||
}
|
||
}
|