mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-10 12:26:16 -04:00
feat(update): update channel is bound to build type.
This commit is contained in:
parent
6221f4b616
commit
f014f59cf2
@ -164,9 +164,6 @@ public final class Config implements Cloneable, Observable {
|
|||||||
@SerializedName("authlibInjectorServers")
|
@SerializedName("authlibInjectorServers")
|
||||||
private ObservableList<AuthlibInjectorServer> authlibInjectorServers = FXCollections.observableArrayList(server -> new Observable[] { server });
|
private ObservableList<AuthlibInjectorServer> authlibInjectorServers = FXCollections.observableArrayList(server -> new Observable[] { server });
|
||||||
|
|
||||||
@SerializedName("updateChannel")
|
|
||||||
private ObjectProperty<UpdateChannel> updateChannel = new SimpleObjectProperty<>(UpdateChannel.STABLE);
|
|
||||||
|
|
||||||
@SerializedName("_version")
|
@SerializedName("_version")
|
||||||
private IntegerProperty configVersion = new SimpleIntegerProperty(0);
|
private IntegerProperty configVersion = new SimpleIntegerProperty(0);
|
||||||
|
|
||||||
@ -536,18 +533,6 @@ public final class Config implements Cloneable, Observable {
|
|||||||
return authlibInjectorServers;
|
return authlibInjectorServers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateChannel getUpdateChannel() {
|
|
||||||
return updateChannel.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectProperty<UpdateChannel> updateChannelProperty() {
|
|
||||||
return updateChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdateChannel(UpdateChannel updateChannel) {
|
|
||||||
this.updateChannel.set(updateChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getConfigVersion() {
|
public int getConfigVersion() {
|
||||||
return configVersion.get();
|
return configVersion.get();
|
||||||
}
|
}
|
||||||
|
@ -24,28 +24,28 @@ import javafx.scene.web.WebEngine;
|
|||||||
import javafx.scene.web.WebView;
|
import javafx.scene.web.WebView;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
||||||
|
import org.jackhuang.hmcl.upgrade.RemoteVersion;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.Metadata.CHANGELOG_URL;
|
import static org.jackhuang.hmcl.Metadata.CHANGELOG_URL;
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
|
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
|
||||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public class UpgradeDialog extends JFXDialogLayout {
|
public class UpgradeDialog extends JFXDialogLayout {
|
||||||
public UpgradeDialog(Runnable updateRunnable) {
|
public UpgradeDialog(RemoteVersion remoteVersion, Runnable updateRunnable) {
|
||||||
{
|
{
|
||||||
setHeading(new Label(i18n("update.changelog")));
|
setHeading(new Label(i18n("update.changelog")));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
String url = CHANGELOG_URL + config().getUpdateChannel().channelName + ".html";
|
String url = CHANGELOG_URL + remoteVersion.getChannel().channelName + ".html";
|
||||||
WebView webView = new WebView();
|
WebView webView = new WebView();
|
||||||
webView.getEngine().setUserDataDirectory(Metadata.HMCL_DIRECTORY.toFile());
|
webView.getEngine().setUserDataDirectory(Metadata.HMCL_DIRECTORY.toFile());
|
||||||
try {
|
try {
|
||||||
WebEngine engine = webView.getEngine();
|
WebEngine engine = webView.getEngine();
|
||||||
engine.load(CHANGELOG_URL + config().getUpdateChannel().channelName);
|
engine.load(CHANGELOG_URL + remoteVersion.getChannel().channelName);
|
||||||
engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
|
engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
String viewURL = engine.getLoadWorker().getMessage().trim();
|
String viewURL = engine.getLoadWorker().getMessage().trim();
|
||||||
if (!viewURL.startsWith(CHANGELOG_URL)) {
|
if (!viewURL.startsWith(CHANGELOG_URL)) {
|
||||||
|
@ -21,6 +21,7 @@ import javafx.application.Platform;
|
|||||||
import javafx.beans.InvalidationListener;
|
import javafx.beans.InvalidationListener;
|
||||||
import javafx.beans.WeakInvalidationListener;
|
import javafx.beans.WeakInvalidationListener;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
import org.jackhuang.hmcl.setting.Settings;
|
import org.jackhuang.hmcl.setting.Settings;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
@ -104,7 +105,11 @@ public final class SettingsPage extends SettingsView {
|
|||||||
chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT);
|
chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT);
|
||||||
chkUpdateStable.setToggleGroup(updateChannelGroup);
|
chkUpdateStable.setToggleGroup(updateChannelGroup);
|
||||||
chkUpdateStable.setUserData(UpdateChannel.STABLE);
|
chkUpdateStable.setUserData(UpdateChannel.STABLE);
|
||||||
selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class).bindBidirectional(config().updateChannelProperty());
|
ObjectProperty<UpdateChannel> updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class);
|
||||||
|
updateChannel.set(UpdateChannel.getChannel());
|
||||||
|
updateChannel.addListener((a, b, newValue) -> {
|
||||||
|
UpdateChecker.requestCheckUpdate(newValue);
|
||||||
|
});
|
||||||
// ====
|
// ====
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public class RemoteVersion {
|
public class RemoteVersion {
|
||||||
|
|
||||||
public static RemoteVersion fetch(String url) throws IOException {
|
public static RemoteVersion fetch(UpdateChannel channel, String url) throws IOException {
|
||||||
try {
|
try {
|
||||||
JsonObject response = JsonUtils.fromNonNullJson(NetworkUtils.doGet(NetworkUtils.toURL(url)), JsonObject.class);
|
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"));
|
String version = Optional.ofNullable(response.get("version")).map(JsonElement::getAsString).orElseThrow(() -> new IOException("version is missing"));
|
||||||
@ -39,9 +39,9 @@ public class RemoteVersion {
|
|||||||
String packXZUrl = Optional.ofNullable(response.get("packxz")).map(JsonElement::getAsString).orElse(null);
|
String packXZUrl = Optional.ofNullable(response.get("packxz")).map(JsonElement::getAsString).orElse(null);
|
||||||
String packXZHash = Optional.ofNullable(response.get("packxzsha1")).map(JsonElement::getAsString).orElse(null);
|
String packXZHash = Optional.ofNullable(response.get("packxzsha1")).map(JsonElement::getAsString).orElse(null);
|
||||||
if (Pack200Utils.isSupported() && packXZUrl != null && packXZHash != null) {
|
if (Pack200Utils.isSupported() && packXZUrl != null && packXZHash != null) {
|
||||||
return new RemoteVersion(version, packXZUrl, Type.PACK_XZ, new IntegrityCheck("SHA-1", packXZHash));
|
return new RemoteVersion(channel, version, packXZUrl, Type.PACK_XZ, new IntegrityCheck("SHA-1", packXZHash));
|
||||||
} else if (jarUrl != null && jarHash != null) {
|
} else if (jarUrl != null && jarHash != null) {
|
||||||
return new RemoteVersion(version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash));
|
return new RemoteVersion(channel, version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash));
|
||||||
} else {
|
} else {
|
||||||
throw new IOException("No download url is available");
|
throw new IOException("No download url is available");
|
||||||
}
|
}
|
||||||
@ -50,18 +50,24 @@ public class RemoteVersion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String version;
|
private final UpdateChannel channel;
|
||||||
private String url;
|
private final String version;
|
||||||
private Type type;
|
private final String url;
|
||||||
private IntegrityCheck integrityCheck;
|
private final Type type;
|
||||||
|
private final IntegrityCheck integrityCheck;
|
||||||
|
|
||||||
public RemoteVersion(String version, String url, Type type, IntegrityCheck integrityCheck) {
|
public RemoteVersion(UpdateChannel channel, String version, String url, Type type, IntegrityCheck integrityCheck) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UpdateChannel getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,26 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.upgrade;
|
package org.jackhuang.hmcl.upgrade;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.Metadata;
|
||||||
|
|
||||||
public enum UpdateChannel {
|
public enum UpdateChannel {
|
||||||
STABLE("stable"),
|
STABLE("stable"),
|
||||||
DEVELOPMENT("dev");
|
DEVELOPMENT("dev"),
|
||||||
|
NIGHTLY("nightly");
|
||||||
|
|
||||||
public final String channelName;
|
public final String channelName;
|
||||||
|
|
||||||
UpdateChannel(String channelName) {
|
UpdateChannel(String channelName) {
|
||||||
this.channelName = channelName;
|
this.channelName = channelName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UpdateChannel getChannel() {
|
||||||
|
if (Metadata.isDev()) {
|
||||||
|
return DEVELOPMENT;
|
||||||
|
} else if (Metadata.isNightly()) {
|
||||||
|
return NIGHTLY;
|
||||||
|
} else {
|
||||||
|
return STABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,14 +23,11 @@ import javafx.beans.binding.BooleanBinding;
|
|||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.value.ObservableBooleanValue;
|
import javafx.beans.value.ObservableBooleanValue;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.setting.ConfigHolder;
|
|
||||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
|
|
||||||
import static org.jackhuang.hmcl.util.Lang.mapOf;
|
import static org.jackhuang.hmcl.util.Lang.mapOf;
|
||||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
import static org.jackhuang.hmcl.util.Lang.thread;
|
||||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||||
@ -47,15 +44,16 @@ public final class UpdateChecker {
|
|||||||
if (latest == null || isDevelopmentVersion(Metadata.VERSION)) {
|
if (latest == null || isDevelopmentVersion(Metadata.VERSION)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return asVersion(latest.getVersion()).compareTo(asVersion(Metadata.VERSION)) > 0;
|
// We can update from development version to stable version,
|
||||||
|
// which can be downgrading.
|
||||||
|
return asVersion(latest.getVersion()).compareTo(asVersion(Metadata.VERSION)) != 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
latestVersion);
|
latestVersion);
|
||||||
private static ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false);
|
private static ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false);
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
ConfigHolder.config().updateChannelProperty().addListener(onInvalidating(UpdateChecker::requestCheckUpdate));
|
requestCheckUpdate(UpdateChannel.getChannel());
|
||||||
requestCheckUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RemoteVersion getLatestVersion() {
|
public static RemoteVersion getLatestVersion() {
|
||||||
@ -91,7 +89,7 @@ public final class UpdateChecker {
|
|||||||
pair("version", Metadata.VERSION),
|
pair("version", Metadata.VERSION),
|
||||||
pair("channel", channel.channelName)));
|
pair("channel", channel.channelName)));
|
||||||
|
|
||||||
return RemoteVersion.fetch(url);
|
return RemoteVersion.fetch(channel, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isDevelopmentVersion(String version) {
|
private static boolean isDevelopmentVersion(String version) {
|
||||||
@ -99,12 +97,11 @@ public final class UpdateChecker {
|
|||||||
version.contains("SNAPSHOT"); // eg. 3.1.SNAPSHOT
|
version.contains("SNAPSHOT"); // eg. 3.1.SNAPSHOT
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void requestCheckUpdate() {
|
public static void requestCheckUpdate(UpdateChannel channel) {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (isCheckingUpdate())
|
if (isCheckingUpdate())
|
||||||
return;
|
return;
|
||||||
checkingUpdate.set(true);
|
checkingUpdate.set(true);
|
||||||
UpdateChannel channel = config().getUpdateChannel();
|
|
||||||
|
|
||||||
thread(() -> {
|
thread(() -> {
|
||||||
RemoteVersion result = null;
|
RemoteVersion result = null;
|
||||||
@ -119,13 +116,7 @@ public final class UpdateChecker {
|
|||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
checkingUpdate.set(false);
|
checkingUpdate.set(false);
|
||||||
if (finalResult != null) {
|
if (finalResult != null) {
|
||||||
if (channel.equals(config().getUpdateChannel())) {
|
|
||||||
latestVersion.set(finalResult);
|
latestVersion.set(finalResult);
|
||||||
} else {
|
|
||||||
// the channel has been changed during the period
|
|
||||||
// check update again
|
|
||||||
requestCheckUpdate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, "Update Checker", true);
|
}, "Update Checker", true);
|
||||||
|
@ -891,14 +891,13 @@ update.channel.dev.hint=You are using the beta version, which may include some e
|
|||||||
If you met some problems, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report them, or join chat <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kaihei.co/Kx7n3t">KaiHeiLa</a> to report problems.\n\n\
|
If you met some problems, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report them, or join chat <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kaihei.co/Kx7n3t">KaiHeiLa</a> to report problems.\n\n\
|
||||||
To hide this hint, you need to <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">donate</a> or make impressive contribution in feedback.
|
To hide this hint, you need to <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">donate</a> or make impressive contribution in feedback.
|
||||||
update.channel.dev.title=Hints for beta version
|
update.channel.dev.title=Hints for beta version
|
||||||
update.channel.dev.update=Update to beta version
|
|
||||||
update.channel.nightly=Alpha
|
update.channel.nightly=Alpha
|
||||||
update.channel.nightly.hint=You are using the alpha version, which may include some extra functionalities compared to the beta and release version, only used for testing.\n\
|
update.channel.nightly.hint=You are using the alpha version, which may include some extra functionalities compared to the beta and release version, only used for testing.\n\
|
||||||
Alpha version should be unstable!\n\
|
Alpha version should be unstable!\n\
|
||||||
If you met some problems, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report them, or join chat <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kaihei.co/Kx7n3t">KaiHeiLa</a> to report problems.\n\n\
|
If you met some problems, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report them, or join chat <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kaihei.co/Kx7n3t">KaiHeiLa</a> to report problems.\n\n\
|
||||||
To hide this hint, you need to <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">donate</a> or make impressive contribution in feedback.
|
To hide this hint, you need to <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">donate</a> or make impressive contribution in feedback.
|
||||||
update.channel.nightly.title=Hints for alpha version
|
update.channel.nightly.title=Hints for alpha version
|
||||||
update.channel.stable.update=Update to release version
|
update.channel.stable=Release
|
||||||
update.checking=Checking for updates
|
update.checking=Checking for updates
|
||||||
update.failed=Failed to perform update
|
update.failed=Failed to perform update
|
||||||
update.found=Update Available!
|
update.found=Update Available!
|
||||||
|
@ -890,14 +890,13 @@ update.channel.dev.hint=你正在使用測試版。測試版包含一些未在
|
|||||||
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kaihei.co/Kx7n3t">開黑啦</a>群以回饋問題。\n\n\
|
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kaihei.co/Kx7n3t">開黑啦</a>群以回饋問題。\n\n\
|
||||||
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">贊助</a> 或在回饋過程中作出貢獻以隱藏本提示。
|
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">贊助</a> 或在回饋過程中作出貢獻以隱藏本提示。
|
||||||
update.channel.dev.title=測試版提示
|
update.channel.dev.title=測試版提示
|
||||||
update.channel.dev.update=更新到開發版
|
|
||||||
update.channel.nightly=預覽版
|
update.channel.nightly=預覽版
|
||||||
update.channel.nightly.hint=你正在使用預覽版。預覽版可能會每天更新一次,包含一些未在正式版和測試版中包含的測試性功能,僅用於體驗新功能\n\
|
update.channel.nightly.hint=你正在使用預覽版。預覽版可能會每天更新一次,包含一些未在正式版和測試版中包含的測試性功能,僅用於體驗新功能\n\
|
||||||
測試版功能未受充分驗證,使用起來可能不穩定!\n\
|
測試版功能未受充分驗證,使用起來可能不穩定!\n\
|
||||||
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kaihei.co/Kx7n3t">開黑啦</a>群以回饋問題。\n\n\
|
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kaihei.co/Kx7n3t">開黑啦</a>群以回饋問題。\n\n\
|
||||||
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">贊助</a> 或在回饋過程中作出貢獻以隱藏本提示。
|
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">贊助</a> 或在回饋過程中作出貢獻以隱藏本提示。
|
||||||
update.channel.nightly.title=預覽版提示
|
update.channel.nightly.title=預覽版提示
|
||||||
update.channel.stable.update=更新到建議版本
|
update.channel.stable=建議版本
|
||||||
update.checking=正在檢查更新
|
update.checking=正在檢查更新
|
||||||
update.failed=更新失敗
|
update.failed=更新失敗
|
||||||
update.found=發現到更新
|
update.found=發現到更新
|
||||||
|
@ -890,14 +890,13 @@ update.channel.dev.hint=你正在使用测试版。测试版包含一些未在
|
|||||||
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kaihei.co/Kx7n3t">开黑啦</a>群以反馈问题。\n\n\
|
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kaihei.co/Kx7n3t">开黑啦</a>群以反馈问题。\n\n\
|
||||||
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">赞助</a> 或在反馈过程中作出贡献以隐藏本提示。
|
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">赞助</a> 或在反馈过程中作出贡献以隐藏本提示。
|
||||||
update.channel.dev.title=测试版提示
|
update.channel.dev.title=测试版提示
|
||||||
update.channel.dev.update=更新到开发版
|
|
||||||
update.channel.nightly=预览版
|
update.channel.nightly=预览版
|
||||||
update.channel.nightly.hint=你正在使用预览版。预览版可能会每天更新一次,包含一些未在正式版和测试版中包含的测试性功能,仅用于体验新功能。\n\
|
update.channel.nightly.hint=你正在使用预览版。预览版可能会每天更新一次,包含一些未在正式版和测试版中包含的测试性功能,仅用于体验新功能。\n\
|
||||||
测试版功能未受充分验证,使用起来可能不稳定!<a href="https://hmcl.huangyuhui.net/download">下载稳定版</a>\n\
|
测试版功能未受充分验证,使用起来可能不稳定!<a href="https://hmcl.huangyuhui.net/download">下载稳定版</a>\n\
|
||||||
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kaihei.co/Kx7n3t">开黑啦</a>群以反馈问题。\n\n\
|
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kaihei.co/Kx7n3t">开黑啦</a>群以反馈问题。\n\n\
|
||||||
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">赞助</a> 或在反馈过程中作出贡献以隐藏本提示。
|
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">赞助</a> 或在反馈过程中作出贡献以隐藏本提示。
|
||||||
update.channel.nightly.title=预览版提示
|
update.channel.nightly.title=预览版提示
|
||||||
update.channel.stable.update=更新到推荐版本
|
update.channel.stable=推荐版本
|
||||||
update.checking=正在检查更新
|
update.checking=正在检查更新
|
||||||
update.failed=更新失败
|
update.failed=更新失败
|
||||||
update.found=发现更新
|
update.found=发现更新
|
||||||
|
Loading…
x
Reference in New Issue
Block a user