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 行。
This commit is contained in:
1 parent
5adac230fe
commit
6b161227d8
42 files changed
+4071
-25
No files matched your search
@@ -0,0 +1,86 @@
|
||||
//! 内容库文案(M109 `CONTENTDL`)。
|
||||
//!
|
||||
//! 一句话一个 key:带变量的句子用 `{name}`,页面只做 [`crate::Catalog::render`],不拼片段。
|
||||
//!
|
||||
//! ## 三条口径
|
||||
//!
|
||||
//! 1. **只说能做的事**:整合包那条写的是「要等导入管线」,不是「稍后自动支持」;
|
||||
//! 2. **站名也进词表**:`Modrinth` / `CurseForge` 的**中文译文必须与英文不同**
|
||||
//! (`catalog/tests.rs` 的 `chinese_catalog_is_actually_chinese` 会红),所以中文写成「Modrinth 源」;
|
||||
//! 3. **禁用态要能解释自己**:`ContentIncompatible*` / `ContentModpackNotReady` 就是禁用按钮旁边那几句话——
|
||||
//! 没有它们,禁用就等于「点了没反应」。
|
||||
//!
|
||||
//! 域文件的形状见 `crate::catalog` 的「域装配」一节。
|
||||
|
||||
macro_rules! content_entries {
|
||||
($next:ident, $($rest:ident,)* { $($acc:tt)* }) => {
|
||||
$next! { $($rest,)* {
|
||||
$($acc)*
|
||||
// --- content library page (M109) ---
|
||||
ContentTitle => ("Content", "内容库"),
|
||||
ContentSubtitle => (
|
||||
"Modpacks, mods, resource packs and shaders",
|
||||
"整合包、Mod、资源包与光影"
|
||||
),
|
||||
ContentSectionVersions => ("Version management", "版本管理"),
|
||||
ContentSectionContent => ("Content library", "内容库"),
|
||||
ContentKindModpack => ("Modpacks", "整合包"),
|
||||
ContentKindMod => ("Mods", "Mod"),
|
||||
ContentKindResourcepack => ("Resource packs", "资源包"),
|
||||
ContentKindShader => ("Shaders", "光影"),
|
||||
ContentSourceModrinth => ("Modrinth", "Modrinth 源"),
|
||||
ContentSourceCurseforge => ("CurseForge", "CurseForge 源"),
|
||||
ContentSortRelevance => ("Relevance", "相关度"),
|
||||
ContentSortDownloads => ("Downloads", "下载量"),
|
||||
ContentSortNewest => ("Newest", "最新发布"),
|
||||
ContentSortUpdated => ("Recently updated", "最近更新"),
|
||||
ContentSearchPlaceholder => ("Search content…", "搜索内容…"),
|
||||
ContentSearch => ("Search", "搜索"),
|
||||
ContentFilterVersion => ("Game version", "游戏版本"),
|
||||
ContentFilterLoader => ("Loader", "加载器"),
|
||||
ContentFilterAny => ("Any", "不限"),
|
||||
ContentCount => ("{count} results", "{count} 个结果"),
|
||||
ContentLoading => ("Loading content…", "正在加载内容…"),
|
||||
ContentLoadingHint => (
|
||||
"Results come from the network; nothing is cached offline yet.",
|
||||
"结果来自网络,暂时没有离线缓存。"
|
||||
),
|
||||
ContentEmptyTitle => ("Nothing matched", "没有匹配的内容"),
|
||||
ContentEmptyBody => (
|
||||
"Try another keyword, or clear a filter.",
|
||||
"换个关键词,或清掉一个筛选条件。"
|
||||
),
|
||||
ContentFailedTitle => ("Could not load content", "内容加载失败"),
|
||||
ContentFailedBody => ("Check the network, then retry.", "检查网络后重试。"),
|
||||
ContentRetry => ("Retry", "重试"),
|
||||
ContentLoadMore => ("Load more", "加载更多"),
|
||||
ContentNoMore => ("No more results", "没有更多了"),
|
||||
ContentDetailEmpty => (
|
||||
"Pick an item to see what it supports.",
|
||||
"选一个项目看它支持什么。"
|
||||
),
|
||||
ContentDetailDownloads => ("{count} downloads", "下载量 {count}"),
|
||||
ContentDetailUpdated => ("Updated {date}", "更新于 {date}"),
|
||||
ContentDetailLoaders => ("Loaders: {list}", "加载器:{list}"),
|
||||
ContentDetailVersions => ("Game versions: {list}", "游戏版本:{list}"),
|
||||
ContentInstall => ("Install into instance", "装入实例"),
|
||||
ContentTargetInstance => ("Target instance", "目标实例"),
|
||||
ContentNoInstances => ("No instance to install into", "没有可装入的实例"),
|
||||
ContentIncompatibleVersion => (
|
||||
"Needs {version}; this instance runs {actual}",
|
||||
"需要 {version},该实例运行的是 {actual}"
|
||||
),
|
||||
ContentIncompatibleLoader => ("Not built for {loader}", "不支持 {loader}"),
|
||||
ContentModpackNotReady => (
|
||||
"Modpack install comes with the M111 import pipeline",
|
||||
"整合包安装要等 M111 的导入管线"
|
||||
),
|
||||
ContentSourceUnavailable => (
|
||||
"Set ULL_CF_API_KEY to search CurseForge",
|
||||
"要搜 CurseForge 请先设置 ULL_CF_API_KEY"
|
||||
),
|
||||
} }
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use content_entries;
|
||||
Reference in new issue
Block a user