diff --git a/crates/presenter/src/dto/events.rs b/crates/presenter/src/dto/events.rs index 7fcd695..ed85fe8 100644 --- a/crates/presenter/src/dto/events.rs +++ b/crates/presenter/src/dto/events.rs @@ -12,6 +12,8 @@ use crate::dto::{ // 主线(M109 的 Content* / M113 的 Pack*)与 M114 的 Authlib*/AccountNotice 的并集。 AccountNotice, AccountView, + AdoptCommand, + AdoptEvent, AgentEvent, AuthlibLoginView, AuthlibRequest, @@ -149,6 +151,11 @@ pub enum CoreEvent { // M113: import/export /// 导入/导出(M113):进度、结果、探测诊断、导出预检(子枚举见 [`PackEvent`]) Pack(Box), + /// 导入已有版本(M223):扫描 / 预检 / 完成 / 失败(子枚举见 [`AdoptEvent`]) + /// + /// 与 [`Self::Pack`] 分开是**语义**上必须的:整合包导入会把内容真搬进实例目录, + /// 而这里只登记盘上已有的版本、写两份配置(`versions/` 一个字节都不动)。 + Adopt(Box), /// 自更新(M159):整份状态快照(检查结论 + 就位状态 + 用户是否已拒绝)。 /// /// 与 `SettingsChanged` 同一条形态:快照整体替换,UI 不做增量合并。 @@ -263,6 +270,8 @@ pub enum AppCommand { // M113: import/export /// 整合包导入/导出(M113):导入 / 预检 / 确认写盘 / 关面板(子枚举见 [`PackCommand`]) Pack(Box), + /// 导入已有版本(M223):扫描 / 预检 / 确认登记 / 关面板(子枚举见 [`AdoptCommand`]) + Adopt(Box), // M159: 自更新 /// 查一次更新(设置页「立即检查」;会清掉「忽略这个版本」的标记并重新请求网络) CheckUpdate, diff --git a/crates/presenter/src/host/dispatch.rs b/crates/presenter/src/host/dispatch.rs index ccdf8e9..e747a62 100644 --- a/crates/presenter/src/host/dispatch.rs +++ b/crates/presenter/src/host/dispatch.rs @@ -253,6 +253,8 @@ impl CoreHost { // (`CancelInstall` 会把标记置位,下载在阶段边界收尾)。 // M113: import/export —— 导入 / 预检 / 确认写盘 / 关面板 AppCommand::Pack(command) => self.pack(*command), + // M223: 导入已有版本 —— 扫描 / 预检 / 确认登记 / 关面板 + AppCommand::Adopt(command) => self.adopt(*command), AppCommand::InstallContent(request) => { let cancel = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); self.install_cancel = Some(std::sync::Arc::clone(&cancel)); diff --git a/crates/presenter/src/host/handle.rs b/crates/presenter/src/host/handle.rs index 493dd92..b6522db 100644 --- a/crates/presenter/src/host/handle.rs +++ b/crates/presenter/src/host/handle.rs @@ -69,6 +69,7 @@ impl CoreHost { // M105 的形状(代次丢包)为准:旧任务(已取消 / 被下一轮顶掉)的进度一律丢掉。 // 这是「点了取消没反应」的根因:取消时 `InstallProgress(None)` 刚把面板收回, // 旧任务的下一条「下载中」事件立刻又把它点亮。 + HostTask::Adopt { event, epoch } => self.handle_adopt(*event, epoch), HostTask::Install { progress, epoch } => { if epoch != self.install_epoch { return; diff --git a/crates/presenter/src/host/install.rs b/crates/presenter/src/host/install.rs index b5957c6..43310d4 100644 --- a/crates/presenter/src/host/install.rs +++ b/crates/presenter/src/host/install.rs @@ -106,7 +106,7 @@ pub fn supported(kind: LoaderKind) -> bool { /// 不支持的加载器 → 给用户的可执行建议。 pub fn unsupported_reason(kind: LoaderKind) -> String { format!( - "{} 还没有接入安装管线(目前支持原版 + Fabric/Quilt/Forge/NeoForge/LiteLoader);请先在实例页导入已有版本,或换成受支持的加载器。", + "{} 还没有接入安装管线(目前支持原版 + Fabric/Quilt/Forge/NeoForge/LiteLoader);如果别的启动器已经装好了这个版本,可以在实例页用「导入已有版本」把它只读接进来(不复制文件),否则请换成受支持的加载器。", kind.label() ) } diff --git a/crates/presenter/src/host/job.rs b/crates/presenter/src/host/job.rs index 7def756..fe02ba7 100644 --- a/crates/presenter/src/host/job.rs +++ b/crates/presenter/src/host/job.rs @@ -68,6 +68,17 @@ pub enum HostTask { /// 任务代次 epoch: u64, }, + // M223: 导入已有版本 + /// 扫描 / 预检 / 确认的结果(一条事件 + 任务代次) + /// + /// 代次是 adopt 自己的(`CoreHost::adopt_epoch`),**不**与安装或 pack 的代次共用: + /// 关一次导入面板不该把下载页在跑的安装静默丢掉。 + Adopt { + /// 事件载荷(扫描 / 预检 / 完成 / 失败) + event: Box, + /// 任务代次 + epoch: u64, + }, /// 安装进度(高频,host 只做聚合与转发) Install { /// 进度快照 diff --git a/crates/presenter/src/state.rs b/crates/presenter/src/state.rs index 94463e3..a59d9c0 100644 --- a/crates/presenter/src/state.rs +++ b/crates/presenter/src/state.rs @@ -8,6 +8,7 @@ use crate::dialogs::DialogQueue; use crate::dto::{ // 主线(M105 的 `LoaderKind` / M113 的 `PackState`)与 M114 的 `AuthlibLoginView` 并集。 AccountView, + AdoptState, AppEvent, AuthlibLoginView, CoreEvent, @@ -133,6 +134,8 @@ pub struct AppState { pub content: ContentState, /// 整合包导入/导出:进度 / 结果 / 探测诊断 / 导出预检(M113) pub pack: PackState, + /// 导入已有版本(M223):扫描 / 预检 / 失败 / 完成(**只装事件态**,表单在页面本地态) + pub adopt: AdoptState, } impl Default for AppState { @@ -178,6 +181,7 @@ impl AppState { live_session: None, content: ContentState::default(), pack: PackState::default(), + adopt: AdoptState::default(), } } @@ -296,6 +300,8 @@ impl AppState { CoreEvent::Update(view) => self.update = *view, // M113: import/export CoreEvent::Pack(event) => self.pack.apply(*event), + // M223: 导入已有版本(唯一写入点:`AdoptState::apply`) + CoreEvent::Adopt(event) => self.adopt.apply(*event), CoreEvent::ContentResults(results) => self.apply_content(*results), CoreEvent::ContentFailed(failure) => self.apply_content_failure(*failure), // M162:详情/版本列表(判断逻辑在 `state/content.rs`,这里只有一行投递)