AskaEth
|
27bbc74eaa
|
fix(packui): M113 收口 —— 导出的「Save to」字段形状与「没进包」标题承诺
复审看图挑出的两处,只改这两处,其余不动。
1. **Save to 字段**:原来是 `label("Save to (empty = suggested)")` + 空值,看起来像「这句提示就是字段值」,
与上面 Pack name / Version 的「标签在上、值在下」不一致。改成短标签 `Save to` + 占位
`empty = suggested path`(新增 `PackExportOutputPlaceholder` 一个键)。
2. **`Not in the pack (listed one by one)` 与 `...and 6 more files` 自相矛盾**:13 条没进包的其实全列了,
但紧随其后的「还有 6 个」说的是**内联样例**的截断,两句挨着会被读成一件事。
改法:「没进包」标题带真实计数(`Not in the pack: {count}`),内联样例加自己的标题
`Copied into overrides/ (first {shown}):`,截断那句改成 `…and {count} more files (not shown here)`
—— 谁被截断、截了几条,写在它自己的那一块里。
`tolerable_title` 因此改成收 `String`(计数是运行时 format 出来的),`golden.rs` 同步三个键。
门禁:`cargo fmt --all --check` 通过;`cargo test -p unlucky-app-iced --lib -j 2`
504 passed / 0 failed(TEST_EXIT=0);`cargo check -p unlucky-app-iced --all-targets` 零 warning。
出图:`04-export-light.png` / `04-export-dark.png` 已重出(其余 8 张未受影响、未改动)。
|
2026-11-05 04:06:40 +08:00 |
|
AskaEth
|
5f09b8113a
|
feat(packui): M113 phase 2 —— 导入导出真正接线(三个共享枚举各只多一个变体)
搬到 M109 rebase 后的新 main(26e764e)之后按**新 main 的形状**写一次,不写两遍。
## 接线
- `dto/pack/event.rs`(新):`PackCommand` / `PackEvent` / `PackState::apply`。
整条流程在三个最挤的共享枚举里各只占**一个**变体(`AppCommand::Pack` / `CoreEvent::Pack` /
`HostTask::Pack{event, epoch}`),子枚举承载细节 —— rebase 时不用替别人定序。
- `events.rs` / `job.rs` / `handle.rs` / `dispatch.rs` / `state.rs`:变体与分支,全部带
`// M113: import/export` 锚点。`state.rs` 只多 1 个字段 + 1 条 apply 分支(399 行)。
- `host/addon/**`(新目录,父文件只加 `mod pack;` + 再导出):
- `pack.rs`:`CoreHost::pack` 落点 + 取消标记 + 实例目录/快照/格式/缺省路径解析
- `pack/import.rs`:探测 → 目标目录 → `import_pack` → 报告(默认 KeepUser,显式才 Overwrite)
- `pack/export.rs`:预检(`scan_instance`,**不写盘**)与写盘(`export_instance`)
- `pack/convert.rs`:core 报告 → DTO,逐字段照搬(三态/五阶段/四处置/三成因/十一原因)
- `pack/diagnose.rs`:探测诊断「像 X 缺 Y」(按标记文件的有无,不看文件名)
- `app/update/content.rs`:导入 / 以包为准 / 预检 / 确认写盘 / 关面板真的派指令;
预检时先记下那份请求,确认时**原样发回**(防「预检 A、写 B」)。
- `pages/content/model.rs`:读 `state.pack`(不再是默认空态)。
- 面板接口按新形状改:`install_panel_model(&InstallProgressView, catalog) -> Option<Download>`
(`InstallView` 不再从 `pages/download` 导出)。
## 取消(如实)
`CancelInstall` 现在同时置导入的取消标记 + 代次 +1:面板立刻收回、旧事件按代次丢弃。
但 core 的 `import_pack` 没有取消令牌、进度回调也拿不到控制流 ⇒ **后台那次导入会跑完**。
所以「取消」的真实含义是「不再显示 + 结果作废」,已在模块文档与报告里写清,并单开 finding。
取消标记用 `Arc<AtomicBool>` 而不是裸静态量:裸静态量会在并行测试间泄漏取消状态(实测到过)。
## 图看出来的三处(塔台要求)
1. `no download source (CurseForge file API not wired)` → `no download source available yet`,
API 名只留在 DTO 的 detail 与日志里;顺带把 `sha512` / `projectID/fileID` 也改成用户话。
2. 右栏 `Installing modpacks is not available yet` → `Installing modpacks from the library into
an instance is not available yet`(那句在 i18n 词表里,不在 M109 页面代码里,所以我自己改)。
3. 结果面板接线后可以关:`Dismiss` / `AbortExport` 发 `PackCommand::Dismiss` → host 回
`PackEvent::Cleared` → 回到入口/浏览态,不再常驻。
## 证据(三条都是真跑,不是假数据)
- `bad_packs_get_a_named_diagnosis`:把文本改名成 .mrpack → 有具名诊断(不是静默、不 panic);
目录形态有 overrides/ 无 manifest.json → 说得出「缺哪个标记」。
- `a_real_pack_runs_through_the_pipeline_end_to_end`:造一个真 MultiMC 实例目录当包,
走 `import::run` 真路径,断言事件流里有进度 + 结果、格式=MutliMC、报告有写盘文件、文件真落地、
代次原样带回。
- `preview_counts_match_the_written_report`:同一实例上跑预检与 `export_instance`,
inline / skipped / remote **三项计数逐项相等**,且逐条路径的归类一致。
门禁:cargo check ✓ / clippy -D warnings(三 crate)EXIT=0 /
cargo test(app-iced 504 + 6 守卫,i18n 24,presenter 181)全绿 / rustfmt --check ✓ /
所有改动文件 ≤400 行(`state.rs` 399、`addon.rs` 106,pack 子目录最大 338)。
|
2026-11-05 04:06:39 +08:00 |
|
AskaEth
|
2129d8cee6
|
fix(packui): M113 第一批修正 —— 一次只摊开一件事、有界滚动、阶段词不再打架
D30 出图实测暴露的四个问题,都在本批范围内修掉:
1. **动作按钮被顶出屏幕**:内容库页正列没有整页滚动(只有结果列表自己滚),入口 + 报告 +
导出三块同时摊开时,「确认写盘 / 关闭 / 以包为准重新导入」落在 900px 以下。
改成一态一块(导出面板 > 进度 > 结果 > 入口);拖拽是窗口级事件,收起入口不丢功能。
2. **阶段词打架**:复用面板自带的阶段词是安装语义(Building the version),与
「Step 2/5 · Unpacking overrides」并排时两种说法。现在面板阶段词留空、由步骤行说真话
—— 仍然只有一份进度条 / 计数 / 取消按钮,没有第二套进度 UI。
3. **列表过长**:缺文件 / 冲突 / 预检样例与已知损失都套上「超过 n 条才滚」的有界容器
(packui/view/parts.rs 的 bounded),少量条目时不浪费空间。
4. **英文单复数**:计数行改成「标签:值」(Files written: 2、cannot export: 1)。
PackPathPlaceholder / PackFormatModrinth 的中文与英文雷同,被
chinese_catalog_is_actually_chinese 抓到,一并改掉。
另:app/update.rs 加完拖拽分支后 408 行超线 → 两个钩子改成返回 Task、三个分支各一行,
现在 397 行。新增致命态出图夹具(ULL_CONTENT_PACK=failed),用来证明「容忍的缺文件」与
「致命回滚」在视觉上可区分。
门禁:cargo check ✓ / clippy -D warnings ✓ / cargo test -p unlucky-app-iced(467+6)✓ /
cargo test -p unlucky-i18n(24)✓ / rustfmt --check ✓ / wc -l 全表 ≤400 ✓
|
2026-11-05 04:06:38 +08:00 |
|
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 |
|
AskaEth
|
42099d4336
|
fix(app-iced): M109 r1 —— CF 来源装入闸门、has_more 读最近一页、末行切半与文案/图标
复审 p1-2items 的两条 P1 与三条 P2,逐条收口。
`blockers_of` 只看版本/加载器/目标实例,不看来源;而 host 的 `resolve_file` 对 CF 直接
返回「未接通」⇒ 切到 CF 源后每条都必然失败,UI 一声不响。
- 新增 `Blocker::SourceNotWired` + 文案 `ContentSourceNotWired`(中英);
- `blockers_of` 的入参从 `Option<(&[String], &[String])>` 收成 `Option<HitFacts>`(版本 /
加载器 / **来源**),两处调用点(产品路径、演示数据)一起改;
- 判据同构于整合包的 `NeedsPipeline`:**点之前**禁用并给一条原因;CF 文件端点接通后删掉这条。
DTO 的 `has_more()` 判「本页装满」是对的,但 reducer 在 `offset>0` 时先 extend 再判,
被判定的是**累计条数** ⇒ 首页满 20 条之后恒真:「加载更多」永不消失、「没有更多了」在
真实翻页路径上不可达,且每点一次白发一次网络请求。
- `ContentState` 新增 `last_page_filled`(**先**按这一页记一位,再并进累计列表);
- 页面的 `has_more` 读它(`&& !pending`);换条件(offset 归零)时清位;
- 新增 `crates/presenter/src/state/content_tests.rs` 四条用例(state.rs 贴 400 行上限,拆文件):
`a_short_last_page_clears_has_more` / `an_empty_last_page_keeps_has_more_false` /
`changing_the_query_resets_the_page_flag` / `a_stale_batch_does_not_touch_the_page_flag`;
- 变异自证:把判据改回「读累计」后前两条红(`末页不满 ⇒ 不许说还有更多`、`空页 ⇒ 没有更多`),
改回绿。
- **末行被 footer 切半**(复审定位的真因):`view.rs` 的 body 列漏了 `.spacing(..)`,而列表
纵向内边距是 0 ⇒ 视口底边正好切在半行上。补 `Space::X2`,并说明为什么必须给。
- **文案去掉开发者术语与内部编号**:`ContentSourceUnavailable` 不再写 `ULL_CF_API_KEY`
(改「CurseForge 需要在设置里配置密钥才能搜索」);`ContentModpackNotReady` 不再写
mission 编号(改「整合包安装尚未开放」);host 侧那条 `InstallProgress` 失败文案同步去编号。
- **图标**:四类改为 `Folder` / `Plus` / `Restore` / `Expand`——不借用导航五枚(同屏撞形,
复审 P2-3)、不用填充字形(`no_hardcoded_tokens` 门禁);偏离表按**实际取值**重写,并补一条
「CF 的装入也是禁用态」的登记。
- 演示数据加 `ULL_CONTENT_STATE=cf` 一屏,出图证明 P1-1 的禁用态(`12-cf-not-wired-light.png`)。
门禁(逐条落盘退出码,不走管道):fmt 0 / clippy `-D warnings`(app-iced+presenter+i18n)0 /
`cargo test -p unlucky-app-iced --lib` 0(451 passed)/ `cargo test -p unlucky-presenter` 0
(174 passed)/ `cargo test --workspace --exclude unlucky-app` 0。改动文件最大 397 行。
取证:`DevDocs/artifacts/m109/`(12 张,全部重出)
|
2026-11-05 03:20:22 +08:00 |
|
AskaEth
|
6b161227d8
|
feat(app-iced): M109 CONTENTDL —— 内容库页(整合包/Mod/资源包/光影)
用户令「下载页只负责下载整合包和Mod/光影」:新开一页做**内容发现与装入**,
检索走 Modrinth(优先,无需 key)/ CurseForge(`ULL_CF_API_KEY` 环境变量,日志只打
set/unset),装入走 core 的下载引擎真下到实例目录,进度/取消/失败复用下载页那块安装面板。
- **入口(B1)**:`Route::Content` 是新顶层路由,但 `Route::nav()` 复用 `NavSection::Download`
——导航轨仍五项,页头右上是「版本管理 | 内容库」一级切换(版本管理页也加了同一个切换,
否则内容库只有 `ULL_START_ROUTE` 能到)
- **页内四条一级侧栏**(`pages/content/layout.rs` 四档几何:992/856/648 三个门槛都是
「Σ栏宽 + 间距」算出来的):整合包 / Mod / 资源包 / 光影;标签栏 200(`Resource packs`
比 M107 的版本类型名长,140 会切字,已登记偏离)
- **筛选**:关键词(草稿 + 显式「搜索」按钮,不逐字打网络)、来源、游戏版本、加载器
(Fabric/Forge/NeoForge/Quilt)、排序;**分页**(「加载更多」)而不是无限滚动——快照只有一个槽、
翻页要看得见、状态要可截图复现
- **四态**:加载 / 空 / 失败 / 有数据 + 「没有更多了」;筛选条在任何状态下都在(加载中藏筛选条
等于把入口收走)
- **一键装入**:`Content::blockers()` 是纯函数——版本不匹配、加载器不匹配、没有目标实例、
整合包缺管线**四条原因逐条**给出,按钮点之前就禁用;判定与画法分开(model/tests 直接钉)
- **整合包今天不可装**:`ContentKind::Modpack.dir()` 是 `None`,UI 禁用 + 说明,host 侧再挡
一次(绕过 UI 也只会回一条 Failed)。真流程是 M111 的导入管线
- **零 UI 网络**:`presenter/host/addon.rs` + `addon/{sources,http,install}.rs`;无 header 的请求走
core 的 `download_bytes`(信号量限流 + 健康度 + 退避全现成),带 `X-API-KEY` 的只有 CF 一条,
自带 429/5xx 退避(优先吃 `Retry-After`,封顶 30s);密钥不进 DTO/日志/仓库
- 文案 41 条中英进 `crates/i18n`(新域接在装配链末尾 ⇒ `Key::ALL` 与金表只追加)
- 演示数据 `ContentHit → Hit::of` 与产品路径同源(格式化不会两套),`ULL_CONTENT_KIND` /
`ULL_CONTENT_STATE` 供出图矩阵选类型与状态
取证:`DevDocs/artifacts/m109/`(10 张:四类内容 × 浅/深 + 搜索无结果 + 加载器不兼容禁用)
门禁:fmt ✓ / clippy `-D warnings`(三 crate)✓ / app-iced 450+6、presenter 170、i18n 24 全绿;
`cargo tree` 两条零 UI 门禁仍空;全部改动文件 ≤400 行。
|
2026-11-05 03:20:21 +08:00 |
|