feat(app-iced): 下载页在选 LiteLoader 时给中性说明(GUI 只叠原版、Forge 组合走 CLI)
新增 Key::DownloadOptionsLiteLoaderVanillaOnly(中英各一句,不含花括号占位符); 金表按 Key::ALL 的真实位置插入(DownloadOptionsNeedsAtLeast 之后、DownloadCancelled 之前), 只加新键不重排旧键。说明走 OptionsView 的新字段 note,不塞 problem(那是错误色 + 禁用确认)。
This commit is contained in:
1 parent
7ed954f7fa
commit
c8bf536c37
5 files changed
+91
No files matched your search
@@ -215,6 +215,12 @@ pub struct OptionsView {
|
||||
pub instance_name: String,
|
||||
/// 不兼容 / 取不到的原因(`Some` ⇒ 确认键按下不去)
|
||||
pub problem: Option<String>,
|
||||
/// 加载器相关的**中性说明**(不是错误:不套错误色、不禁用确认键)。
|
||||
///
|
||||
/// 目前只有 LiteLoader 有:下载页只能装「原版 + 加载器」这一层,叠在 Forge 上要走命令行
|
||||
/// (M222 的边界,见 [`Key::DownloadOptionsLiteLoaderVanillaOnly`])。把它塞进 `problem`
|
||||
/// 会让用户以为这个组合不能装、还会按不下去确认键,所以单独一条。
|
||||
pub note: Option<String>,
|
||||
/// 本地已装(确认键给「已安装」禁用态)
|
||||
pub installed: bool,
|
||||
/// 现在能不能点「安装」
|
||||
@@ -276,6 +282,13 @@ impl OptionsView {
|
||||
(Ok(()), _) => None,
|
||||
};
|
||||
|
||||
// 中性说明:只解释「这一页能做到哪一层」,不参与确认键判定。
|
||||
let note = (loader == Loader::LiteLoader).then(|| {
|
||||
catalog
|
||||
.text(Key::DownloadOptionsLiteLoaderVanillaOnly)
|
||||
.to_string()
|
||||
});
|
||||
|
||||
// 四条同时成立才按得下去:不兼容没有、列表真的就位(原版不需要列表)、没装过。
|
||||
// 「列表没到位」既包括 `Loading` 也包括 `Failed` 与空表——它们都已经在 `problem` 里说了原因。
|
||||
let ready = loader == Loader::Vanilla
|
||||
@@ -289,6 +302,7 @@ impl OptionsView {
|
||||
loader_version,
|
||||
instance_name: draft.instance_name.clone(),
|
||||
problem,
|
||||
note,
|
||||
installed: row.installed,
|
||||
can_confirm,
|
||||
}
|
||||
|
||||
@@ -272,3 +272,61 @@ fn installed_versions_cannot_be_confirmed_again() {
|
||||
assert!(options.installed);
|
||||
assert!(!options.can_confirm);
|
||||
}
|
||||
|
||||
/// 中性说明(M222):只有 LiteLoader 带「这里只叠原版」那条,且它**不影响**确认键。
|
||||
///
|
||||
/// 抓得住:说明被塞进 `problem`(会让用户以为不能装、确认键按不下去);或者说明跑到别家
|
||||
/// 加载器下面(Forge/Fabric 没有这条边界)。
|
||||
#[test]
|
||||
fn liteloader_carries_a_neutral_note_without_blocking_confirm() {
|
||||
let state = state_with(
|
||||
LoaderKind::LiteLoader,
|
||||
"1.12.2",
|
||||
Ok(vec!["1.12.2-SNAPSHOT"]),
|
||||
);
|
||||
let options = OptionsView::of(
|
||||
&row("1.12.2", VersionKind::Release),
|
||||
&state,
|
||||
&draft(Loader::LiteLoader),
|
||||
Lang::En.catalog(),
|
||||
);
|
||||
let note = options.note.as_deref().expect("LiteLoader 应带中性说明");
|
||||
assert!(note.contains("vanilla"), "{note}");
|
||||
assert!(
|
||||
note.contains("--loader liteloader"),
|
||||
"要给出可执行的下一步:{note}"
|
||||
);
|
||||
assert!(options.problem.is_none(), "中性说明不能变成错误");
|
||||
assert!(options.can_confirm, "说明不该禁用确认键");
|
||||
|
||||
// 中文目录同样给中文说明,且仍然不禁用确认键。
|
||||
let zh = state_with(
|
||||
LoaderKind::LiteLoader,
|
||||
"1.12.2",
|
||||
Ok(vec!["1.12.2-SNAPSHOT"]),
|
||||
);
|
||||
let options = OptionsView::of(
|
||||
&row("1.12.2", VersionKind::Release),
|
||||
&zh,
|
||||
&draft(Loader::LiteLoader),
|
||||
Lang::ZhCn.catalog(),
|
||||
);
|
||||
let note = options.note.as_deref().expect("中文也要有说明");
|
||||
assert!(note.contains("原版"), "{note}");
|
||||
assert!(options.can_confirm);
|
||||
|
||||
// 别家加载器不带这条说明。
|
||||
for loader in [Loader::Vanilla, Loader::Fabric, Loader::Forge] {
|
||||
let state = state_with(loader.kind(), "1.20.1", Ok(Vec::new()));
|
||||
let options = OptionsView::of(
|
||||
&row("1.20.1", VersionKind::Release),
|
||||
&state,
|
||||
&draft(loader),
|
||||
Lang::En.catalog(),
|
||||
);
|
||||
assert!(
|
||||
options.note.is_none(),
|
||||
"{loader:?} 不该带 LiteLoader 的说明"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -93,6 +93,18 @@ pub(crate) fn section<'a>(
|
||||
.spacing(ui.space(Space::X2))
|
||||
.width(Length::Fill);
|
||||
|
||||
// 中性说明(M222):只解释这一页能装到哪一层,不套错误色、不影响确认键。
|
||||
// 换行由 iced 的文本布局负责,长句不会横向溢出;但**视觉验收仍需截图确认**(D30)。
|
||||
if let Some(note) = &options.note {
|
||||
body = body.push(frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
note.as_str(),
|
||||
ui.color(Role::OnSurfaceVariant),
|
||||
));
|
||||
}
|
||||
|
||||
// 「加载器版本」这一段只在**真该有列表**时出现:原版没有、静态不兼容没有(原因在下面那行)、
|
||||
// 取不到也没有(同样在原因行)。留一个空标题只会让人以为界面缺了一块。
|
||||
if show_versions(options) {
|
||||
|
||||
@@ -99,6 +99,12 @@ macro_rules! download_entries {
|
||||
"{loader} needs Minecraft {min} or newer",
|
||||
"{loader} 需要 Minecraft {min} 或更新"
|
||||
),
|
||||
// M222:下载页只做「原版 + 加载器」一层,Forge 父链只有命令行能走。中性说明,
|
||||
// 不是错误(不禁用确认键、不套错误色)——所以它不走 `problem` 那条通道。
|
||||
DownloadOptionsLiteLoaderVanillaOnly => (
|
||||
"LiteLoader stacks on vanilla only — for Forge, run: ull install <forge id> --loader liteloader",
|
||||
"LiteLoader 只叠在原版上 —— 要叠 Forge 请运行:ull install <Forge 版本 id> --loader liteloader"
|
||||
),
|
||||
DownloadCancelled => (
|
||||
"Install cancelled — finished files are kept, the instance was not created",
|
||||
"安装已取消 —— 已下好的文件保留,实例未登记"
|
||||
|
||||
@@ -106,6 +106,7 @@ pub(super) const ROWS: &[(&str, &str, &str)] = &[
|
||||
("DownloadOptionsInstanceNameHint", "Empty = use the version id", "留空就用版本号"),
|
||||
("DownloadOptionsIncompatible", "{loader} has no builds for {version}", "{loader} 没有适配 {version} 的构建"),
|
||||
("DownloadOptionsNeedsAtLeast", "{loader} needs Minecraft {min} or newer", "{loader} 需要 Minecraft {min} 或更新"),
|
||||
("DownloadOptionsLiteLoaderVanillaOnly", "LiteLoader stacks on vanilla only — for Forge, run: ull install <forge id> --loader liteloader", "LiteLoader 只叠在原版上 —— 要叠 Forge 请运行:ull install <Forge 版本 id> --loader liteloader"),
|
||||
("DownloadCancelled", "Install cancelled — finished files are kept, the instance was not created", "安装已取消 —— 已下好的文件保留,实例未登记"),
|
||||
("LogsSubtitleIdle", "Nothing is running right now", "当前没有运行中的实例"),
|
||||
("LogsStatus", "{instance} · {when} · {outcome}", "{instance}|{when}|{outcome}"),
|
||||
|
||||
Reference in new issue
Block a user