feat: notification of dev/nightly version.
This commit is contained in:
@@ -43,6 +43,8 @@ public final class Metadata {
|
||||
public static final String PUBLISH_URL = "http://www.mcbbs.net/thread-142335-1-1.html";
|
||||
public static final String EULA_URL = "https://hmcl.huangyuhui.net/eula";
|
||||
|
||||
public static final String BUILD_CHANNEL = JarUtils.thisJar().flatMap(JarUtils::getManifest).map(manifest -> manifest.getMainAttributes().getValue("Build-Channel")).orElse("nightly");
|
||||
|
||||
public static final Path MINECRAFT_DIRECTORY = OperatingSystem.getWorkingDirectory("minecraft");
|
||||
public static final Path HMCL_DIRECTORY = getHMCLDirectory();
|
||||
|
||||
@@ -54,4 +56,16 @@ public final class Metadata {
|
||||
}
|
||||
return OperatingSystem.getWorkingDirectory("hmcl");
|
||||
}
|
||||
|
||||
public static boolean isStable() {
|
||||
return "stable".equals(BUILD_CHANNEL);
|
||||
}
|
||||
|
||||
public static boolean isDev() {
|
||||
return "dev".equals(BUILD_CHANNEL);
|
||||
}
|
||||
|
||||
public static boolean isNightly() {
|
||||
return !isStable() && !isDev();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,10 +44,13 @@ import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.text.TextFlow;
|
||||
import javafx.util.Callback;
|
||||
import javafx.util.Duration;
|
||||
import javafx.util.StringConverter;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.ui.construct.JFXHyperlink;
|
||||
import org.jackhuang.hmcl.util.Logging;
|
||||
import org.jackhuang.hmcl.util.ResourceNotFoundError;
|
||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||
@@ -55,9 +58,17 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.javafx.ExtendedProperties;
|
||||
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
@@ -65,6 +76,7 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
@@ -687,4 +699,36 @@ public final class FXUtils {
|
||||
|
||||
Controllers.showToast(i18n("message.copied"));
|
||||
}
|
||||
|
||||
public static TextFlow segmentToTextFlow(final String segment, Consumer<String> hyperlinkAction) throws ParserConfigurationException, IOException, SAXException {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document doc = builder.parse(new InputSource(new StringReader("<body>" + segment + "</body>")));
|
||||
Element r = doc.getDocumentElement();
|
||||
|
||||
NodeList children = r.getChildNodes();
|
||||
List<javafx.scene.Node> texts = new ArrayList<>();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
org.w3c.dom.Node node = children.item(i);
|
||||
|
||||
if (node instanceof Element) {
|
||||
Element element = (Element) node;
|
||||
if ("a".equals(element.getTagName())) {
|
||||
String href = element.getAttribute("href");
|
||||
JFXHyperlink hyperlink = new JFXHyperlink(element.getTextContent());
|
||||
hyperlink.setOnAction(e -> hyperlinkAction.accept(href));
|
||||
texts.add(hyperlink);
|
||||
} else if ("br".equals(element.getTagName())) {
|
||||
texts.add(new Text("\n"));
|
||||
} else {
|
||||
throw new IllegalArgumentException("unsupported tag " + element.getTagName());
|
||||
}
|
||||
} else {
|
||||
texts.add(new Text(node.getTextContent()));
|
||||
}
|
||||
}
|
||||
final TextFlow tf = new TextFlow(texts.toArray(new javafx.scene.Node[0]));
|
||||
return tf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui.construct;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.text.TextFlow;
|
||||
import org.jackhuang.hmcl.ui.Controllers;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
|
||||
public class AnnouncementCard extends VBox {
|
||||
|
||||
public AnnouncementCard(String title, String content) {
|
||||
TextFlow tf;
|
||||
try {
|
||||
tf = FXUtils.segmentToTextFlow(content, AnnouncementCard::onAction);
|
||||
} catch (Exception e) {
|
||||
LOG.log(Level.WARNING, "Failed to parse announcement content", e);
|
||||
tf = new TextFlow();
|
||||
tf.getChildren().setAll(new Text(content));
|
||||
}
|
||||
|
||||
Label label = new Label(title);
|
||||
label.getStyleClass().add("title");
|
||||
getChildren().setAll(label, tf);
|
||||
setSpacing(14);
|
||||
getStyleClass().addAll("card", "announcement");
|
||||
}
|
||||
|
||||
private static void onAction(String href) {
|
||||
if (href.startsWith("hmcl://")) {
|
||||
if ("hmcl://settings/feedback".equals(href)) {
|
||||
Controllers.getSettingsPage().showFeedback();
|
||||
Controllers.navigate(Controllers.getSettingsPage());
|
||||
}
|
||||
} else {
|
||||
FXUtils.openLink(href);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,10 @@ public class LauncherSettingsPage extends BorderPane implements DecoratorPage {
|
||||
tab.getSelectionModel().select(gameTab);
|
||||
}
|
||||
|
||||
public void showFeedback() {
|
||||
tab.getSelectionModel().select(feedbackTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadOnlyObjectProperty<State> stateProperty() {
|
||||
return state.getReadOnlyProperty();
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.jackhuang.hmcl.setting.Profiles;
|
||||
import org.jackhuang.hmcl.setting.Theme;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.ui.construct.AnnouncementCard;
|
||||
import org.jackhuang.hmcl.ui.construct.PopupMenu;
|
||||
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
|
||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||
@@ -73,8 +74,9 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
private final ObservableList<Node> versionNodes;
|
||||
private Profile profile;
|
||||
|
||||
private StackPane updatePane;
|
||||
private JFXButton menuButton;
|
||||
private final VBox announcementPane;
|
||||
private final StackPane updatePane;
|
||||
private final JFXButton menuButton;
|
||||
|
||||
{
|
||||
HBox titleNode = new HBox(8);
|
||||
@@ -92,6 +94,8 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
|
||||
setPadding(new Insets(20));
|
||||
|
||||
announcementPane = new VBox(16);
|
||||
|
||||
updatePane = new StackPane();
|
||||
updatePane.setVisible(false);
|
||||
updatePane.getStyleClass().add("bubble");
|
||||
@@ -198,7 +202,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
launchPane.getChildren().setAll(launchButton, separator, menuButton);
|
||||
}
|
||||
|
||||
getChildren().setAll(updatePane, launchPane);
|
||||
getChildren().setAll(announcementPane, updatePane, launchPane);
|
||||
|
||||
menu.setMaxHeight(365);
|
||||
menu.setMaxWidth(545);
|
||||
@@ -212,6 +216,14 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
Bindings.bindContent(menu.getContent(), versionNodes);
|
||||
}
|
||||
|
||||
public MainPage() {
|
||||
if (Metadata.isNightly()) {
|
||||
announcementPane.getChildren().add(new AnnouncementCard(i18n("update.channel.nightly.title"), i18n("update.channel.nightly.hint")));
|
||||
} else if (Metadata.isDev()) {
|
||||
announcementPane.getChildren().add(new AnnouncementCard(i18n("update.channel.dev.title"), i18n("update.channel.dev.hint")));
|
||||
}
|
||||
}
|
||||
|
||||
private void doAnimation(boolean show) {
|
||||
Duration duration = Duration.millis(320);
|
||||
Timeline nowAnimation = new Timeline();
|
||||
|
||||
@@ -120,6 +120,19 @@
|
||||
-fx-text-fill: rgba(0.0, 0.0, 0.0, 0.87);
|
||||
}
|
||||
|
||||
.announcement {
|
||||
|
||||
}
|
||||
|
||||
.announcement .title {
|
||||
-fx-font-size: 14px;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.announcement JFXHyperlink, .announcement Text {
|
||||
-fx-font-size: 12px;
|
||||
}
|
||||
|
||||
.rippler-container {
|
||||
-jfx-rippler-fill: #a2a2a2;
|
||||
}
|
||||
|
||||
@@ -839,8 +839,20 @@ system.operating_system=OS
|
||||
update=Update
|
||||
update.accept=Update
|
||||
update.changelog=Changes
|
||||
update.channel.dev=Update to beta version
|
||||
update.channel.stable=Update to stable version
|
||||
update.channel.dev=Beta
|
||||
update.channel.dev.hint=You are using the beta version, which may include some extra functionalities compared to the release version, only used for testing.\n\
|
||||
Beta 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\
|
||||
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.update=Update to beta version
|
||||
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\
|
||||
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\
|
||||
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.stable.update=Update to release version
|
||||
update.checking=Checking for updates
|
||||
update.failed=Failed to perform update
|
||||
update.found=Update Available!
|
||||
|
||||
@@ -838,8 +838,20 @@ system.operating_system=操作系統
|
||||
update=啟動器更新
|
||||
update.accept=更新
|
||||
update.changelog=更新日誌
|
||||
update.channel.dev=更新到開發版
|
||||
update.channel.stable=更新到建議版本
|
||||
update.channel.dev=測試版
|
||||
update.channel.dev.hint=你正在使用測試版。測試版包含一些未在正式版中包含的測試性功能,僅用於體驗新功能。\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> 或在回饋過程中作出貢獻以隱藏本提示。
|
||||
update.channel.dev.title=測試版提示
|
||||
update.channel.dev.update=更新到開發版
|
||||
update.channel.nightly=預覽版
|
||||
update.channel.nightly.hint=你正在使用預覽版。預覽版可能會每天更新一次,包含一些未在正式版和測試版中包含的測試性功能,僅用於體驗新功能\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> 或在回饋過程中作出貢獻以隱藏本提示。
|
||||
update.channel.nightly.title=預覽版提示
|
||||
update.channel.stable.update=更新到建議版本
|
||||
update.checking=正在檢查更新
|
||||
update.failed=更新失敗
|
||||
update.found=發現到更新
|
||||
|
||||
@@ -838,8 +838,20 @@ system.operating_system=操作系统
|
||||
update=启动器更新
|
||||
update.accept=更新
|
||||
update.changelog=更新日志
|
||||
update.channel.dev=更新到开发版
|
||||
update.channel.stable=更新到推荐版本
|
||||
update.channel.dev=测试版
|
||||
update.channel.dev.hint=你正在使用测试版。测试版包含一些未在正式版中包含的测试性功能,仅用于体验新功能。\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> 或在反馈过程中作出贡献以隐藏本提示。
|
||||
update.channel.dev.title=测试版提示
|
||||
update.channel.dev.update=更新到开发版
|
||||
update.channel.nightly=预览版
|
||||
update.channel.nightly.hint=你正在使用预览版。预览版可能会每天更新一次,包含一些未在正式版和测试版中包含的测试性功能,仅用于体验新功能。\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> 或在反馈过程中作出贡献以隐藏本提示。
|
||||
update.channel.nightly.title=预览版提示
|
||||
update.channel.stable.update=更新到推荐版本
|
||||
update.checking=正在检查更新
|
||||
update.failed=更新失败
|
||||
update.found=发现更新
|
||||
|
||||
Reference in New Issue
Block a user