From 315669fa595aea0f92ff7f1c239b7e87854948f0 Mon Sep 17 00:00:00 2001 From: Glavo Date: Fri, 3 Oct 2025 19:56:59 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E2=80=9C=E6=8F=90?= =?UTF-8?q?=E5=89=8D=E9=A2=84=E8=A7=88=20HMCL=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E2=80=9D=E9=80=89=E9=A1=B9=20(#4223)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jackhuang/hmcl/setting/Config.java | 15 ++++++++++ .../org/jackhuang/hmcl/ui/UpgradeDialog.java | 17 +++++++++-- .../jackhuang/hmcl/ui/main/SettingsPage.java | 9 ++++-- .../jackhuang/hmcl/ui/main/SettingsView.java | 10 +++++++ .../jackhuang/hmcl/upgrade/RemoteVersion.java | 12 ++++++-- .../jackhuang/hmcl/upgrade/UpdateChecker.java | 28 ++++++++++--------- .../resources/assets/lang/I18N.properties | 1 + .../resources/assets/lang/I18N_zh.properties | 1 + .../assets/lang/I18N_zh_CN.properties | 1 + 9 files changed, 72 insertions(+), 22 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java index bde5c4651c..62bb7760fd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java @@ -181,6 +181,9 @@ public static Config fromJson(String json) throws JsonParseException { @SerializedName("promptedVersion") private StringProperty promptedVersion = new SimpleStringProperty(); + @SerializedName("acceptPreviewUpdate") + private BooleanProperty acceptPreviewUpdate = new SimpleBooleanProperty(false); + @SerializedName("_version") private IntegerProperty configVersion = new SimpleIntegerProperty(0); @@ -671,6 +674,18 @@ public void setPromptedVersion(String promptedVersion) { this.promptedVersion.set(promptedVersion); } + public boolean isAcceptPreviewUpdate() { + return acceptPreviewUpdate.get(); + } + + public BooleanProperty acceptPreviewUpdateProperty() { + return acceptPreviewUpdate; + } + + public void setAcceptPreviewUpdate(boolean acceptPreviewUpdate) { + this.acceptPreviewUpdate.set(acceptPreviewUpdate); + } + public ObservableMap getShownTips() { return shownTips; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java index 73a48ea643..ddbe6808be 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java @@ -48,11 +48,22 @@ public UpgradeDialog(RemoteVersion remoteVersion, Runnable updateRunnable) { setBody(new ProgressIndicator()); String url = CHANGELOG_URL + remoteVersion.getChannel().channelName + ".html"; + boolean isPreview = remoteVersion.isPreview(); Task.supplyAsync(Schedulers.io(), () -> { Document document = Jsoup.parse(new URL(url), 30 * 1000); - Node node = document.selectFirst("#nowchange"); + String id = null; + Node node = null; + if (isPreview) { + id = "nowpreview"; + node = document.selectFirst("#" + id); + } + if (node == null) { + id = "nowchange"; + node = document.selectFirst("#" + id); + } + if (node == null || !"h1".equals(node.nodeName())) - throw new IOException("Cannot find #nowchange in document"); + throw new IOException("Cannot find current changelog in document"); HTMLRenderer renderer = new HTMLRenderer(uri -> { LOG.info("Open link: " + uri); @@ -60,7 +71,7 @@ public UpgradeDialog(RemoteVersion remoteVersion, Runnable updateRunnable) { }); do { - if ("h1".equals(node.nodeName()) && !"nowchange".equals(node.attr("id"))) { + if ("h1".equals(node.nodeName()) && !id.equals(node.attr("id"))) { break; } renderer.appendNode(node); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java index 90df9e610e..03db696d43 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java @@ -106,9 +106,12 @@ public SettingsPage() { chkUpdateStable.setUserData(UpdateChannel.STABLE); ObjectProperty updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class); updateChannel.set(UpdateChannel.getChannel()); - updateChannel.addListener((a, b, newValue) -> { - UpdateChecker.requestCheckUpdate(newValue); - }); + + InvalidationListener checkUpdateListener = e -> { + UpdateChecker.requestCheckUpdate(updateChannel.get(), previewPane.isSelected()); + }; + updateChannel.addListener(checkUpdateListener); + previewPane.selectedProperty().addListener(checkUpdateListener); // ==== } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java index 0dece1e9ae..ba945698d6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java @@ -37,6 +37,7 @@ import org.jackhuang.hmcl.ui.construct.ComponentList; import org.jackhuang.hmcl.ui.construct.ComponentSublist; import org.jackhuang.hmcl.ui.construct.MultiFileItem; +import org.jackhuang.hmcl.ui.construct.OptionToggleButton; import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.i18n.Locales.SupportedLocale; @@ -56,6 +57,7 @@ public abstract class SettingsView extends StackPane { protected final JFXRadioButton chkUpdateStable; protected final JFXRadioButton chkUpdateDev; protected final JFXButton btnUpdate; + protected final OptionToggleButton previewPane; protected final ScrollPane scroll; public SettingsView() { @@ -145,6 +147,14 @@ public SettingsView() { settingsPane.getContent().add(updatePane); } + { + previewPane = new OptionToggleButton(); + previewPane.setTitle(i18n("update.preview")); + previewPane.selectedProperty().bindBidirectional(config().acceptPreviewUpdateProperty()); + + settingsPane.getContent().add(previewPane); + } + { fileCommonLocation = new MultiFileItem<>(); fileCommonLocationSublist = new ComponentSublist(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java index c7f47426c9..dcbdb64850 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java @@ -29,7 +29,7 @@ public final class RemoteVersion { - public static RemoteVersion fetch(UpdateChannel channel, String url) throws IOException { + public static RemoteVersion fetch(UpdateChannel channel, boolean preview, String url) throws IOException { try { JsonObject response = JsonUtils.fromNonNullJson(NetworkUtils.doGet(NetworkUtils.toURL(url)), JsonObject.class); String version = Optional.ofNullable(response.get("version")).map(JsonElement::getAsString).orElseThrow(() -> new IOException("version is missing")); @@ -37,7 +37,7 @@ public static RemoteVersion fetch(UpdateChannel channel, String url) throws IOEx String jarHash = Optional.ofNullable(response.get("jarsha1")).map(JsonElement::getAsString).orElse(null); boolean force = Optional.ofNullable(response.get("force")).map(JsonElement::getAsBoolean).orElse(false); if (jarUrl != null && jarHash != null) { - return new RemoteVersion(channel, version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash), force); + return new RemoteVersion(channel, version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash), preview, force); } else { throw new IOException("No download url is available"); } @@ -51,14 +51,16 @@ public static RemoteVersion fetch(UpdateChannel channel, String url) throws IOEx private final String url; private final Type type; private final IntegrityCheck integrityCheck; + private final boolean preview; private final boolean force; - public RemoteVersion(UpdateChannel channel, String version, String url, Type type, IntegrityCheck integrityCheck, boolean force) { + public RemoteVersion(UpdateChannel channel, String version, String url, Type type, IntegrityCheck integrityCheck, boolean preview, boolean force) { this.channel = channel; this.version = version; this.url = url; this.type = type; this.integrityCheck = integrityCheck; + this.preview = preview; this.force = force; } @@ -82,6 +84,10 @@ public IntegrityCheck getIntegrityCheck() { return integrityCheck; } + public boolean isPreview() { + return preview; + } + public boolean isForce() { return force; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java index b4663b0f28..4f78569381 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java @@ -27,14 +27,15 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber; import java.io.IOException; +import java.util.LinkedHashMap; -import static org.jackhuang.hmcl.util.Lang.mapOf; -import static org.jackhuang.hmcl.util.Lang.thread; +import static org.jackhuang.hmcl.setting.ConfigHolder.config; +import static org.jackhuang.hmcl.util.Lang.*; import static org.jackhuang.hmcl.util.logging.Logger.LOG; -import static org.jackhuang.hmcl.util.Pair.pair; public final class UpdateChecker { - private UpdateChecker() {} + private UpdateChecker() { + } private static final ObjectProperty latestVersion = new SimpleObjectProperty<>(); private static final BooleanBinding outdated = Bindings.createBooleanBinding( @@ -55,7 +56,7 @@ private UpdateChecker() {} private static final ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false); public static void init() { - requestCheckUpdate(UpdateChannel.getChannel()); + requestCheckUpdate(UpdateChannel.getChannel(), config().isAcceptPreviewUpdate()); } public static RemoteVersion getLatestVersion() { @@ -82,16 +83,17 @@ public static ReadOnlyBooleanProperty checkingUpdateProperty() { return checkingUpdate.getReadOnlyProperty(); } - private static RemoteVersion checkUpdate(UpdateChannel channel) throws IOException { + private static RemoteVersion checkUpdate(UpdateChannel channel, boolean preview) throws IOException { if (!IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK && !IntegrityChecker.isSelfVerified()) { throw new IOException("Self verification failed"); } - String url = NetworkUtils.withQuery(Metadata.HMCL_UPDATE_URL, mapOf( - pair("version", Metadata.VERSION), - pair("channel", channel.channelName))); + LinkedHashMap query = new LinkedHashMap<>(); + query.put("version", Metadata.VERSION); + query.put("channel", preview ? channel.channelName + "-preview" : channel.channelName); - return RemoteVersion.fetch(channel, url); + String url = NetworkUtils.withQuery(Metadata.HMCL_UPDATE_URL, query); + return RemoteVersion.fetch(channel, preview, url); } private static boolean isDevelopmentVersion(String version) { @@ -99,7 +101,7 @@ private static boolean isDevelopmentVersion(String version) { version.contains("SNAPSHOT"); // eg. 3.5.SNAPSHOT } - public static void requestCheckUpdate(UpdateChannel channel) { + public static void requestCheckUpdate(UpdateChannel channel, boolean preview) { Platform.runLater(() -> { if (isCheckingUpdate()) return; @@ -108,8 +110,8 @@ public static void requestCheckUpdate(UpdateChannel channel) { thread(() -> { RemoteVersion result = null; try { - result = checkUpdate(channel); - LOG.info("Latest version (" + channel + ") is " + result); + result = checkUpdate(channel, preview); + LOG.info("Latest version (" + channel + ", preview=" + preview + ") is " + result); } catch (IOException e) { LOG.warning("Failed to check for update", e); } diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 1358acd865..50f36d311d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1423,6 +1423,7 @@ update.note=Beta and Nightly channels may have more features or fixes, but they update.latest=This is the latest version update.no_browser=Cannot open in system browser. But we copied the link to your clipboard, and you can open it manually. update.tooltip=Update +update.preview=Try out the HMCL version version=Games version.name=Instance Name diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 7d679e63b9..f3e5966a80 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -1207,6 +1207,7 @@ update.note=開發版與預覽版包含更多的功能以及錯誤修復,但 update.latest=目前版本為最新版本 update.no_browser=無法開啟瀏覽器。網址已經複製到剪貼簿了,你可以手動複製網址開啟頁面。 update.tooltip=更新 +update.preview=提前預覽 HMCL 版本 version=遊戲 version.name=遊戲實例名稱 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index ef6a8c9c5e..7daeafed4a 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1217,6 +1217,7 @@ update.note=开发版与预览版包含更多的功能以及错误修复,但 update.latest=当前版本为最新版本 update.no_browser=无法打开浏览器。网址已经复制到剪贴板,你可以手动粘贴网址打开页面。 update.tooltip=更新 +update.preview=提前预览 HMCL 版本 version=游戏 version.name=游戏实例名称 From b6451569fbe6ca41ad4c62e306e2d59a0b569bcc Mon Sep 17 00:00:00 2001 From: 3gf8jv4dv <3gf8jv4dv@gmail.com> Date: Fri, 10 Oct 2025 15:55:54 +0800 Subject: [PATCH 2/3] chore(docs&l10n): adjust preview update option text (#4598) --- .../src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java | 1 + HMCL/src/main/resources/assets/lang/I18N.properties | 3 ++- HMCL/src/main/resources/assets/lang/I18N_zh.properties | 3 ++- HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java index ba945698d6..64bf0e1181 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java @@ -151,6 +151,7 @@ public SettingsView() { previewPane = new OptionToggleButton(); previewPane.setTitle(i18n("update.preview")); previewPane.selectedProperty().bindBidirectional(config().acceptPreviewUpdateProperty()); + FXUtils.installFastTooltip(previewPane, i18n("update.preview.tooltip")); settingsPane.getContent().add(previewPane); } diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 50f36d311d..8019274886 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1423,7 +1423,8 @@ update.note=Beta and Nightly channels may have more features or fixes, but they update.latest=This is the latest version update.no_browser=Cannot open in system browser. But we copied the link to your clipboard, and you can open it manually. update.tooltip=Update -update.preview=Try out the HMCL version +update.preview=Preview HMCL releases early +update.preview.tooltip=Enable this option to receive new versions of HMCL early for testing before their official release. version=Games version.name=Instance Name diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index f3e5966a80..be67e7a6a8 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -1207,7 +1207,8 @@ update.note=開發版與預覽版包含更多的功能以及錯誤修復,但 update.latest=目前版本為最新版本 update.no_browser=無法開啟瀏覽器。網址已經複製到剪貼簿了,你可以手動複製網址開啟頁面。 update.tooltip=更新 -update.preview=提前預覽 HMCL 版本 +update.preview=提前測試 HMCL 預覽版本 +update.preview.tooltip=啟用此選項,你將可以提前取得 HMCL 的新版本,以便在正式發布前進行測試。 version=遊戲 version.name=遊戲實例名稱 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 7daeafed4a..119d94a70e 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1218,6 +1218,7 @@ update.latest=当前版本为最新版本 update.no_browser=无法打开浏览器。网址已经复制到剪贴板,你可以手动粘贴网址打开页面。 update.tooltip=更新 update.preview=提前预览 HMCL 版本 +update.preview.tooltip=启用此选项,你将可以提前获取 HMCL 的新版本,以便在正式发布前进行测试。 version=游戏 version.name=游戏实例名称 From 5cd9ed0492a3ed75580ad455f87e6e2da968a296 Mon Sep 17 00:00:00 2001 From: 3gf8jv4dv <3gf8jv4dv@gmail.com> Date: Sun, 12 Oct 2025 20:54:53 +0800 Subject: [PATCH 3/3] chore(l10n): add preview update option translation to spanish (#4599) --- HMCL/src/main/resources/assets/lang/I18N_es.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HMCL/src/main/resources/assets/lang/I18N_es.properties b/HMCL/src/main/resources/assets/lang/I18N_es.properties index cddb276cce..88f5439469 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -1419,6 +1419,8 @@ update.note=Advertencia: Las versiones beta y las versiones nocturnas pueden ten update.latest=Esta es la última versión. update.no_browser=No se puede abrir en el navegador del sistema. Pero, hemos copiado el enlace a su portapapeles y puede abrirlo manualmente. update.tooltip=Actualización +update.preview=Vista previa de actualizaciones anticipadas +update.preview.tooltip=Activa esta opción para recibir nuevas versiones del lanzador antes de su lanzamiento oficial para probarlas version=Juegos version.name=Nombre de instancia