feat(app-iced): Java 页「下载一个 JDK」+ 三个设置键(M197)

用户原话:「我们内置了那么多镜像源 甚至用户不能手动选择指定版本下载。」
「自动下载 jdk17 作为基准版本,后续在设置中提供多版本可供用户下载。」

- core:新增 `game::java::catalog`(8/11/17/21/25 五档 × 能承接的发行版 × 「该装哪档」),
  数据全部来自 `JdkVendor::supports` 与 `vendor::order`,不复制第二份真相。
- progress:`SourceFailed` 补一个结构化的 `kind`(在这之前只有中文 `reason`,双语界面
  要么放弃语言、要么放弃「哪个源为什么退避」这条用户可见信息)。
- app-iced:`downloads` 模块真下(后台线程 + `ProgressEmitter` + 快照),三态(选择列表 /
  下载中 / 失败)都能说出「命中的源 / 退避原因 / 试过哪些源」;成功后重扫并(在
  `java.auto_install` 开着且没有默认 JDK 时)把新装的那份设为默认。
- 三个设置键做成可改 UI:`java.installRoot` / `java.vendorPriority` / `java.auto_install`,
  各自带「现在生效什么、从哪一层来」(数据目录模式 / 地区默认序),改完回读落盘值。
- `State::satisfied` 换成带方向的 `Fit`:1.12.2 + Java 21 不再被说成「低于要求」。
- i18n:删掉 `SettingsJavaEmptyBody` / `SettingsJavaAddHint` 的 markdown 反引号;
  `SettingsJavaNeverScannedBody` 改成不与首屏自动扫矛盾的表述。
- 出图三张(选择列表 / 下载中 / 失败)在 DevDocs/artifacts/m197/。

顺带拆文件守 400 行:`golden/tail.rs` 的 M174 段搬到 `golden/tail_ai.rs`,
`pages/settings/java/{context,prefs,prefs_store,downloads,download_view}` 各自成模块。
This commit is contained in:
AskaEth committed 2026-11-08 20:49:56 +08:00
1 parent 329c529bea
commit ce463cc9b5
33 files changed
+3839 -322

No files matched your search

