Files
Unlucky-Launcher/crates/app-iced/src/pages/content/packui/model/progress.rs
T
AskaEth fbeff94e55 feat(packui): M113 第一批 —— 内容库页的导入/导出区(界面 + DTO + i18n + 拖拽落点)
导入入口(拖拽 + 路径输入 + 目标实例)与导出(格式选择 + 预检)的**界面层**,
数据面镜像 M111/M112 的管线报告(presenter DTO),进度整块复用下载页的安装面板。

## 落了什么

- pages/content/packui*:入口 / 进度块 / 结果块 / 导出预检块(每文件 ≤400)
  - 拖拽区(hover 变主色描边)+ 路径输入框 + 目标实例 chips
  - 进度:一行「步骤 n/5 · 解包覆盖内容」+ **下载页那块安装面板**(不另画进度条)
  - 结果:三态(Success/Partial/Failed)+ 缺文件逐条(Warn/Tertiary)+ 冲突逐条
    (成因 + 本次处置 + 可展开三方 SHA-1)+ 致命块(Error/ErrorContainer)
  - 导出:mrpack / CF 二选一 + 包名/版本/路径 + 预检「将内联 N 个文件 · 无法导出 M 项」
    + 逐条无法导出项 + 已知损失 + 确认写盘
- presenter/src/dto/pack{,/format,/import,/conflict,/export}.rs:镜像 core 报告的 DTO
  (三态、五阶段、三分类、十一条原因,全部 from_slug 与 core 稳定码逐字对齐)
- i18n:81 条 Pack* 键(content_entries! 尾部追加;golden.rs 同序同文)
- app/update.rs:FileDropped / FileHovered / FilesHoveredLeft → 内容库页(本版唯一的选文件通道)
- M109 的四个文件各一处插入:mod 声明 + Pack(..) 变体 + pack 字段 + 正列插入点

## 边界(如实)

- 没有系统文件选择框:依赖树里无对话框依赖,加它要动根 Cargo.toml + 许可门禁 +
  Linux 后端选型(影响单文件产物)。入口是拖拽 + 路径输入,原因写在界面上。
- 冲突没有逐文件决策:core 的 ConflictPolicy 是整次导入一个全局档,ConflictFile 是事后账。
  本批给「逐文件看 + 整体翻档(以包为准重新导入)」,文案明写「两者都留(改名)暂不支持」。
  默认一律 KeepUser——绝不默认覆盖用户改过的文件。
- 本批按钮半通:拖拽/路径/格式/实例/展开都真生效;「点导入真的开跑」「预检/确认写盘」
  要等第二批的 AppCommand 与事件通道(M109 rebase 到新 main 后按新形状写一次)。
2026-11-05 04:06:37 +08:00

115 lines
4.2 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.
//! 阶段与进度:**把导入进度映射成下载页那块面板的入参**(不另画一套进度 UI)。
//!
//! ## 任务书第 5 条怎么落
//!
//! 「沿用既有安装面板组件与状态机,禁止再写第二套进度 UI」——
//!
//! 1. 导入的 `ImportStageView` / 计数 / 当前路径先映射成 [`InstallProgressView`](本文件
//! [`panel_progress`]);
//! 2. 画法交给 `pages::download::install_panel`(M109 已经打过薄包装,同一个函数、同一套几何
//! 与文案);
//! 3. 面板只认四个粗阶段(规划 / 下载 / 安装 / 登记),任务书要的「解包 / overrides / 补文件」
//! 三档由**一行步骤说明**([`stage_line`])承载。
//!
//! 第 3 点不是第二套进度 UI:多出来的只是一句文字,进度条、计数行、取消按钮仍然只有那一份。
//! 为什么不再造一条按 `ImportStageView` 五档划分的进度条:那正是「第二套」的定义,而且两块条
//! 同时出现时用户不知道该信哪一条。
use unlucky_i18n::{Catalog, Key};
use unlucky_presenter::dto::{
ImportProgressView, ImportStageView, InstallProgressView, InstallStage,
};
use crate::pages::download::Download;
/// 抛进面板的进度行。
#[derive(Debug, Clone, PartialEq)]
pub struct Running {
/// 包名(面板标题那一行)
pub pack: String,
/// 细档位说明(`步骤 2/5 · 解包覆盖内容`)
pub stage_line: String,
/// 交给下载页那块面板的进度(**唯一**的进度形状来源)
pub panel: Download,
}
/// 细档位说明(`步骤 2/5 · 解包覆盖内容`)。
#[must_use]
pub fn stage_line(stage: ImportStageView, catalog: Catalog) -> String {
let total = ImportStageView::ALL.len();
let index = ImportStageView::ALL
.iter()
.position(|item| *item == stage)
.map_or(1, |at| at + 1);
catalog.render(
Key::PackStageLine,
&[
("index", &index.to_string()),
("total", &total.to_string()),
("stage", catalog.text(stage_key(stage))),
],
)
}
/// 阶段 → 文案 key。
#[must_use]
pub const fn stage_key(stage: ImportStageView) -> Key {
match stage {
ImportStageView::Probe => Key::PackStageProbe,
ImportStageView::Extract => Key::PackStageExtract,
ImportStageView::Fetch => Key::PackStageFetch,
ImportStageView::Commit => Key::PackStageCommit,
ImportStageView::Register => Key::PackStageRegister,
}
}
/// 导入阶段 → 安装面板的粗阶段(**唯一映射处**)。
///
/// `Extract` / `Commit` 都落到 `Installing`:对那块面板而言它们都是「在写盘」,区别由
/// [`stage_line`] 说给用户。
#[must_use]
pub const fn panel_stage(stage: ImportStageView) -> InstallStage {
match stage {
ImportStageView::Probe => InstallStage::Planning,
ImportStageView::Extract | ImportStageView::Commit => InstallStage::Installing,
ImportStageView::Fetch => InstallStage::Downloading,
ImportStageView::Register => InstallStage::Registering,
}
}
/// 导入进度 → 下载页面板的入参。
///
/// `version` / `instance` 都填包名:面板第一行显示的就是「这次在装什么」,
/// 而导入的对象是包,不是某个版本 id。
#[must_use]
pub fn panel_progress(progress: &ImportProgressView) -> InstallProgressView {
InstallProgressView {
version: progress.pack.clone(),
instance: progress.pack.clone(),
loader: String::new(),
stage: panel_stage(progress.stage),
files_done: u64::from(progress.done),
files_total: u64::from(progress.total),
bytes_done: 0,
bytes_total: 0,
speed_bps: 0,
eta_secs: 0,
message: progress.current.clone().unwrap_or_default(),
}
}
/// 进度事件 → 面板要的视图模型。
pub(super) fn running_of(progress: &ImportProgressView, catalog: Catalog) -> Running {
Running {
pack: progress.pack.clone(),
stage_line: stage_line(progress.stage, catalog),
panel: Download {
install: Some(crate::pages::download::install_view(
&panel_progress(progress),
catalog,
)),
..Download::loading()
},
}
}