fix(app-iced): 点选共享档立刻显示后果原文,登记在飞时不吃关闭(M223 自检)

两处自己复审抓到的问题:

1. 契约 §5.2 要求 Shared/VersionDir 被**点选**就展示 target_notes() 原文,而上一版要等
   用户再点一次「预检」才出现。现在点选这两档会顺手发一次**零写盘**的预检,结果落在
   Pick 段当提示读(不把用户甩到确认页:确认仍由显式的「预检」按钮触发,Form::checked)。
   改档之后旧 plan 因目标档不一致而不再显示(Form::fresh_plan),避免画上一档的后果原文。
2. 「关闭」在登记在飞时被忽略:core 那条线程已经开跑,关面板会让 Done 事件被代次丢掉,
   用户看到的就是「实例写进去了,界面什么都没说」。

用例:a_foreign_target_shows_its_notes_without_jumping_to_confirm /
choosing_a_foreign_target_previews_but_waits_for_the_user /
closing_is_ignored_while_the_registration_is_in_flight。
This commit is contained in:
AskaEth committed 2026-11-10 19:37:43 +08:00
1 parent 9ca5ee8ae7
commit a36e17a5d3
4 files changed
+163 -19

No files matched your search

+9 -1
View File
@@ -14,7 +14,7 @@ use unlucky_design::shape::ShapeScale;
use unlucky_design::spacing::Space as Sp;
use unlucky_design::typography::TypeRole;
use unlucky_i18n::{Catalog, Key};
use unlucky_presenter::dto::{AdoptCandidateView, AdoptScanView, AdoptTargetView};
use unlucky_presenter::dto::{AdoptCandidateView, AdoptPlanView, AdoptScanView, AdoptTargetView};
use crate::app::components::inputs::{text_field, Field};
use crate::app::components::selection::{chip, Chip};
@@ -30,6 +30,7 @@ pub(super) fn pick<'a>(
ui: &'a Ui,
form: &'a Form,
scan: Option<&'a AdoptScanView>,
plan: Option<&'a AdoptPlanView>,
catalog: Catalog,
) -> Element<'a, Message> {
let Some(scan) = scan else {
@@ -57,6 +58,13 @@ pub(super) fn pick<'a>(
body = body.push(frame::divider(ui).map(Message::Page));
body = body.push(label(ui, catalog.text(Key::AdoptTargetLabel)));
body = body.push(target_row(ui, form, catalog));
// 后果原文(契约 §5.2):共享档 / 版本目录档一被点选就显示 core `target_notes()` 的原文——
// 这一条来自**零写盘**的自动预检(见 `AdoptMessage::Target` 的落点),不是界面另写的一句。
if let Some(plan) = plan {
for note in &plan.notes {
body = body.push(wrapped(ui, note.clone(), ui.color(Role::OnSurfaceVariant)));
}
}
body = body.push(text_field(
ui,
Field::new(form.name.as_str()).label(catalog.text(Key::AdoptNameLabel)),
+48 -4
View File
@@ -90,11 +90,11 @@ fn the_four_stages_project_from_the_event_state() {
// Pick
assert_eq!(state.stage(), AdoptStage::Pick);
assert_eq!(
title_text(&state, catalog),
title_text(state.stage(), catalog),
catalog.text(Key::AdoptTitle),
"标题走目录"
);
assert!(subtitle(&state, catalog).contains("不复制"));
assert!(subtitle(state.stage(), &state, catalog).contains("不复制"));
// Preview:`notes` 是 core `target_notes()` 的原文,界面一个字都不许改
let note =
@@ -136,7 +136,7 @@ fn the_four_stages_project_from_the_event_state() {
"两条问题一条都不许吞"
);
assert_eq!(
title_text(&state, catalog),
title_text(state.stage(), catalog),
catalog.text(Key::AdoptFailureTitle)
);
@@ -152,7 +152,7 @@ fn the_four_stages_project_from_the_event_state() {
})));
assert_eq!(state.stage(), AdoptStage::Done);
assert_eq!(
title_text(&state, catalog),
title_text(state.stage(), catalog),
catalog.text(Key::AdoptDoneTitle)
);
}
@@ -199,3 +199,47 @@ fn both_catalogs_have_the_wizard_wording() {
let hint = Lang::En.catalog().text(Key::AdoptTargetSharedHint);
assert!(hint.contains(".minecraft"), "{hint}");
}
/// 「点选共享档 ⇒ 立刻看到后果原文」但**不**把用户甩到确认页:
/// 预检结果到了也只是 Pick 段里的提示,直到用户点过「预检」(`checked`) 才进 Preview。
///
/// 抓得住:把 `Form::stage` 写回直接取 `AdoptState::stage()`(点一次共享档就跳到确认页,
/// 实例名还没来得及改);或忘了 `fresh_plan` 的目标一致性判据(改档之后画上一档的后果原文)。
#[test]
fn a_foreign_target_shows_its_notes_without_jumping_to_confirm() {
let mut state = state_with_scan();
let note =
"运行目录 = /game(共享档):mods/saves/config 会落在别人的 .minecraft 里".to_string();
state.apply(AdoptEvent::Planned(Box::new(AdoptPlanView {
version_id: "1.20.1".to_string(),
name: "1.20.1".to_string(),
target: AdoptTargetView::Shared,
isolation: AdoptIsolationView::Shared,
run_dir: std::path::PathBuf::from("/game"),
notes: vec![note.clone()],
})));
let mut form = Form {
open: true,
selected: Some("1.20.1".to_string()),
target: AdoptTargetView::Shared,
..Form::default()
};
// 自动预检回来但用户没点「预检」:仍是 Pick 段,notes 当作提示可读
assert_eq!(form.stage(&state), AdoptStage::Pick);
assert_eq!(
form.fresh_plan(&state)
.map(|plan| plan.notes.first().cloned()),
Some(Some(note.clone())),
"后果原文必须能取到"
);
// 点过「预检」之后才进确认段
form.checked = true;
assert_eq!(form.stage(&state), AdoptStage::Preview);
// 换了目标档:上一档的预检作废(不再当后果原文画)
form.target = AdoptTargetView::VersionDir;
assert!(form.fresh_plan(&state).is_none(), "过期的预检不许画");
}