+170 -6
View File
@@ -30,13 +30,13 @@ macro_rules! settings_java_entries {
SettingsJavaScanDone => ("{count} JDK found", "找到 {count} 个 JDK"),
SettingsJavaNeverScanned => ("Not scanned yet", "还没扫描过"),
SettingsJavaNeverScannedBody => (
"Press Scan to look for installed JDKs (registry, common install folders, JAVA_HOME and PATH). Nothing runs until you do.",
"点「立即扫描」去找已装的 JDK(注册表、常见安装目录、JAVA_HOME 与 PATH)。在那之前启动器不会自己去扫。"
"The list is still empty. The launcher scans once by itself when the settings page opens; press Scan now to look again right away.",
"列表还是空的。打开设置页时启动器会自己扫一次;也可以点「立即扫描」立刻再扫一遍。"
),
SettingsJavaEmptyTitle => ("No Java runtime found", "未检测到 Java 运行时"),
SettingsJavaEmptyBody => (
"Nothing matched. Add the path of a JDK you already unpacked below, or install one with `ull java install 21` on the command line.",
"没找到任何 JDK。可以在下面手动加上你自己解压的那份,或者用命令行 `ull java install 21` 装一个。"
"Nothing matched. Add the path of a JDK you already unpacked below, or install one with ull java install 21 on the command line.",
"没找到任何 JDK。可以在下面手动加上你自己解压的那份,或者用命令行 ull java install 21 装一个。"
),
// ── 运行时列表
SettingsJavaDefault => ("Default", "默认"),
@@ -59,8 +59,8 @@ macro_rules! settings_java_entries {
"例:C:\\Program Files\\Java\\jdk-21"
),
SettingsJavaAddHint => (
"A JDK folder or its java executable. We run `java -version` on it; anything that cannot answer is refused.",
"JDK 目录或它的 java 可执行文件。会真跑一次 `java -version`;答不出话的一律拒绝。"
"A JDK folder or its java executable. We run java -version on it; anything that cannot answer is refused.",
"JDK 目录或它的 java 可执行文件。会真跑一次 java -version;答不出话的一律拒绝。"
),
SettingsJavaAddAction => ("Add", "添加"),
SettingsJavaAdded => ("Added {path}", "已添加 {path}"),
@@ -148,6 +148,170 @@ macro_rules! settings_java_entries {
"the settings file could not be written (disk full, no permission, or the value was rejected)",
"设置写不进去(磁盘满、没权限,或这个值被拒绝)"
),
// ── M197:版本与实例要求的匹配(两向)
SettingsJavaTooNew => (
"Above the requirement: this instance can only use Java {maximum} or older (the old loader cannot read newer class files)",
"高于要求:当前实例只能用 Java {maximum} 及以下(老加载器吃不了新 class 文件)"
),
// ── M197:下载一个 JDK(版本目录 / 下载中 / 失败三态)
SettingsJavaDownloadTitle => ("Download a JDK", "下载一个 JDK"),
SettingsJavaDownloadHint => (
"Downloads go through the built-in mirror table: in China the campus mirrors are tried first (Temurin over Tsinghua TUNA), and GitHub-hosted archives are fetched through gh-proxy. Every archive is verified against its SHA-256 before it is unpacked.",
"下载走内置镜像表:国内先试院校镜像(Temurin 走清华 TUNA),GitHub 上的归档套 gh-proxy。落盘前一律按 SHA-256 校验。"
),
SettingsJavaDownloadLts => ("LTS", "长期支持版(LTS)"),
SettingsJavaDownloadBaseline => ("Baseline (D13)", "基准版本(D13)"),
SettingsJavaDownloadVendors => ("Vendors: {vendors}", "发行版:{vendors}"),
SettingsJavaDownloadNoVendor => (
"No vendor publishes this major version on this platform.",
"这个平台上没有发行版发这个大版本。"
),
SettingsJavaDownloadAction => ("Install", "安装"),
SettingsJavaDownloadReinstall => ("Install again", "重装"),
SettingsJavaDownloadInstalled => ("Already installed: {path}", "已安装:{path}"),
SettingsJavaDownloadNeeded => (
"The current instance needs {requirement}.",
"当前实例需要 {requirement}。"
),
SettingsJavaDownloadFits => (
"Usable by the current instance",
"当前实例可用"
),
SettingsJavaDownloadTooLow => (
"The current instance needs Java {minimum} or newer, so installing this one will not start it.",
"当前实例需要 Java {minimum} 及以上 —— 装这一档也起不来。"
),
SettingsJavaDownloadTooHigh => (
"The current instance can only use Java {maximum} or older, so installing this one will not start it.",
"当前实例只能用 Java {maximum} 及以下 —— 装这一档也起不来。"
),
SettingsJavaDownloadRecommended => (
"Recommended for the current instance",
"为当前实例推荐这一档"
),
SettingsJavaDownloadBusy => ("Installing Java {major}…", "正在安装 Java {major}…"),
SettingsJavaDownloadPhasePreparing => ("Looking up the release…", "正在查版本…"),
SettingsJavaDownloadPhaseDownloading => (
"Downloading {percent}% ({done} of {total})",
"下载中 {percent}%({done} / {total})"
),
SettingsJavaDownloadPhaseVerifying => ("Verifying the archive…", "正在校验归档…"),
SettingsJavaDownloadPhaseExtracting => ("Unpacking…", "正在解压…"),
SettingsJavaDownloadSource => ("Source: {source}", "来源:{source}"),
SettingsJavaDownloadRetry => (
"{source} failed ({reason}); retry {attempt} in {seconds}s",
"{source} 失败({reason});{seconds} 秒后重试第 {attempt} 次"
),
SettingsJavaDownloadSwitch => ("Switching source: {from} → {to}", "换源:{from} → {to}"),
SettingsJavaDownloadDone => (
"Java {major} ({vendor}) is ready at {root} · source {source}",
"Java {major}({vendor})已就绪:{root} · 来源 {source}"
),
SettingsJavaDownloadDoneReused => (
"Java {major} ({vendor}) was already installed at {root}; nothing was downloaded.",
"Java {major}({vendor})之前已经装好:{root},这一次没有下载。"
),
SettingsJavaDownloadFailed => (
"Java {major} could not be installed; the last source tried was {source}. The full reason is in the log.",
"Java {major} 没装成;最后试到的源是 {source}。完整原因在日志里。"
),
SettingsJavaDownloadFailedNoSource => (
"Java {major} could not be installed: the version lookup itself failed. The full reason is in the log.",
"Java {major} 没装成:查版本这一步就失败了。完整原因在日志里。"
),
SettingsJavaDownloadFailedHint => (
"Check the network, or change the vendor order below.",
"先查网络,或者改下面的发行版顺序。"
),
SettingsJavaDownloadTriedHeader => ("Sources tried:", "试过的源:"),
SettingsJavaDownloadTried => ("{source}: {reason}", "{source}:{reason}"),
SettingsJavaDownloadRefused => ("Not started: {reason}", "没开始:{reason}"),
SettingsJavaReasonDownloadBusy => (
"another JDK install is already running",
"已经有一个 JDK 在装了"
),
SettingsJavaReasonDownloadUnknownMajor => (
"that major version is not in the catalog",
"目录里没有这个大版本"
),
SettingsJavaReasonDownloadNoVendor => (
"no vendor publishes that major version here",
"没有发行版在这里发这个大版本"
),
SettingsJavaReasonRootUnresolved => (
"the JDK install folder cannot be resolved on this system",
"这台机器上解析不出 JDK 安装目录"
),
// ── 源失败原因(结构化,`DownloadErrorKind` 的文案面;core 的原句只进日志)
SettingsJavaSourceReasonNotFound => (
"this mirror does not have that file (404)",
"这个镜像没有这个文件(404)"
),
SettingsJavaSourceReasonServer => (
"the server answered with a 5xx / 429 error",
"服务器报错 5xx / 429"
),
SettingsJavaSourceReasonTimeout => ("the request timed out", "请求超时"),
SettingsJavaSourceReasonNetwork => ("the connection failed", "连不上"),
SettingsJavaSourceReasonIntegrity => ("the checksum did not match", "校验不符"),
SettingsJavaSourceReasonIo => ("a local disk error", "本地磁盘错误"),
SettingsJavaSourceReasonOther => ("the request was rejected", "请求被拒"),
// ── M197:三个设置键(`java.installRoot` / `java.vendorPriority` / `java.auto_install`)
SettingsJavaInstallRoot => ("JDK install folder", "JDK 安装目录"),
SettingsJavaInstallRootPlaceholder => ("D:\\Java", "例:D:\\Java"),
SettingsJavaInstallRootHint => (
"Leave it empty to follow the data mode: portable keeps JDKs inside the launcher folder, standard uses the system Java folder. A path here overrides both, and JDKs land in <root>/<vendor>/<version>/.",
"留空 = 跟数据目录模式走:portable 放在启动器目录里,standard 放在系统 Java 目录。填了它覆盖前两者,JDK 落在 <root>/<发行方>/<版本>/。"
),
SettingsJavaInstallRootEffective => ("In effect: {mode} · {path}", "生效:{mode} · {path}"),
SettingsJavaInstallRootLayerSetting => (
"this comes from java.installRoot",
"这一项来自 java.installRoot"
),
SettingsJavaInstallRootLayerDataMode => (
"this comes from core.data_mode ({mode})",
"这一项来自 core.data_mode({mode})"
),
SettingsJavaInstallRootUnresolved => (
"The system Java folder cannot be resolved here. Type a folder above, or set core.data_mode back to portable.",
"这台机器上解析不出系统标准 Java 目录。在上面填一个目录,或把 core.data_mode 改回 portable。"
),
SettingsJavaVendorPriority => ("Vendor order", "发行版顺序"),
SettingsJavaVendorOrderEffective => ("In effect: {order}", "生效顺序:{order}"),
SettingsJavaVendorOrderLayerSetting => (
"this comes from java.vendorPriority",
"这一项来自 java.vendorPriority"
),
SettingsJavaVendorOrderLayerRegion => (
"this comes from the built-in order for your region ({region})",
"这一项来自内置的地区默认序({region})"
),
SettingsJavaRegionDomestic => ("China", "国内"),
SettingsJavaRegionGlobal => ("rest of the world", "国外"),
SettingsJavaVendorUp => ("Up", "上移"),
SettingsJavaVendorDown => ("Down", "下移"),
SettingsJavaVendorReset => ("Reset to the region default", "恢复地区默认序"),
SettingsJavaVendorSupports => ("ships {majors}", "发 {majors}"),
SettingsJavaAutoInstall => ("Prepare a JDK when none is found", "缺 JDK 时自动准备"),
SettingsJavaAutoInstallHint => (
"On: the catalog below marks the version the current instance needs, and a freshly installed JDK becomes the default when no default is set yet. Off: you pick everything yourself.",
"开:下面的目录会按当前实例的要求标出该装哪一档,装完之后若还没有默认 JDK 就自动设为默认。关:全部自己挑。"
),
SettingsJavaAutoInstallOn => ("on", "开"),
SettingsJavaAutoInstallOff => ("off", "关"),
SettingsJavaPrefsSave => ("Save", "保存"),
SettingsJavaPrefsSaved => (
"Saved and read back from disk: all three keys are in the settings file.",
"已保存并从磁盘读回:三个键都进配置文件了。"
),
SettingsJavaPrefsUnsaved => (
"There are unsaved changes in this section.",
"这一段有未保存的改动。"
),
SettingsJavaReasonInstallRootTooLong => (
"the folder path is too long",
"目录路径太长"
),
} }
};
}