fix(m161): 收更新键/按钮/矮窗口/启动错误/导入结果五笔债

① 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
里贴线或越线的文件按模块拆开(纯搬移,行为不变)。
This commit is contained in:
AskaEth committed 2026-11-07 15:02:13 +08:00
1 parent b2d9f3927f
commit 03741ecd2d
69 files changed
+2653 -707

No files matched your search

+49 -2
View File
@@ -62,6 +62,43 @@ impl ImportStageView {
}
}
/// 致命失败的**阶段**(M161:`rolled_back` 一个人说不了两件事)。
///
/// core 的 `ImportReport::rolled_back` 语义是「目标目录已确认与导入前一致」——它同时覆盖
/// 「回滚完整完成」和「**从未写过**目标目录」两种情形(见 `core::addon::import::pipeline` 的
/// `record_rollback` / `abandoned`)。UI 拿一个 bool 判不出该说哪一句,于是预检失败也会被
/// 说成「已回滚」,而实际上一个字节都没写。这个枚举把两种情形重新分开,并补上第三种
/// (回滚有失败项,目标目录可能与导入前不同)。
///
/// 只在 `status == Failed` 时有值:成功/部分成功的报告没有「失败阶段」可言。
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ImportFailureStageView {
/// 预检/装配阶段就失败了:**目标目录一个字节都没写**(用户该去修包/修配置再试)。
NotStarted,
/// 已经写过目标目录,回滚**完整**完成(零残留)。
RolledBack,
/// 写过了,但回滚有失败项:目标目录可能与导入前不同(`warnings` 里逐条列了)。
RollbackIncomplete,
}
impl ImportFailureStageView {
/// 稳定 slug(日志 / 测试用;**不要改名**)。
#[must_use]
pub const fn slug(self) -> &'static str {
match self {
Self::NotStarted => "not_started",
Self::RolledBack => "rolled_back",
Self::RollbackIncomplete => "rollback_incomplete",
}
}
/// 本次失败到底动没动目标目录。
#[must_use]
pub const fn touched_target(self) -> bool {
!matches!(self, Self::NotStarted)
}
}
/// 导入三态(`Partial` **不是** `Success`)。
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ImportStatusView {
@@ -69,7 +106,11 @@ pub enum ImportStatusView {
Success,
/// 有缺文件或有冲突(内容不完整,但实例可用)。
Partial,
/// 致命失败,**已整包回滚**。
/// 致命失败。
///
/// **「动没动过目标目录」不在这里**(M161):同一个 `Failed` 既可能是预检没过(一个字节都没写),
/// 也可能是写完又回滚干净,还可能是回滚没做完——三种由
/// [`ImportReportView::failure_stage`] 分开说,界面按它选标题与图标。
Failed,
}
@@ -243,7 +284,7 @@ pub struct MissingFileView {
pub detail: String,
}
/// 一次**已整包回滚**的致命失败。
/// 一次致命失败(是不是「已整包回滚」看 [`ImportReportView::failure_stage`])。
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ImportErrorView {
/// 稳定码(`pack_traversal` / `import_integrity` …,进日志与 `--json`)。
@@ -292,7 +333,13 @@ pub struct ImportReportView {
/// 本次写入的字节数。
pub bytes_written: u64,
/// 回滚是否完整(`false` = 目标目录可能与导入前不一致,逐条在 `warnings` 里)。
///
/// **注意**:`true` 有两种来源——「回滚完整完成」与「从未写过目标目录」(core 的
/// `abandoned`)。要区分它们看 [`ImportReportView::failure_stage`];界面上的措辞
/// **必须**按那个字段选(M161)。
pub rolled_back: bool,
/// 失败发生在哪一步(`None` = 这次不是致命失败)。
pub failure_stage: Option<ImportFailureStageView>,
}
impl ImportReportView {