diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 8a066debb..c6efa3008 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -37,6 +37,7 @@ import org.jackhuang.hmcl.task.*; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.DialogController; import org.jackhuang.hmcl.ui.LogWindow; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane; import org.jackhuang.hmcl.util.*; @@ -148,11 +149,11 @@ public final class LauncherHelper { else launchingStepsPane.setCancel(it -> { process.stop(); - Controllers.closeDialog(it); + it.fireEvent(new DialogCloseEvent()); }); } else Platform.runLater(() -> { - Controllers.closeDialog(launchingStepsPane); + launchingStepsPane.fireEvent(new DialogCloseEvent()); Controllers.dialog(i18n("version.launch_script.success", scriptFile.getAbsolutePath())); }); @@ -177,7 +178,7 @@ public final class LauncherHelper { // Check if the application has stopped // because onStop will be invoked if tasks fail when the executor service shut down. if (!Controllers.isStopped()) { - Controllers.closeDialog(launchingStepsPane); + launchingStepsPane.fireEvent(new DialogCloseEvent()); Exception ex = executor.getLastException(); if (ex != null) { String message; @@ -267,8 +268,9 @@ public final class LauncherHelper { } public void emitStatus(LoadingState state) { - if (state == LoadingState.DONE) - Controllers.closeDialog(launchingStepsPane); + if (state == LoadingState.DONE) { + launchingStepsPane.fireEvent(new DialogCloseEvent()); + } launchingStepsPane.setTitle(state.getLocalizedMessage()); launchingStepsPane.setSubtitle((state.ordinal() + 1) + " / " + LoadingState.values().length); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AccountLoginPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AccountLoginPane.java index f7f6195a7..89bd4c6bd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AccountLoginPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AccountLoginPane.java @@ -21,13 +21,13 @@ import com.jfoenix.controls.JFXPasswordField; import com.jfoenix.controls.JFXProgressBar; import javafx.fxml.FXML; import javafx.scene.control.Label; -import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.auth.AuthInfo; import org.jackhuang.hmcl.auth.NoSelectedCharacterException; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import java.util.function.Consumer; @@ -35,7 +35,6 @@ public class AccountLoginPane extends StackPane { private final Account oldAccount; private final Consumer success; private final Runnable failed; - private final Consumer closeConsumer; @FXML private Label lblUsername; @@ -43,11 +42,10 @@ public class AccountLoginPane extends StackPane { @FXML private Label lblCreationWarning; @FXML private JFXProgressBar progressBar; - public AccountLoginPane(Account oldAccount, Consumer closeConsumer, Consumer success, Runnable failed) { + public AccountLoginPane(Account oldAccount, Consumer success, Runnable failed) { this.oldAccount = oldAccount; this.success = success; this.failed = failed; - this.closeConsumer = closeConsumer; FXUtils.loadFXML(this, "/assets/fxml/account-login.fxml"); @@ -70,9 +68,9 @@ public class AccountLoginPane extends StackPane { Object account = variable.get("login"); if (account instanceof AuthInfo) { success.accept(((AuthInfo) account)); - closeConsumer.accept(this); + fireEvent(new DialogCloseEvent()); } else if (account instanceof NoSelectedCharacterException) { - closeConsumer.accept(this); + fireEvent(new DialogCloseEvent()); } else if (account instanceof Exception) { lblCreationWarning.setText(AddAccountPane.accountException((Exception) account)); } @@ -84,6 +82,6 @@ public class AccountLoginPane extends StackPane { @FXML private void onCancel() { failed.run(); - closeConsumer.accept(this); + fireEvent(new DialogCloseEvent()); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAccountPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAccountPane.java index 138acab4f..6724eb5bf 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAccountPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAccountPane.java @@ -28,7 +28,6 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import org.jackhuang.hmcl.auth.*; @@ -44,6 +43,7 @@ import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.construct.AdvancedListBox; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.IconedItem; import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.ui.construct.Validator; @@ -56,7 +56,6 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import java.util.List; import java.util.Optional; import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; import java.util.logging.Level; public class AddAccountPane extends StackPane { @@ -72,17 +71,13 @@ public class AddAccountPane extends StackPane { @FXML private JFXDialogLayout layout; @FXML private JFXButton btnAccept; @FXML private SpinnerPane acceptPane; - private final Consumer finalization; - - public AddAccountPane(Consumer finalization) { - this.finalization = finalization; + public AddAccountPane() { FXUtils.loadFXML(this, "/assets/fxml/account-add.fxml"); cboServers.setCellFactory(jfxListCellFactory(server -> new TwoLineListItem(server.getName(), server.getUrl()))); cboServers.setConverter(stringConverter(AuthlibInjectorServer::getName)); cboServers.setItems(Settings.SETTINGS.authlibInjectorServers); - cboServers.setPromptText(i18n("general.prompt.empty")); // workaround: otherwise the combox will be black if (!cboServers.getItems().isEmpty()) @@ -149,10 +144,10 @@ public class AddAccountPane extends StackPane { .finalized(Schedulers.javafx(), variables -> { Settings.INSTANCE.addAccount(variables.get("create_account")); acceptPane.hideSpinner(); - finalization.accept(this); + fireEvent(new DialogCloseEvent()); }, exception -> { if (exception instanceof NoSelectedCharacterException) { - finalization.accept(this); + fireEvent(new DialogCloseEvent()); } else { lblCreationWarning.setText(accountException(exception)); } @@ -162,12 +157,12 @@ public class AddAccountPane extends StackPane { @FXML private void onCreationCancel() { - finalization.accept(this); + fireEvent(new DialogCloseEvent()); } @FXML private void onManageInjecterServers() { - finalization.accept(this); + fireEvent(new DialogCloseEvent()); Controllers.navigate(Controllers.getServersPage()); } @@ -270,7 +265,7 @@ public class AddAccountPane extends StackPane { } return exception.getMessage(); } else { - return exception.getClass() + ": " + exception.getLocalizedMessage(); + return exception.getClass().getName() + ": " + exception.getLocalizedMessage(); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAuthlibInjectorServerPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAuthlibInjectorServerPane.java new file mode 100644 index 000000000..83a711ae0 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAuthlibInjectorServerPane.java @@ -0,0 +1,130 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2018 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui; + +import static org.jackhuang.hmcl.ui.FXUtils.loadFXML; +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +import java.io.IOException; +import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer; +import org.jackhuang.hmcl.setting.Settings; +import org.jackhuang.hmcl.task.Schedulers; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.ui.animation.ContainerAnimations; +import org.jackhuang.hmcl.ui.animation.TransitionHandler; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; +import org.jackhuang.hmcl.ui.construct.SpinnerPane; +import org.jackhuang.hmcl.util.NetworkUtils; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXDialogLayout; +import com.jfoenix.controls.JFXTextField; + +import javafx.beans.binding.Bindings; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.StackPane; + +public class AddAuthlibInjectorServerPane extends StackPane { + + @FXML private StackPane addServerContainer; + @FXML private Label lblServerUrl; + @FXML private Label lblServerName; + @FXML private Label lblCreationWarning; + @FXML private Label lblServerWarning; + @FXML private JFXTextField txtServerUrl; + @FXML private JFXDialogLayout addServerPane; + @FXML private JFXDialogLayout confirmServerPane; + @FXML private SpinnerPane nextPane; + @FXML private JFXButton btnAddNext; + + private TransitionHandler transitionHandler; + + private AuthlibInjectorServer serverBeingAdded; + + public AddAuthlibInjectorServerPane() { + loadFXML(this, "/assets/fxml/authlib-injector-server-add.fxml"); + transitionHandler = new TransitionHandler(addServerContainer); + transitionHandler.setContent(addServerPane, ContainerAnimations.NONE.getAnimationProducer()); + + btnAddNext.disableProperty().bind( + Bindings.createBooleanBinding(txtServerUrl::validate, txtServerUrl.textProperty()).not()); + nextPane.hideSpinner(); + } + + private String fixInputUrl(String url) { + if (!url.endsWith("/")) { + url += "/"; + } + return url; + } + + private String resolveFetchExceptionMessage(Throwable exception) { + if (exception instanceof IOException) { + return i18n("account.failed.connect_injector_server"); + } else { + return exception.getClass().getName() + ": " + exception.getLocalizedMessage(); + } + } + + @FXML + private void onAddCancel() { + fireEvent(new DialogCloseEvent()); + } + + @FXML + private void onAddNext() { + String url = fixInputUrl(txtServerUrl.getText()); + + nextPane.showSpinner(); + addServerPane.setDisable(true); + + Task.of(() -> { + serverBeingAdded = AuthlibInjectorServer.fetchServerInfo(url); + }).finalized(Schedulers.javafx(), (variables, isDependentsSucceeded) -> { + addServerPane.setDisable(false); + nextPane.hideSpinner(); + + if (isDependentsSucceeded) { + lblServerName.setText(serverBeingAdded.getName()); + lblServerUrl.setText(serverBeingAdded.getUrl()); + + lblServerWarning.setVisible("http".equals(NetworkUtils.toURL(serverBeingAdded.getUrl()).getProtocol())); + + transitionHandler.setContent(confirmServerPane, ContainerAnimations.SWIPE_LEFT.getAnimationProducer()); + } else { + lblCreationWarning.setText(resolveFetchExceptionMessage(variables.get("lastException"))); + } + }).start(); + + } + + @FXML + private void onAddPrev() { + transitionHandler.setContent(addServerPane, ContainerAnimations.SWIPE_RIGHT.getAnimationProducer()); + } + + @FXML + private void onAddFinish() { + if (!Settings.SETTINGS.authlibInjectorServers.contains(serverBeingAdded)) { + Settings.SETTINGS.authlibInjectorServers.add(serverBeingAdded); + } + fireEvent(new DialogCloseEvent()); + } + +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AuthlibInjectorServersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AuthlibInjectorServersPage.java index 7b676d198..937391866 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AuthlibInjectorServersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AuthlibInjectorServersPage.java @@ -1,134 +1,69 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2018 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ package org.jackhuang.hmcl.ui; -import com.jfoenix.controls.*; +import static java.util.stream.Collectors.toList; +import static org.jackhuang.hmcl.ui.FXUtils.loadFXML; +import static org.jackhuang.hmcl.ui.FXUtils.smoothScrolling; +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +import org.jackhuang.hmcl.setting.Settings; +import org.jackhuang.hmcl.ui.wizard.DecoratorPage; + +import javafx.beans.InvalidationListener; +import javafx.beans.WeakInvalidationListener; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.fxml.FXML; -import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; -import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer; -import org.jackhuang.hmcl.setting.Settings; -import org.jackhuang.hmcl.task.Schedulers; -import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.ui.animation.ContainerAnimations; -import org.jackhuang.hmcl.ui.animation.TransitionHandler; -import org.jackhuang.hmcl.ui.construct.SpinnerPane; -import org.jackhuang.hmcl.ui.wizard.DecoratorPage; -import org.jackhuang.hmcl.util.NetworkUtils; -import static java.util.stream.Collectors.toList; -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; - -import java.io.IOException; - public class AuthlibInjectorServersPage extends StackPane implements DecoratorPage { private final StringProperty title = new SimpleStringProperty(this, "title", i18n("account.injector.server")); @FXML private ScrollPane scrollPane; - @FXML private StackPane addServerContainer; - @FXML private Label lblServerUrl; - @FXML private Label lblServerName; - @FXML private Label lblCreationWarning; - @FXML private Label lblServerWarning; @FXML private VBox listPane; - @FXML private JFXTextField txtServerUrl; - @FXML private JFXDialogLayout addServerPane; - @FXML private JFXDialogLayout confirmServerPane; - @FXML private JFXDialog dialog; @FXML private StackPane contentPane; - @FXML private SpinnerPane nextPane; - @FXML private JFXButton btnAddNext; - private final TransitionHandler transitionHandler; + private InvalidationListener serversListener; - private AuthlibInjectorServer serverBeingAdded; + public AuthlibInjectorServersPage() { + loadFXML(this, "/assets/fxml/authlib-injector-servers.fxml"); + smoothScrolling(scrollPane); - { - FXUtils.loadFXML(this, "/assets/fxml/authlib-injector-servers.fxml"); - FXUtils.smoothScrolling(scrollPane); - transitionHandler = new TransitionHandler(addServerContainer); - - getChildren().remove(dialog); - dialog.setDialogContainer(this); - - txtServerUrl.textProperty().addListener((a, b, newValue) -> - btnAddNext.setDisable(!txtServerUrl.validate())); - - reload(); + serversListener = observable -> updateServersList(); + Settings.SETTINGS.authlibInjectorServers.addListener(new WeakInvalidationListener(serversListener)); + updateServersList(); } - private void removeServer(AuthlibInjectorServerItem item) { - Settings.SETTINGS.authlibInjectorServers.remove(item.getServer()); - reload(); - } - - private void reload() { + private void updateServersList() { listPane.getChildren().setAll( Settings.SETTINGS.authlibInjectorServers.stream() - .map(server -> new AuthlibInjectorServerItem(server, this::removeServer)) + .map(server -> new AuthlibInjectorServerItem(server, + item -> Settings.SETTINGS.authlibInjectorServers.remove(item.getServer()))) .collect(toList())); - if (Settings.SETTINGS.authlibInjectorServers.isEmpty()) { - onAdd(); - } } + @FXML private void onAdd() { - transitionHandler.setContent(addServerPane, ContainerAnimations.NONE.getAnimationProducer()); - txtServerUrl.setText(""); - txtServerUrl.resetValidation(); - lblCreationWarning.setText(""); - addServerPane.setDisable(false); - nextPane.hideSpinner(); - dialog.show(); - } - - @FXML - private void onAddCancel() { - dialog.close(); - } - - @FXML - private void onAddNext() { - String url = fixInputUrl(txtServerUrl.getText()); - - nextPane.showSpinner(); - addServerPane.setDisable(true); - - Task.of(() -> { - serverBeingAdded = AuthlibInjectorServer.fetchServerInfo(url); - }).finalized(Schedulers.javafx(), (variables, isDependentsSucceeded) -> { - nextPane.hideSpinner(); - addServerPane.setDisable(false); - - if (isDependentsSucceeded) { - lblServerName.setText(serverBeingAdded.getName()); - lblServerUrl.setText(serverBeingAdded.getUrl()); - - lblServerWarning.setVisible("http".equals(NetworkUtils.toURL(serverBeingAdded.getUrl()).getProtocol())); - - transitionHandler.setContent(confirmServerPane, ContainerAnimations.SWIPE_LEFT.getAnimationProducer()); - } else { - lblCreationWarning.setText(resolveFetchExceptionMessage(variables.get("lastException"))); - } - }).start(); - - } - - @FXML - private void onAddPrev() { - transitionHandler.setContent(addServerPane, ContainerAnimations.SWIPE_RIGHT.getAnimationProducer()); - } - - @FXML - private void onAddFinish() { - if (!Settings.INSTANCE.SETTINGS.authlibInjectorServers.contains(serverBeingAdded)) { - Settings.INSTANCE.SETTINGS.authlibInjectorServers.add(serverBeingAdded); - } - reload(); - dialog.close(); + Controllers.dialog(new AddAuthlibInjectorServerPane()); } public String getTitle() { @@ -143,19 +78,4 @@ public class AuthlibInjectorServersPage extends StackPane implements DecoratorPa public void setTitle(String title) { this.title.set(title); } - - private String fixInputUrl(String url) { - if (!url.endsWith("/")) { - url += "/"; - } - return url; - } - - private String resolveFetchExceptionMessage(Throwable exception) { - if (exception instanceof IOException) { - return i18n("account.failed.connect_injector_server"); - } else { - return exception.getClass() + ": " + exception.getLocalizedMessage(); - } - } } 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 4ae3bd74f..7edfd58db 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -26,6 +26,7 @@ import org.jackhuang.hmcl.Launcher; import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.InputDialogPane; import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; @@ -132,15 +133,15 @@ public final class Controllers { } public static void dialog(String text, String title, int type, Runnable onAccept) { - dialog(new MessageDialogPane(text, title, Controllers::closeDialog, type, onAccept)); + dialog(new MessageDialogPane(text, title, type, onAccept)); } public static void confirmDialog(String text, String title, Runnable onAccept, Runnable onCancel) { - dialog(new MessageDialogPane(text, title, Controllers::closeDialog, onAccept, onCancel)); + dialog(new MessageDialogPane(text, title, onAccept, onCancel)); } public static void inputDialog(String text, Consumer onResult) { - dialog(new InputDialogPane(text, Controllers::closeDialog, onResult)); + dialog(new InputDialogPane(text, onResult)); } public static Region taskDialog(TaskExecutor executor, String title, String subtitle) { @@ -156,6 +157,9 @@ public final class Controllers { return pane; } + /** + * Use {@link DialogCloseEvent} + */ public static void closeDialog(Region content) { if (stage == null) // shut down return; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java index afea4c9f9..d871f9d62 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java @@ -32,6 +32,7 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.geometry.BoundingBox; import javafx.geometry.Bounds; @@ -59,6 +60,7 @@ import org.jackhuang.hmcl.ui.animation.AnimationProducer; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.animation.TransitionHandler; import org.jackhuang.hmcl.ui.construct.AdvancedListBox; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.StackContainerPane; import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogWizardDisplayer; import org.jackhuang.hmcl.ui.wizard.*; @@ -67,6 +69,7 @@ import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.StringUtils; import java.io.File; import java.util.Locale; +import java.util.Optional; import java.util.Queue; import java.util.Random; import java.util.concurrent.ConcurrentLinkedQueue; @@ -81,6 +84,8 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza private static final SVGGlyph close = Lang.apply(new SVGGlyph(0, "CLOSE", "M810 274l-238 238 238 238-60 60-238-238-238 238-60-60 238-238-238-238 60-60 238 238 238-238z", Color.WHITE), glyph -> { glyph.setPrefSize(12, 12); glyph.setSize(12, 12); }); + private static final String PROPERTY_DIALOG_CLOSE_HANDLER = Decorator.class.getName() + ".dialog.closeListener"; + private final ObjectProperty onCloseButtonAction; private final BooleanProperty customMaximize = new SimpleBooleanProperty(false); @@ -563,20 +568,26 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza public void showDialog(Node node) { FXUtils.checkFxUserThread(); + EventHandler handler = event -> closeDialog(node); + node.getProperties().put(PROPERTY_DIALOG_CLOSE_HANDLER, handler); + node.addEventHandler(DialogCloseEvent.CLOSE, handler); + if (dialogPane.isEmpty()) dialog.show(); dialogPane.push(node); } + @SuppressWarnings("unchecked") public void closeDialog(Node node) { FXUtils.checkFxUserThread(); + Optional.ofNullable(node.getProperties().get(PROPERTY_DIALOG_CLOSE_HANDLER)) + .ifPresent(handler -> node.removeEventHandler(DialogCloseEvent.CLOSE, (EventHandler) handler)); + dialogPane.pop(node); - if (dialogPane.getChildren().isEmpty()) - Platform.runLater(() -> { - if (dialogPane.getChildren().isEmpty()) - dialog.close(); - }); + if (dialogPane.getChildren().isEmpty()) { + dialog.close(); + } } public void startWizard(WizardProvider wizardProvider) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogController.java index 16f9476dd..b0d4d5862 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogController.java @@ -34,7 +34,7 @@ public final class DialogController { CountDownLatch latch = new CountDownLatch(1); AtomicReference res = new AtomicReference<>(null); JFXUtilities.runInFX(() -> { - AccountLoginPane pane = new AccountLoginPane(account, Controllers::closeDialog, it -> { + AccountLoginPane pane = new AccountLoginPane(account, it -> { res.set(it); latch.countDown(); }, latch::countDown); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java index 164adfcae..f0d127d4d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java @@ -45,6 +45,7 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.ui.construct.AdvancedListBox; import org.jackhuang.hmcl.ui.construct.ClassTitle; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.IconedItem; import org.jackhuang.hmcl.ui.construct.RipplerContainer; import org.jackhuang.hmcl.util.Lang; @@ -100,7 +101,7 @@ public final class LeftPaneController { } private void addNewAccount() { - Controllers.dialog(new AddAccountPane(Controllers::closeDialog)); + Controllers.dialog(new AddAccountPane()); } private void onSelectedAccountChanged(Account newAccount) { @@ -228,7 +229,7 @@ public final class LeftPaneController { Modpack modpack = ModpackHelper.readModpackManifest(modpackFile); TaskExecutor executor = ModpackHelper.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack) .with(Task.of(Schedulers.javafx(), () -> { - Controllers.closeDialog(region.get()); + region.get().fireEvent(new DialogCloseEvent()); checkAccount(); })).executor(); region.set(Controllers.taskDialog(executor, i18n("modpack.installing"), "")); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java index 943a9ddb3..f1c30cf78 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java @@ -42,6 +42,7 @@ import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.ui.download.DownloadWizardProvider; import org.jackhuang.hmcl.ui.wizard.DecoratorPage; @@ -165,17 +166,17 @@ public final class MainPage extends StackPane implements DecoratorPage { AtomicReference region = new AtomicReference<>(); try { TaskExecutor executor = ModpackHelper.getUpdateTask(profile, selectedFile, id, ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(id))) - .then(Task.of(Schedulers.javafx(), () -> Controllers.closeDialog(region.get()))).executor(); + .then(Task.of(Schedulers.javafx(), () -> region.get().fireEvent(new DialogCloseEvent()))).executor(); region.set(Controllers.taskDialog(executor, i18n("modpack.update"), "")); executor.start(); } catch (UnsupportedModpackException e) { - Controllers.closeDialog(region.get()); + region.get().fireEvent(new DialogCloseEvent()); Controllers.dialog(i18n("modpack.unsupported"), i18n("message.error"), MessageBox.ERROR_MESSAGE); } catch (MismatchedModpackTypeException e) { - Controllers.closeDialog(region.get()); + region.get().fireEvent(new DialogCloseEvent()); Controllers.dialog(i18n("modpack.mismatched_type"), i18n("message.error"), MessageBox.ERROR_MESSAGE); } catch (IOException e) { - Controllers.closeDialog(region.get()); + region.get().fireEvent(new DialogCloseEvent()); Controllers.dialog(i18n("modpack.invalid"), i18n("message.error"), MessageBox.ERROR_MESSAGE); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/TwoLineListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/TwoLineListItem.java index b4380785e..2cbcc6a79 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/TwoLineListItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/TwoLineListItem.java @@ -1,3 +1,20 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2018 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ package org.jackhuang.hmcl.ui; import javafx.beans.property.SimpleStringProperty; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionHandler.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionHandler.java index cec4a9d47..8959c05e3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionHandler.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionHandler.java @@ -86,7 +86,7 @@ public final class TransitionHandler implements AnimationHandler { Timeline nowAnimation = new Timeline(); nowAnimation.getKeyFrames().addAll(transition.animate(this)); nowAnimation.getKeyFrames().add(new KeyFrame(duration, e -> { - previousNode.setMouseTransparent((Boolean) previousNode.getProperties().get(MOUSE_TRANSPARENT)); + view.setMouseTransparent(false); view.getChildren().remove(previousNode); })); nowAnimation.play(); @@ -98,21 +98,19 @@ public final class TransitionHandler implements AnimationHandler { if (view.getWidth() > 0 && view.getHeight() > 0) { previousNode = currentNode; if (previousNode == null) - previousNode = NULL; + previousNode = EMPTY_PANE; } else - previousNode = NULL; + previousNode = EMPTY_PANE; if (previousNode == newView) - previousNode = NULL; + previousNode = EMPTY_PANE; - previousNode.getProperties().put(MOUSE_TRANSPARENT, previousNode.isMouseTransparent()); - previousNode.setMouseTransparent(true); + view.setMouseTransparent(true); currentNode = newView; view.getChildren().setAll(previousNode, currentNode); } - private static final String MOUSE_TRANSPARENT = "TransitionHandler.MOUSE_TRANSPARENT"; - private static final StackPane NULL = new StackPane(); + private final StackPane EMPTY_PANE = new StackPane(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/DialogCloseEvent.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/DialogCloseEvent.java new file mode 100644 index 000000000..6b7d7656b --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/DialogCloseEvent.java @@ -0,0 +1,45 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2018 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui.construct; + +import org.jackhuang.hmcl.ui.Controllers; + +import javafx.event.Event; +import javafx.event.EventTarget; +import javafx.event.EventType; +import javafx.scene.layout.Region; + +/** + * Indicates a close operation on the dialog. + * + * @author yushijinhun + * @see Controllers#dialog(Region) + */ +public class DialogCloseEvent extends Event { + + public static final EventType CLOSE = new EventType<>("CLOSE"); + + public DialogCloseEvent() { + super(CLOSE); + } + + public DialogCloseEvent(Object source, EventTarget target) { + super(source, target, CLOSE); + } + +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/InputDialogPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/InputDialogPane.java index 5fbb315a7..8e7dfe365 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/InputDialogPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/InputDialogPane.java @@ -21,7 +21,6 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXTextField; import javafx.fxml.FXML; import javafx.scene.control.Label; -import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import org.jackhuang.hmcl.ui.FXUtils; @@ -38,13 +37,13 @@ public class InputDialogPane extends StackPane { @FXML private Label content; - public InputDialogPane(String text, Consumer closeConsumer, Consumer onResult) { + public InputDialogPane(String text, Consumer onResult) { FXUtils.loadFXML(this, "/assets/fxml/input-dialog.fxml"); content.setText(text); - cancelButton.setOnMouseClicked(e -> closeConsumer.accept(this)); + cancelButton.setOnMouseClicked(e -> fireEvent(new DialogCloseEvent())); acceptButton.setOnMouseClicked(e -> { onResult.accept(textField.getText()); - closeConsumer.accept(this); + fireEvent(new DialogCloseEvent()); }); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java index 4473a7c0b..842832d97 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java @@ -21,7 +21,6 @@ import com.jfoenix.controls.JFXButton; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import org.jackhuang.hmcl.setting.Theme; @@ -30,10 +29,8 @@ import org.jackhuang.hmcl.ui.SVG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import java.util.Optional; -import java.util.function.Consumer; public final class MessageDialogPane extends StackPane { - private boolean closingDialog = true; @FXML private JFXButton acceptButton; @@ -48,7 +45,7 @@ public final class MessageDialogPane extends StackPane { @FXML private HBox actions; - public MessageDialogPane(String text, String title, Consumer closeConsumer, int type, Runnable onAccept) { + public MessageDialogPane(String text, String title, int type, Runnable onAccept) { FXUtils.loadFXML(this, "/assets/fxml/message-dialog.fxml"); if (title != null) @@ -56,7 +53,7 @@ public final class MessageDialogPane extends StackPane { content.setText(text); acceptButton.setOnMouseClicked(e -> { - closeConsumer.accept(MessageDialogPane.this); + fireEvent(new DialogCloseEvent()); Optional.ofNullable(onAccept).ifPresent(Runnable::run); }); @@ -83,12 +80,12 @@ public final class MessageDialogPane extends StackPane { } } - public MessageDialogPane(String text, String title, Consumer closeConsumer, Runnable onAccept, Runnable onCancel) { - this(text, title, closeConsumer, MessageBox.QUESTION_MESSAGE, onAccept); + public MessageDialogPane(String text, String title, Runnable onAccept, Runnable onCancel) { + this(text, title, MessageBox.QUESTION_MESSAGE, onAccept); cancelButton.setVisible(true); cancelButton.setOnMouseClicked(e -> { - closeConsumer.accept(MessageDialogPane.this); + fireEvent(new DialogCloseEvent()); Optional.ofNullable(onCancel).ifPresent(Runnable::run); }); @@ -97,8 +94,4 @@ public final class MessageDialogPane extends StackPane { actions.getChildren().add(cancelButton); } - - public void disableClosingDialog() { - closingDialog = false; - } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskExecutorDialogWizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskExecutorDialogWizardDisplayer.java index e306d1586..4e4aeb76a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskExecutorDialogWizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskExecutorDialogWizardDisplayer.java @@ -35,7 +35,7 @@ public interface TaskExecutorDialogWizardDisplayer extends AbstractWizardDisplay @Override default void handleTask(Map settings, Task task) { TaskExecutorDialogPane pane = new TaskExecutorDialogPane(it -> { - Controllers.closeDialog(it); + it.fireEvent(new DialogCloseEvent()); Controllers.navigate(null); }); @@ -62,7 +62,7 @@ public interface TaskExecutorDialogWizardDisplayer extends AbstractWizardDisplay @Override public void onStop(boolean success, TaskExecutor executor) { JFXUtilities.runInFX(() -> { - Controllers.closeDialog(pane); + pane.fireEvent(new DialogCloseEvent()); if (success) { if (settings.containsKey("success_message") && settings.get("success_message") instanceof String) Controllers.dialog((String) settings.get("success_message"), null, MessageBox.FINE_MESSAGE, () -> Controllers.navigate(null)); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java index 50914c6a8..1cd70a89b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java @@ -27,6 +27,7 @@ import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.util.*; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -120,7 +121,7 @@ public class AppDataUpgrader extends IUpgrader { .directory(new File("").getAbsoluteFile()).start(); System.exit(0); } - JFXUtilities.runInFX(() -> Controllers.closeDialog(region.get())); + JFXUtilities.runInFX(() -> region.get().fireEvent(new DialogCloseEvent())); } catch (IOException ex) { Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex); } @@ -138,7 +139,7 @@ public class AppDataUpgrader extends IUpgrader { .directory(new File("").getAbsoluteFile()).start(); System.exit(0); } - JFXUtilities.runInFX(() -> Controllers.closeDialog(region.get())); + JFXUtilities.runInFX(() -> region.get().fireEvent(new DialogCloseEvent())); } catch (IOException ex) { Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java index a3344021f..d878fe963 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java @@ -24,6 +24,7 @@ import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.VersionNumber; import java.io.File; @@ -72,7 +73,7 @@ public class NewFileUpgrader extends IUpgrader { } System.exit(0); } - JFXUtilities.runInFX(() -> Controllers.closeDialog(region.get())); + JFXUtilities.runInFX(() -> region.get().fireEvent(new DialogCloseEvent())); } private static String getRealPath() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java index 5298829e0..33e9eb02e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java @@ -51,8 +51,6 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler { put("netscape.javascript.JSException", i18n("crash.NoClassDefFound")); put("java.lang.IncompatibleClassChangeError", i18n("crash.NoClassDefFound")); put("java.lang.ClassFormatError", i18n("crash.NoClassDefFound")); - put("java.lang.OutOfMemoryError", "FUCKING MEMORY LIMIT!"); - put("Trampoline", i18n("launcher.update_java")); put("com.sun.javafx.css.StyleManager.findMatchingStyles", i18n("launcher.update_java")); put("NoSuchAlgorithmException", "Has your operating system been installed completely or is a ghost system?"); } diff --git a/HMCL/src/main/resources/assets/fxml/account-add.fxml b/HMCL/src/main/resources/assets/fxml/account-add.fxml index cabe52503..2567bd210 100644 --- a/HMCL/src/main/resources/assets/fxml/account-add.fxml +++ b/HMCL/src/main/resources/assets/fxml/account-add.fxml @@ -29,7 +29,7 @@