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 后按新形状写一次)。
This commit is contained in:
1 parent
0367073d32
commit
fbeff94e55
31 files changed
+3646
-9
No files matched your search
@@ -0,0 +1,114 @@
|
||||
//! 阶段与进度:**把导入进度映射成下载页那块面板的入参**(不另画一套进度 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()
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user