From 87af44328b091e70d2a3cbd183524d98356f7c8e Mon Sep 17 00:00:00 2001 From: Glavo Date: Fri, 3 Oct 2025 19:56:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E2=80=9C=E6=8F=90=E5=89=8D?= =?UTF-8?q?=E9=A2=84=E8=A7=88=20HMCL=20=E7=89=88=E6=9C=AC=E2=80=9D?= =?UTF-8?q?=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 | 9 ++++++ .../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, 71 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 24e8acfd6..46004c63e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java @@ -250,6 +250,21 @@ public final class Config implements Observable { this.promptedVersion.set(promptedVersion); } + @SerializedName("acceptPreviewUpdate") + private final BooleanProperty acceptPreviewUpdate = new SimpleBooleanProperty(false); + + public BooleanProperty acceptPreviewUpdateProperty() { + return acceptPreviewUpdate; + } + + public boolean isAcceptPreviewUpdate() { + return acceptPreviewUpdate.get(); + } + + public void setAcceptPreviewUpdate(boolean acceptPreviewUpdate) { + this.acceptPreviewUpdate.set(acceptPreviewUpdate); + } + @SerializedName("shownTips") private final ObservableMap shownTips = FXCollections.observableHashMap(); 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 73a48ea64..ddbe6808b 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 final class UpgradeDialog extends JFXDialogLayout { 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 final class UpgradeDialog extends JFXDialogLayout { }); 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 ccc97f26e..ddc700a71 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 @@ -114,9 +114,12 @@ public final class SettingsPage extends SettingsView { 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 d64abed46..a0bfefeee 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 @@ -58,6 +58,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() { @@ -147,6 +148,14 @@ public abstract class SettingsView extends StackPane { 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 848e03df7..142dcd6b1 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 @@ import java.util.Optional; 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(url), JsonObject.class); String version = Optional.ofNullable(response.get("version")).map(JsonElement::getAsString).orElseThrow(() -> new IOException("version is missing")); @@ -37,7 +37,7 @@ public final class RemoteVersion { 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 final class RemoteVersion { 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 final class RemoteVersion { 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 b4663b0f2..1504828d7 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.io.NetworkUtils; 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 @@ public final class 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 final class UpdateChecker { 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))); + var 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 @@ public final class UpdateChecker { 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 final class UpdateChecker { 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 3e813e492..b726771fa 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1443,6 +1443,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 29ce5106b..03aed69d5 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -1227,6 +1227,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 43603a3cb..f06245767 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1237,6 +1237,7 @@ update.note=开发版与预览版包含更多的功能以及错误修复,但 update.latest=当前版本为最新版本 update.no_browser=无法打开浏览器。网址已经复制到剪贴板,你可以手动粘贴网址打开页面。 update.tooltip=更新 +update.preview=提前预览 HMCL 版本 version=游戏 version.name=游戏实例名称