添加“提前预览 HMCL 版本”选项 (#4223)
This commit is contained in:
@@ -250,6 +250,21 @@ public final class Config implements Observable {
|
|||||||
this.promptedVersion.set(promptedVersion);
|
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")
|
@SerializedName("shownTips")
|
||||||
private final ObservableMap<String, Object> shownTips = FXCollections.observableHashMap();
|
private final ObservableMap<String, Object> shownTips = FXCollections.observableHashMap();
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,22 @@ public final class UpgradeDialog extends JFXDialogLayout {
|
|||||||
setBody(new ProgressIndicator());
|
setBody(new ProgressIndicator());
|
||||||
|
|
||||||
String url = CHANGELOG_URL + remoteVersion.getChannel().channelName + ".html";
|
String url = CHANGELOG_URL + remoteVersion.getChannel().channelName + ".html";
|
||||||
|
boolean isPreview = remoteVersion.isPreview();
|
||||||
Task.supplyAsync(Schedulers.io(), () -> {
|
Task.supplyAsync(Schedulers.io(), () -> {
|
||||||
Document document = Jsoup.parse(new URL(url), 30 * 1000);
|
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()))
|
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 -> {
|
HTMLRenderer renderer = new HTMLRenderer(uri -> {
|
||||||
LOG.info("Open link: " + uri);
|
LOG.info("Open link: " + uri);
|
||||||
@@ -60,7 +71,7 @@ public final class UpgradeDialog extends JFXDialogLayout {
|
|||||||
});
|
});
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ("h1".equals(node.nodeName()) && !"nowchange".equals(node.attr("id"))) {
|
if ("h1".equals(node.nodeName()) && !id.equals(node.attr("id"))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
renderer.appendNode(node);
|
renderer.appendNode(node);
|
||||||
|
|||||||
@@ -114,9 +114,12 @@ public final class SettingsPage extends SettingsView {
|
|||||||
chkUpdateStable.setUserData(UpdateChannel.STABLE);
|
chkUpdateStable.setUserData(UpdateChannel.STABLE);
|
||||||
ObjectProperty<UpdateChannel> updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class);
|
ObjectProperty<UpdateChannel> updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class);
|
||||||
updateChannel.set(UpdateChannel.getChannel());
|
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);
|
||||||
// ====
|
// ====
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public abstract class SettingsView extends StackPane {
|
|||||||
protected final JFXRadioButton chkUpdateStable;
|
protected final JFXRadioButton chkUpdateStable;
|
||||||
protected final JFXRadioButton chkUpdateDev;
|
protected final JFXRadioButton chkUpdateDev;
|
||||||
protected final JFXButton btnUpdate;
|
protected final JFXButton btnUpdate;
|
||||||
|
protected final OptionToggleButton previewPane;
|
||||||
protected final ScrollPane scroll;
|
protected final ScrollPane scroll;
|
||||||
|
|
||||||
public SettingsView() {
|
public SettingsView() {
|
||||||
@@ -147,6 +148,14 @@ public abstract class SettingsView extends StackPane {
|
|||||||
settingsPane.getContent().add(updatePane);
|
settingsPane.getContent().add(updatePane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
previewPane = new OptionToggleButton();
|
||||||
|
previewPane.setTitle(i18n("update.preview"));
|
||||||
|
previewPane.selectedProperty().bindBidirectional(config().acceptPreviewUpdateProperty());
|
||||||
|
|
||||||
|
settingsPane.getContent().add(previewPane);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
fileCommonLocation = new MultiFileItem<>();
|
fileCommonLocation = new MultiFileItem<>();
|
||||||
fileCommonLocationSublist = new ComponentSublist();
|
fileCommonLocationSublist = new ComponentSublist();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public final class RemoteVersion {
|
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 {
|
try {
|
||||||
JsonObject response = JsonUtils.fromNonNullJson(NetworkUtils.doGet(url), JsonObject.class);
|
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"));
|
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);
|
String jarHash = Optional.ofNullable(response.get("jarsha1")).map(JsonElement::getAsString).orElse(null);
|
||||||
boolean force = Optional.ofNullable(response.get("force")).map(JsonElement::getAsBoolean).orElse(false);
|
boolean force = Optional.ofNullable(response.get("force")).map(JsonElement::getAsBoolean).orElse(false);
|
||||||
if (jarUrl != null && jarHash != null) {
|
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 {
|
} else {
|
||||||
throw new IOException("No download url is available");
|
throw new IOException("No download url is available");
|
||||||
}
|
}
|
||||||
@@ -51,14 +51,16 @@ public final class RemoteVersion {
|
|||||||
private final String url;
|
private final String url;
|
||||||
private final Type type;
|
private final Type type;
|
||||||
private final IntegrityCheck integrityCheck;
|
private final IntegrityCheck integrityCheck;
|
||||||
|
private final boolean preview;
|
||||||
private final boolean force;
|
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.channel = channel;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.integrityCheck = integrityCheck;
|
this.integrityCheck = integrityCheck;
|
||||||
|
this.preview = preview;
|
||||||
this.force = force;
|
this.force = force;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +84,10 @@ public final class RemoteVersion {
|
|||||||
return integrityCheck;
|
return integrityCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPreview() {
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isForce() {
|
public boolean isForce() {
|
||||||
return force;
|
return force;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,14 +27,15 @@ import org.jackhuang.hmcl.util.io.NetworkUtils;
|
|||||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.util.Lang.mapOf;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
import static org.jackhuang.hmcl.util.Lang.*;
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
|
||||||
|
|
||||||
public final class UpdateChecker {
|
public final class UpdateChecker {
|
||||||
private UpdateChecker() {}
|
private UpdateChecker() {
|
||||||
|
}
|
||||||
|
|
||||||
private static final ObjectProperty<RemoteVersion> latestVersion = new SimpleObjectProperty<>();
|
private static final ObjectProperty<RemoteVersion> latestVersion = new SimpleObjectProperty<>();
|
||||||
private static final BooleanBinding outdated = Bindings.createBooleanBinding(
|
private static final BooleanBinding outdated = Bindings.createBooleanBinding(
|
||||||
@@ -55,7 +56,7 @@ public final class UpdateChecker {
|
|||||||
private static final ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false);
|
private static final ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false);
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
requestCheckUpdate(UpdateChannel.getChannel());
|
requestCheckUpdate(UpdateChannel.getChannel(), config().isAcceptPreviewUpdate());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RemoteVersion getLatestVersion() {
|
public static RemoteVersion getLatestVersion() {
|
||||||
@@ -82,16 +83,17 @@ public final class UpdateChecker {
|
|||||||
return checkingUpdate.getReadOnlyProperty();
|
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()) {
|
if (!IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK && !IntegrityChecker.isSelfVerified()) {
|
||||||
throw new IOException("Self verification failed");
|
throw new IOException("Self verification failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
String url = NetworkUtils.withQuery(Metadata.HMCL_UPDATE_URL, mapOf(
|
var query = new LinkedHashMap<String, String>();
|
||||||
pair("version", Metadata.VERSION),
|
query.put("version", Metadata.VERSION);
|
||||||
pair("channel", channel.channelName)));
|
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) {
|
private static boolean isDevelopmentVersion(String version) {
|
||||||
@@ -99,7 +101,7 @@ public final class UpdateChecker {
|
|||||||
version.contains("SNAPSHOT"); // eg. 3.5.SNAPSHOT
|
version.contains("SNAPSHOT"); // eg. 3.5.SNAPSHOT
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void requestCheckUpdate(UpdateChannel channel) {
|
public static void requestCheckUpdate(UpdateChannel channel, boolean preview) {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (isCheckingUpdate())
|
if (isCheckingUpdate())
|
||||||
return;
|
return;
|
||||||
@@ -108,8 +110,8 @@ public final class UpdateChecker {
|
|||||||
thread(() -> {
|
thread(() -> {
|
||||||
RemoteVersion result = null;
|
RemoteVersion result = null;
|
||||||
try {
|
try {
|
||||||
result = checkUpdate(channel);
|
result = checkUpdate(channel, preview);
|
||||||
LOG.info("Latest version (" + channel + ") is " + result);
|
LOG.info("Latest version (" + channel + ", preview=" + preview + ") is " + result);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.warning("Failed to check for update", e);
|
LOG.warning("Failed to check for update", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.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.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.tooltip=Update
|
||||||
|
update.preview=Try out the HMCL version
|
||||||
|
|
||||||
version=Games
|
version=Games
|
||||||
version.name=Instance Name
|
version.name=Instance Name
|
||||||
|
|||||||
@@ -1227,6 +1227,7 @@ update.note=開發版與預覽版包含更多的功能以及錯誤修復,但
|
|||||||
update.latest=目前版本為最新版本
|
update.latest=目前版本為最新版本
|
||||||
update.no_browser=無法開啟瀏覽器。網址已經複製到剪貼簿了,你可以手動複製網址開啟頁面。
|
update.no_browser=無法開啟瀏覽器。網址已經複製到剪貼簿了,你可以手動複製網址開啟頁面。
|
||||||
update.tooltip=更新
|
update.tooltip=更新
|
||||||
|
update.preview=提前預覽 HMCL 版本
|
||||||
|
|
||||||
version=遊戲
|
version=遊戲
|
||||||
version.name=遊戲實例名稱
|
version.name=遊戲實例名稱
|
||||||
|
|||||||
@@ -1237,6 +1237,7 @@ update.note=开发版与预览版包含更多的功能以及错误修复,但
|
|||||||
update.latest=当前版本为最新版本
|
update.latest=当前版本为最新版本
|
||||||
update.no_browser=无法打开浏览器。网址已经复制到剪贴板,你可以手动粘贴网址打开页面。
|
update.no_browser=无法打开浏览器。网址已经复制到剪贴板,你可以手动粘贴网址打开页面。
|
||||||
update.tooltip=更新
|
update.tooltip=更新
|
||||||
|
update.preview=提前预览 HMCL 版本
|
||||||
|
|
||||||
version=游戏
|
version=游戏
|
||||||
version.name=游戏实例名称
|
version.name=游戏实例名称
|
||||||
|
|||||||
Reference in New Issue
Block a user