diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java index 4993bb7019..8c8ba92f02 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -63,6 +63,7 @@ import org.jackhuang.hmcl.ui.versions.GameListPage; import org.jackhuang.hmcl.ui.versions.VersionPage; import org.jackhuang.hmcl.ui.versions.Versions; +import org.jackhuang.hmcl.upgrade.UpdateChecker; import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.Architecture; @@ -318,6 +319,12 @@ public static void initialize(Stage stage) { stage.setOnCloseRequest(e -> Launcher.stopApplication()); decorator = new DecoratorController(stage, getRootPage()); + getRootPage().getMainPage().showUpdateProperty().bind(UpdateChecker.checkingUpdateProperty().not().and(UpdateChecker.outdatedProperty())); + getRootPage().getMainPage().showUpdateDialogProperty().bind( + decorator.backableProperty().not() + .and(getRootPage().getMainPage().showUpdateProperty()) + .and(config().disableAutoShowUpdateDialogProperty().not()) + ); if (config().getCommonDirType() == EnumCommonDirectory.CUSTOM && !FileUtils.canCreateDirectory(config().getCommonDirectory())) { @@ -503,6 +510,11 @@ public static void confirmWithCountdown(String text, String title, int seconds, timeline.play(); } + public static void dialogLater(Region content) { + if (decorator != null) + decorator.showDialogLater(content); + } + public static CompletableFuture prompt(String title, FutureCallback onResult) { return prompt(title, onResult, ""); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogUtils.java index faae25cbdf..b77360c3ec 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogUtils.java @@ -31,7 +31,9 @@ import org.jackhuang.hmcl.ui.decorator.Decorator; import org.jetbrains.annotations.Nullable; +import java.util.LinkedList; import java.util.Optional; +import java.util.Queue; import java.util.function.Consumer; public final class DialogUtils { @@ -45,6 +47,8 @@ private DialogUtils() { public static final String PROPERTY_PARENT_PANE_REF = DialogUtils.class.getName() + ".dialog.parentPaneRef"; public static final String PROPERTY_PARENT_DIALOG_REF = DialogUtils.class.getName() + ".dialog.parentDialogRef"; + public static final String PROPERTY_DIALOG_SHOW_LATER = DialogUtils.class.getName() + ".dialog.showLater"; + public static void show(Decorator decorator, Node content) { if (decorator.getDrawerWrapper() == null) { Platform.runLater(() -> show(decorator, content)); @@ -121,6 +125,30 @@ public void changed(ObservableValue observable, Boolean oldVa } } + public static void showLater(Decorator decorator, Node content) { + if (decorator.getDrawerWrapper() == null) { + Platform.runLater(() -> showLater(decorator, content)); + return; + } + showLater(decorator.getDrawerWrapper(), () -> show(decorator, content)); + } + + @SuppressWarnings("unchecked") + public static void showLater(StackPane container, Runnable showDialogAction) { + FXUtils.checkFxUserThread(); + + if (container.getProperties().get(PROPERTY_DIALOG_INSTANCE) == null) { + showDialogAction.run(); + return; + } + Queue queue = (Queue) container.getProperties().get(PROPERTY_DIALOG_SHOW_LATER); + if (queue == null) { + queue = new LinkedList<>(); + container.getProperties().put(PROPERTY_DIALOG_SHOW_LATER, queue); + } + queue.add(showDialogAction); + } + @SuppressWarnings("unchecked") public static void close(Node content) { FXUtils.checkFxUserThread(); @@ -131,6 +159,8 @@ public static void close(Node content) { JFXDialogPane pane = (JFXDialogPane) content.getProperties().get(PROPERTY_PARENT_PANE_REF); JFXDialog dialog = (JFXDialog) content.getProperties().get(PROPERTY_PARENT_DIALOG_REF); + Runnable showNextDialogAction = null; + if (dialog != null && pane != null) { if (pane.size() == 1 && pane.peek().orElse(null) == content) { dialog.setOnDialogClosed(e -> pane.pop(content)); @@ -142,6 +172,12 @@ public static void close(Node content) { container.getProperties().remove(PROPERTY_DIALOG_PANE_INSTANCE); container.getProperties().remove(PROPERTY_PARENT_DIALOG_REF); container.getProperties().remove(PROPERTY_PARENT_PANE_REF); + + Queue queue = (Queue) container.getProperties().get(PROPERTY_DIALOG_SHOW_LATER); + if (queue != null && !queue.isEmpty()) { + Runnable next = queue.remove(); + if (next != null) showNextDialogAction = next; + } } } else { pane.pop(content); @@ -151,5 +187,7 @@ public static void close(Node content) { dialogAware.onDialogClosed(); } } + + if (showNextDialogAction != null) showNextDialogAction.run(); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java index 3e5d0a617f..6fe6e1b20b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java @@ -22,6 +22,7 @@ import javafx.animation.Interpolator; import javafx.beans.InvalidationListener; import javafx.beans.WeakInvalidationListener; +import javafx.beans.property.BooleanProperty; import javafx.geometry.Insets; import javafx.scene.Node; import javafx.scene.image.Image; @@ -343,6 +344,10 @@ public void navigate(Node node, AnimationProducer animationProducer, Duration du navigator.navigate(node, animationProducer, duration, interpolator); } + public BooleanProperty backableProperty() { + return navigator.backableProperty(); + } + private void close() { if (navigator.getCurrentPage() instanceof DecoratorPage) { DecoratorPage page = (DecoratorPage) navigator.getCurrentPage(); @@ -427,6 +432,10 @@ private void closeDialog(Node node) { DialogUtils.close(node); } + public void showDialogLater(Node node) { + DialogUtils.showLater(decorator, node); + } + // ==== Toast ==== public void showToast(String content) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java index 3393035fc6..9b721cadaa 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java @@ -90,6 +90,7 @@ public final class MainPage extends StackPane implements DecoratorPage { private final StringProperty currentGame = new SimpleStringProperty(this, "currentGame"); private final BooleanProperty showUpdate = new SimpleBooleanProperty(this, "showUpdate"); + private final BooleanProperty showUpdateDialog = new SimpleBooleanProperty(this, "showUpdateDialog"); private final ObjectProperty latestVersion = new SimpleObjectProperty<>(this, "latestVersion"); private final ObservableList versions = FXCollections.observableArrayList(); private Profile profile; @@ -98,6 +99,8 @@ public final class MainPage extends StackPane implements DecoratorPage { private final StackPane updatePane; private final JFXButton menuButton; + private RemoteVersion lastShownVersion; + { HBox titleNode = new HBox(8); titleNode.setPadding(new Insets(0, 0, 0, 2)); @@ -170,7 +173,8 @@ public final class MainPage extends StackPane implements DecoratorPage { FXUtils.setLimitHeight(updatePane, 55); StackPane.setAlignment(updatePane, Pos.TOP_RIGHT); FXUtils.onClicked(updatePane, this::onUpgrade); - FXUtils.onChange(showUpdateProperty(), this::showUpdate); + FXUtils.onChange(showUpdateProperty(), this::doAnimation); + FXUtils.onChange(showUpdateDialogProperty(), this::showUpdateDialog); { HBox hBox = new HBox(); @@ -274,13 +278,12 @@ public void accept(String currentGame) { } - private void showUpdate(boolean show) { - doAnimation(show); - - if (show && !config().isDisableAutoShowUpdateDialog() - && getLatestVersion() != null - && !Objects.equals(config().getPromptedVersion(), getLatestVersion().getVersion())) { - Controllers.dialog(new MessageDialogPane.Builder("", i18n("update.bubble.title", getLatestVersion().getVersion()), MessageDialogPane.MessageType.INFO) + private void showUpdateDialog(boolean show) { + if (show && getLatestVersion() != null && getLatestVersion() != lastShownVersion + && !Objects.equals(config().getPromptedVersion(), getLatestVersion().getVersion()) + ) { + lastShownVersion = getLatestVersion(); + Controllers.dialogLater(new MessageDialogPane.Builder("", i18n("update.bubble.title", getLatestVersion().getVersion()), MessageDialogPane.MessageType.INFO) .addAction(i18n("button.view"), () -> { config().setPromptedVersion(getLatestVersion().getVersion()); onUpgrade(); @@ -362,8 +365,8 @@ private void onUpgrade() { } private void closeUpdateBubble() { - showUpdate.unbind(); - showUpdate.set(false); + showUpdateDialog.unbind(); + showUpdateDialog.set(false); } @Override @@ -403,6 +406,18 @@ public void setShowUpdate(boolean showUpdate) { this.showUpdate.set(showUpdate); } + public boolean isShowUpdateDialog() { + return showUpdateDialog.get(); + } + + public BooleanProperty showUpdateDialogProperty() { + return showUpdateDialog; + } + + public void setShowUpdateDialog(boolean showUpdateDialog) { + this.showUpdateDialog.set(showUpdateDialog); + } + public RemoteVersion getLatestVersion() { return latestVersion.get(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java index 32e7b24ca8..9bc78247e0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java @@ -117,7 +117,6 @@ public MainPage getMainPage() { }); FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), mainPage::setCurrentGame); - mainPage.showUpdateProperty().bind(UpdateChecker.outdatedProperty()); mainPage.latestVersionProperty().bind(UpdateChecker.latestVersionProperty()); Profiles.registerVersionsListener(profile -> { 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 7d4fa507c6..a5076d1cee 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java @@ -118,10 +118,10 @@ public static void requestCheckUpdate(UpdateChannel channel, boolean preview) { RemoteVersion finalResult = result; Platform.runLater(() -> { - checkingUpdate.set(false); if (finalResult != null) { latestVersion.set(finalResult); } + checkingUpdate.set(false); }); }, "Update Checker", true); });