From 1b8cf6b1e5a8251fbc311c3379b31924447507a9 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Wed, 6 Oct 2021 17:05:51 +0800 Subject: [PATCH] feat(ui): decorator page animation.. --- .../org/jackhuang/hmcl/ui/Controllers.java | 3 +- .../hmcl/ui/account/AccountListPage.java | 141 ++++++++---------- .../hmcl/ui/animation/TransitionPane.java | 5 +- .../ui/decorator/DecoratorAnimatedPage.java | 12 ++ .../decorator/DecoratorAnimationProducer.java | 90 +++++++++++ .../ui/decorator/DecoratorController.java | 8 +- .../hmcl/ui/decorator/DecoratorSkin.java | 18 +-- .../hmcl/ui/download/DownloadPage.java | 30 ++-- .../hmcl/ui/main/LauncherSettingsPage.java | 2 +- .../hmcl/ui/multiplayer/MultiplayerPage.java | 2 +- .../hmcl/ui/versions/GameListPage.java | 2 +- .../hmcl/ui/versions/ModUpdatesPage.java | 4 +- .../hmcl/ui/versions/VersionPage.java | 40 ++--- 13 files changed, 224 insertions(+), 133 deletions(-) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorAnimationProducer.java 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 28d71738c..20a2e614b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -38,7 +38,6 @@ import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.ui.account.AccountListPage; -import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.construct.*; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.decorator.DecoratorController; @@ -286,7 +285,7 @@ public final class Controllers { } public static void navigate(Node node) { - decorator.getNavigator().navigate(node, ContainerAnimations.FADE.getAnimationProducer()); + decorator.navigate(node); } public static void showToast(String content) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java index b546eee31..8c97b3749 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java @@ -27,9 +27,8 @@ import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.scene.control.ScrollPane; import javafx.scene.control.Skin; -import javafx.scene.control.SkinBase; import javafx.scene.control.Tooltip; -import javafx.scene.layout.BorderPane; +import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer; @@ -37,10 +36,10 @@ import org.jackhuang.hmcl.setting.Accounts; import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; -import org.jackhuang.hmcl.ui.ListPageBase; import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.construct.AdvancedListItem; import org.jackhuang.hmcl.ui.construct.ClassTitle; +import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.util.javafx.BindingMapping; import org.jackhuang.hmcl.util.javafx.MappedObservableList; @@ -51,15 +50,16 @@ import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor; -public class AccountListPage extends ListPageBase implements DecoratorPage { - private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.manage"), -1)); +public class AccountListPage extends DecoratorAnimatedPage implements DecoratorPage { + private final ObservableList items; + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.manage"))); private final ListProperty accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList()); private final ListProperty authServers = new SimpleListProperty<>(this, "authServers", FXCollections.observableArrayList()); private final ObjectProperty selectedAccount; public AccountListPage() { - setItems(MappedObservableList.create(accounts, AccountListItem::new)); - selectedAccount = createSelectedItemPropertyFor(getItems(), Account.class); + items = MappedObservableList.create(accounts, AccountListItem::new); + selectedAccount = createSelectedItemPropertyFor(items, Account.class); } public ObjectProperty selectedAccountProperty() { @@ -84,100 +84,87 @@ public class AccountListPage extends ListPageBase implements De return new AccountListPageSkin(this); } - private static class AccountListPageSkin extends SkinBase { + private static class AccountListPageSkin extends DecoratorAnimatedPageSkin { private final ObservableList authServerItems; public AccountListPageSkin(AccountListPage skinnable) { super(skinnable); - BorderPane root = new BorderPane(); - { - BorderPane left = new BorderPane(); - FXUtils.setLimitWidth(left, 200); - + VBox boxMethods = new VBox(); { - VBox boxItemList = new VBox(); - boxItemList.getStyleClass().add("advanced-list-box-content"); + boxMethods.getStyleClass().add("advanced-list-box-content"); + boxMethods.getChildren().add(new ClassTitle(i18n("account.create"))); + FXUtils.setLimitWidth(boxMethods, 200); - boxItemList.getChildren().add(new ClassTitle(i18n("account.create"))); + AdvancedListItem offlineItem = new AdvancedListItem(); + offlineItem.getStyleClass().add("navigation-drawer-item"); + offlineItem.setActionButtonVisible(false); + offlineItem.setTitle(i18n("account.methods.offline")); + offlineItem.setLeftGraphic(wrap(SVG::account)); + offlineItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_OFFLINE))); + boxMethods.getChildren().add(offlineItem); - { - VBox boxMethods = new VBox(); - FXUtils.setLimitWidth(boxMethods, 200); + AdvancedListItem mojangItem = new AdvancedListItem(); + mojangItem.getStyleClass().add("navigation-drawer-item"); + mojangItem.setActionButtonVisible(false); + mojangItem.setTitle(i18n("account.methods.yggdrasil")); + mojangItem.setLeftGraphic(wrap(SVG::mojang)); + mojangItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_MOJANG))); + boxMethods.getChildren().add(mojangItem); - AdvancedListItem offlineItem = new AdvancedListItem(); - offlineItem.getStyleClass().add("navigation-drawer-item"); - offlineItem.setActionButtonVisible(false); - offlineItem.setTitle(i18n("account.methods.offline")); - offlineItem.setLeftGraphic(wrap(SVG::account)); - offlineItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_OFFLINE))); - boxMethods.getChildren().add(offlineItem); + AdvancedListItem microsoftItem = new AdvancedListItem(); + microsoftItem.getStyleClass().add("navigation-drawer-item"); + microsoftItem.setActionButtonVisible(false); + microsoftItem.setTitle(i18n("account.methods.microsoft")); + microsoftItem.setLeftGraphic(wrap(SVG::microsoft)); + microsoftItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_MICROSOFT))); + boxMethods.getChildren().add(microsoftItem); - AdvancedListItem mojangItem = new AdvancedListItem(); - mojangItem.getStyleClass().add("navigation-drawer-item"); - mojangItem.setActionButtonVisible(false); - mojangItem.setTitle(i18n("account.methods.yggdrasil")); - mojangItem.setLeftGraphic(wrap(SVG::mojang)); - mojangItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_MOJANG))); - boxMethods.getChildren().add(mojangItem); + VBox boxAuthServers = new VBox(); + authServerItems = MappedObservableList.create(skinnable.authServersProperty(), server -> { + AdvancedListItem item = new AdvancedListItem(); + item.getStyleClass().add("navigation-drawer-item"); + item.setLeftGraphic(wrap(SVG::server)); + item.setOnAction(e -> Controllers.dialog(new CreateAccountPane(server))); - AdvancedListItem microsoftItem = new AdvancedListItem(); - microsoftItem.getStyleClass().add("navigation-drawer-item"); - microsoftItem.setActionButtonVisible(false); - microsoftItem.setTitle(i18n("account.methods.microsoft")); - microsoftItem.setLeftGraphic(wrap(SVG::microsoft)); - microsoftItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_MICROSOFT))); - boxMethods.getChildren().add(microsoftItem); - - VBox boxAuthServers = new VBox(); - authServerItems = MappedObservableList.create(skinnable.authServersProperty(), server -> { - AdvancedListItem item = new AdvancedListItem(); - item.getStyleClass().add("navigation-drawer-item"); - item.setLeftGraphic(wrap(SVG::server)); - item.setOnAction(e -> Controllers.dialog(new CreateAccountPane(server))); - - JFXButton btnRemove = new JFXButton(); - btnRemove.setOnAction(e -> { - skinnable.authServersProperty().remove(server); - e.consume(); - }); - btnRemove.getStyleClass().add("toggle-icon4"); - btnRemove.setGraphic(SVG.close(Theme.blackFillBinding(), 14, 14)); - item.setRightGraphic(btnRemove); - - ObservableValue title = BindingMapping.of(server, AuthlibInjectorServer::getName); - item.titleProperty().bind(title); - item.subtitleProperty().set(URI.create(server.getUrl()).getHost()); - Tooltip tooltip = new Tooltip(); - tooltip.textProperty().bind(Bindings.format("%s (%s)", title, server.getUrl())); - FXUtils.installFastTooltip(item, tooltip); - - return item; + JFXButton btnRemove = new JFXButton(); + btnRemove.setOnAction(e -> { + skinnable.authServersProperty().remove(server); + e.consume(); }); - Bindings.bindContent(boxAuthServers.getChildren(), authServerItems); - boxMethods.getChildren().add(boxAuthServers); + btnRemove.getStyleClass().add("toggle-icon4"); + btnRemove.setGraphic(SVG.close(Theme.blackFillBinding(), 14, 14)); + item.setRightGraphic(btnRemove); - boxItemList.getChildren().add(new ScrollPane(boxMethods)); - } + ObservableValue title = BindingMapping.of(server, AuthlibInjectorServer::getName); + item.titleProperty().bind(title); + item.subtitleProperty().set(URI.create(server.getUrl()).getHost()); + Tooltip tooltip = new Tooltip(); + tooltip.textProperty().bind(Bindings.format("%s (%s)", title, server.getUrl())); + FXUtils.installFastTooltip(item, tooltip); - left.setCenter(boxItemList); + return item; + }); + Bindings.bindContent(boxAuthServers.getChildren(), authServerItems); + boxMethods.getChildren().add(boxAuthServers); } + AdvancedListItem addAuthServerItem = new AdvancedListItem(); { - AdvancedListItem addAuthServerItem = new AdvancedListItem(); addAuthServerItem.getStyleClass().add("navigation-drawer-item"); addAuthServerItem.setTitle(i18n("account.injector.add")); addAuthServerItem.setSubtitle(i18n("account.methods.authlib_injector")); addAuthServerItem.setActionButtonVisible(false); addAuthServerItem.setLeftGraphic(wrap(SVG::plusCircleOutline)); addAuthServerItem.setOnAction(e -> Controllers.dialog(new AddAuthlibInjectorServerPane())); - BorderPane.setMargin(addAuthServerItem, new Insets(0, 0, 12, 0)); - left.setBottom(addAuthServerItem); + VBox.setMargin(addAuthServerItem, new Insets(0, 0, 12, 0)); } - root.setLeft(left); + ScrollPane scrollPane = new ScrollPane(boxMethods); + VBox.setVgrow(scrollPane, Priority.ALWAYS); + setLeft(scrollPane, addAuthServerItem); } ScrollPane scrollPane = new ScrollPane(); @@ -189,15 +176,13 @@ public class AccountListPage extends ListPageBase implements De list.setSpacing(10); list.getStyleClass().add("card-list"); - Bindings.bindContent(list.getChildren(), skinnable.itemsProperty()); + Bindings.bindContent(list.getChildren(), skinnable.items); scrollPane.setContent(list); JFXScrollPane.smoothScrolling(scrollPane); - root.setCenter(scrollPane); + setCenter(scrollPane); } - - getChildren().setAll(root); } } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionPane.java index f5376149e..ba52ab36e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionPane.java @@ -95,5 +95,8 @@ public class TransitionPane extends StackPane implements AnimationHandler { getChildren().setAll(previousNode, currentNode); } - private final StackPane EMPTY_PANE = new StackPane(); + private final EmptyPane EMPTY_PANE = new EmptyPane(); + + public static class EmptyPane extends StackPane { + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorAnimatedPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorAnimatedPage.java index 21c8e9699..2fc221743 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorAnimatedPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorAnimatedPage.java @@ -31,6 +31,10 @@ public class DecoratorAnimatedPage extends Control { protected final VBox left = new VBox(); protected final StackPane center = new StackPane(); + { + getStyleClass().add("gray-background"); + } + protected void setLeft(Node... children) { left.getChildren().setAll(children); } @@ -39,6 +43,14 @@ public class DecoratorAnimatedPage extends Control { center.getChildren().setAll(children); } + public VBox getLeft() { + return left; + } + + public StackPane getCenter() { + return center; + } + @Override protected Skin createDefaultSkin() { return new DecoratorAnimatedPageSkin<>(this); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorAnimationProducer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorAnimationProducer.java new file mode 100644 index 000000000..cb709a922 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorAnimationProducer.java @@ -0,0 +1,90 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2021 huangyuhui 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 . + */ +package org.jackhuang.hmcl.ui.decorator; + +import javafx.animation.Interpolator; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.scene.Node; +import javafx.util.Duration; +import org.jackhuang.hmcl.ui.animation.AnimationHandler; +import org.jackhuang.hmcl.ui.animation.AnimationProducer; +import org.jackhuang.hmcl.ui.animation.TransitionPane; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class DecoratorAnimationProducer implements AnimationProducer { + @Override + public void init(AnimationHandler handler) { + } + + @Override + public List animate(AnimationHandler handler) { + Node prev = handler.getPreviousNode(); + Node next = handler.getCurrentNode(); + if (prev instanceof TransitionPane.EmptyPane) { + return Collections.emptyList(); + } + + Duration halfDuration = handler.getDuration().divide(2); + + List keyFrames = new ArrayList<>(); + + keyFrames.add(new KeyFrame(Duration.ZERO, + new KeyValue(prev.opacityProperty(), 1, Interpolator.EASE_BOTH))); + keyFrames.add(new KeyFrame(halfDuration, + new KeyValue(prev.opacityProperty(), 0, Interpolator.EASE_BOTH))); + if (prev instanceof DecoratorAnimatedPage) { + Node left = ((DecoratorAnimatedPage) prev).getLeft(); + Node center = ((DecoratorAnimatedPage) prev).getCenter(); + + keyFrames.add(new KeyFrame(Duration.ZERO, + new KeyValue(left.translateXProperty(), 0, Interpolator.EASE_BOTH), + new KeyValue(center.translateXProperty(), 0, Interpolator.EASE_BOTH))); + keyFrames.add(new KeyFrame(halfDuration, + new KeyValue(left.translateXProperty(), -30, Interpolator.EASE_BOTH), + new KeyValue(center.translateXProperty(), 30, Interpolator.EASE_BOTH))); + } + + keyFrames.add(new KeyFrame(halfDuration, + new KeyValue(next.opacityProperty(), 0, Interpolator.EASE_BOTH))); + keyFrames.add(new KeyFrame(handler.getDuration(), + new KeyValue(next.opacityProperty(), 1, Interpolator.EASE_BOTH))); + if (next instanceof DecoratorAnimatedPage) { + Node left = ((DecoratorAnimatedPage) next).getLeft(); + Node center = ((DecoratorAnimatedPage) next).getCenter(); + + keyFrames.add(new KeyFrame(halfDuration, + new KeyValue(left.translateXProperty(), -30, Interpolator.EASE_BOTH), + new KeyValue(center.translateXProperty(), 30, Interpolator.EASE_BOTH))); + keyFrames.add(new KeyFrame(handler.getDuration(), + new KeyValue(left.translateXProperty(), 0, Interpolator.EASE_BOTH), + new KeyValue(center.translateXProperty(), 0, Interpolator.EASE_BOTH))); + } + + return keyFrames; + } + + @Override + public @Nullable AnimationProducer opposite() { + return null; + } +} 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 26109fa09..39e343584 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 @@ -224,8 +224,10 @@ public class DecoratorController { // ==== Navigation ==== - public Navigator getNavigator() { - return navigator; + private static final DecoratorAnimationProducer animation = new DecoratorAnimationProducer(); + + public void navigate(Node node) { + navigator.navigate(node, animation); } private void close() { @@ -390,7 +392,7 @@ public class DecoratorController { public void startWizard(WizardProvider wizardProvider, String category) { FXUtils.checkFxUserThread(); - getNavigator().navigate(new DecoratorWizardDisplayer(wizardProvider, category), ContainerAnimations.FADE.getAnimationProducer()); + navigator.navigate(new DecoratorWizardDisplayer(wizardProvider, category), ContainerAnimations.FADE.getAnimationProducer()); } // ==== Authlib Injector DnD ==== diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java index fe4e83ed4..61075ab7d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java @@ -19,7 +19,6 @@ package org.jackhuang.hmcl.ui.decorator; import com.jfoenix.controls.JFXButton; import com.jfoenix.svg.SVGGlyph; -import javafx.animation.Animation; import javafx.beans.binding.Bindings; import javafx.collections.ListChangeListener; import javafx.css.PseudoClass; @@ -197,21 +196,8 @@ public class DecoratorSkin extends SkinBase { navBarPane.getChildren().setAll(node); } - leftPane.prefWidthProperty().unbind(); - if (s.getLeftPaneWidth() >= 0) { - FXUtils.playAnimation(leftPane, "animation", - s.isAnimate() ? Duration.millis(160) : null, leftPane.prefWidthProperty(), null, s.getLeftPaneWidth(), FXUtils.SINE); - } else { - Animation animation = FXUtils.playAnimation(leftPane, "animation1", - s.isAnimate() ? Duration.millis(160) : null, leftPane.prefWidthProperty(), null, container.getWidth(), FXUtils.SINE); - if (animation != null) { - animation.setOnFinished(action -> { - if (animation.getStatus() != Animation.Status.STOPPED) { - leftPane.prefWidthProperty().bind(container.widthProperty()); - } - }); - } - } + FXUtils.playAnimation(leftPane, "animation", + s.isAnimate() ? Duration.millis(160) : null, leftPane.prefWidthProperty(), null, s.getLeftPaneWidth(), FXUtils.SINE); }); titleBar.setCenter(navBarPane); titleBar.setRight(buttonsContainerPlaceHolder); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java index a96d63043..c501ee80c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java @@ -58,6 +58,7 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CancellationException; +import java.util.function.Supplier; import static org.jackhuang.hmcl.ui.FXUtils.runInFX; import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap; @@ -78,9 +79,9 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage private WeakListenerHolder listenerHolder; public DownloadPage() { - newGameTab.setNodeSupplier(() -> new VersionsPage(versionPageNavigator, i18n("install.installer.choose", i18n("install.installer.game")), "", DownloadProviders.getDownloadProvider(), - "game", versionPageNavigator::onGameSelected)); - modpackTab.setNodeSupplier(() -> { + newGameTab.setNodeSupplier(loadVersionFor(() -> new VersionsPage(versionPageNavigator, i18n("install.installer.choose", i18n("install.installer.game")), "", DownloadProviders.getDownloadProvider(), + "game", versionPageNavigator::onGameSelected))); + modpackTab.setNodeSupplier(loadVersionFor(() -> { DownloadListPage page = new DownloadListPage(CurseForgeRemoteModRepository.MODPACKS, Versions::downloadModpackImpl); JFXButton installLocalModpackButton = new JFXButton(i18n("install.modpack")); @@ -90,22 +91,17 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage page.getActions().add(installLocalModpackButton); return page; - }); - modTab.setNodeSupplier(() -> new ModDownloadListPage((profile, version, file) -> download(profile, version, file, "mods"), true)); - resourcePackTab.setNodeSupplier(() -> new DownloadListPage(CurseForgeRemoteModRepository.RESOURCE_PACKS, (profile, version, file) -> download(profile, version, file, "resourcepacks"))); + })); + modTab.setNodeSupplier(loadVersionFor(() -> new ModDownloadListPage((profile, version, file) -> download(profile, version, file, "mods"), true))); + resourcePackTab.setNodeSupplier(loadVersionFor(() -> new DownloadListPage(CurseForgeRemoteModRepository.RESOURCE_PACKS, (profile, version, file) -> download(profile, version, file, "resourcepacks")))); // customizationTab.setNodeSupplier(() -> new ModDownloadListPage(CurseModManager.CUSTOMIZATIONS, this::download)); - worldTab.setNodeSupplier(() -> new DownloadListPage(CurseForgeRemoteModRepository.WORLDS)); + worldTab.setNodeSupplier(loadVersionFor(() -> new DownloadListPage(CurseForgeRemoteModRepository.WORLDS))); tab = new TabHeader(newGameTab, modpackTab, modTab, resourcePackTab, worldTab); Profiles.registerVersionsListener(this::loadVersions); tab.select(newGameTab); FXUtils.onChangeAndOperate(tab.getSelectionModel().selectedItemProperty(), newValue -> { - if (newValue.initializeIfNeeded()) { - if (newValue.getNode() instanceof VersionPage.VersionLoadable) { - ((VersionPage.VersionLoadable) newValue.getNode()).loadVersion(Profiles.getSelectedProfile(), null); - } - } transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer()); }); @@ -154,6 +150,16 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage setCenter(transitionPane); } + private Supplier loadVersionFor(Supplier nodeSupplier) { + return () -> { + T node = nodeSupplier.get(); + if (node instanceof VersionPage.VersionLoadable) { + ((VersionPage.VersionLoadable) node).loadVersion(Profiles.getSelectedProfile(), null); + } + return node; + }; + } + private void download(Profile profile, @Nullable String version, RemoteMod.Version file, String subdirectoryName) { if (version == null) version = profile.getSelectedVersion(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java index a11876033..d6c11595c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java @@ -36,7 +36,7 @@ import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class LauncherSettingsPage extends DecoratorAnimatedPage implements DecoratorPage, PageAware { - private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("settings"), -1)); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("settings"))); private final TabHeader tab; private final TabHeader.Tab gameTab = new TabHeader.Tab<>("versionSettingsPage"); private final TabHeader.Tab settingsTab = new TabHeader.Tab<>("settingsPage"); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPage.java index 489915590..576edfbbc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPage.java @@ -50,7 +50,7 @@ import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class MultiplayerPage extends DecoratorAnimatedPage implements DecoratorPage, PageAware { - private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("multiplayer"), -1)); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("multiplayer"))); private final ObjectProperty multiplayerState = new SimpleObjectProperty<>(MultiplayerManager.State.DISCONNECTED); private final ReadOnlyStringWrapper token = new ReadOnlyStringWrapper(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java index 67721360b..83c19f2a8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java @@ -47,7 +47,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor; public class GameListPage extends DecoratorAnimatedPage implements DecoratorPage { - private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("version.manage"), -1)); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("version.manage"))); private final ListProperty profiles = new SimpleListProperty<>(FXCollections.observableArrayList()); @SuppressWarnings("FieldCanBeLocal") private final ObservableList profileListItems; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java index b00de0ee1..225943108 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java @@ -52,7 +52,7 @@ import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class ModUpdatesPage extends BorderPane implements DecoratorPage { - private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(DecoratorPage.State.fromTitle(i18n("mods.check_updates"), -1)); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(DecoratorPage.State.fromTitle(i18n("mods.check_updates"))); private final ModManager modManager; private final ObservableList objects; @@ -60,6 +60,8 @@ public class ModUpdatesPage extends BorderPane implements DecoratorPage { public ModUpdatesPage(ModManager modManager, List updates) { this.modManager = modManager; + getStyleClass().add("gray-background"); + JFXTreeTableColumn enabledColumn = new JFXTreeTableColumn<>(); enabledColumn.setCellFactory(column -> new JFXCheckBoxTreeTableCell<>()); setupCellValueFactory(enabledColumn, ModUpdateObject::enabledProperty); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java index 0838bbbce..8c9e9fd3a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java @@ -29,6 +29,7 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import org.jackhuang.hmcl.setting.Profile; +import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; @@ -41,6 +42,7 @@ import org.jackhuang.hmcl.util.io.FileUtils; import java.io.File; import java.util.Optional; +import java.util.function.Supplier; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -58,29 +60,33 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage private String preferredVersionName = null; { - versionSettingsTab.setNodeSupplier(() -> new VersionSettingsPage(false)); - modListTab.setNodeSupplier(ModListPage::new); - installerListTab.setNodeSupplier(InstallerListPage::new); - worldListTab.setNodeSupplier(WorldListPage::new); + versionSettingsTab.setNodeSupplier(loadVersionFor(() -> new VersionSettingsPage(false))); + modListTab.setNodeSupplier(loadVersionFor(ModListPage::new)); + installerListTab.setNodeSupplier(loadVersionFor(InstallerListPage::new)); + worldListTab.setNodeSupplier(loadVersionFor(WorldListPage::new)); tab = new TabHeader(versionSettingsTab, modListTab, installerListTab, worldListTab); addEventHandler(Navigator.NavigationEvent.NAVIGATED, this::onNavigated); - tab.getSelectionModel().select(versionSettingsTab); + tab.select(versionSettingsTab); FXUtils.onChangeAndOperate(tab.getSelectionModel().selectedItemProperty(), newValue -> { - if (newValue.initializeIfNeeded()) { - if (this.version.get() != null) { - if (newValue.getNode() instanceof VersionLoadable) { - ((VersionLoadable) newValue.getNode()).loadVersion(version.get().getProfile(), version.get().getVersion()); - } - } - } - transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer()); }); } + private Supplier loadVersionFor(Supplier nodeSupplier) { + return () -> { + T node = nodeSupplier.get(); + if (this.version.get() != null) { + if (node instanceof VersionPage.VersionLoadable) { + ((VersionPage.VersionLoadable) node).loadVersion(Profiles.getSelectedProfile(), null); + } + } + return node; + }; + } + public void setVersion(String version, Profile profile) { this.version.set(new Profile.ProfileVersion(profile, version)); } @@ -207,7 +213,7 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage versionSettingsItem.setLeftGraphic(wrap(SVG::gearOutline)); versionSettingsItem.setActionButtonVisible(false); versionSettingsItem.activeProperty().bind(control.tab.getSelectionModel().selectedItemProperty().isEqualTo(control.versionSettingsTab)); - versionSettingsItem.setOnAction(e -> control.tab.getSelectionModel().select(control.versionSettingsTab)); + versionSettingsItem.setOnAction(e -> control.tab.select(control.versionSettingsTab)); AdvancedListItem modListItem = new AdvancedListItem(); modListItem.getStyleClass().add("navigation-drawer-item"); @@ -215,7 +221,7 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage modListItem.setLeftGraphic(wrap(SVG::puzzle)); modListItem.setActionButtonVisible(false); modListItem.activeProperty().bind(control.tab.getSelectionModel().selectedItemProperty().isEqualTo(control.modListTab)); - modListItem.setOnAction(e -> control.tab.getSelectionModel().select(control.modListTab)); + modListItem.setOnAction(e -> control.tab.select(control.modListTab)); AdvancedListItem installerListItem = new AdvancedListItem(); installerListItem.getStyleClass().add("navigation-drawer-item"); @@ -223,7 +229,7 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage installerListItem.setLeftGraphic(wrap(SVG::cube)); installerListItem.setActionButtonVisible(false); installerListItem.activeProperty().bind(control.tab.getSelectionModel().selectedItemProperty().isEqualTo(control.installerListTab)); - installerListItem.setOnAction(e -> control.tab.getSelectionModel().select(control.installerListTab)); + installerListItem.setOnAction(e -> control.tab.select(control.installerListTab)); AdvancedListItem worldListItem = new AdvancedListItem(); worldListItem.getStyleClass().add("navigation-drawer-item"); @@ -231,7 +237,7 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage worldListItem.setLeftGraphic(wrap(SVG::earth)); worldListItem.setActionButtonVisible(false); worldListItem.activeProperty().bind(control.tab.getSelectionModel().selectedItemProperty().isEqualTo(control.worldListTab)); - worldListItem.setOnAction(e -> control.tab.getSelectionModel().select(control.worldListTab)); + worldListItem.setOnAction(e -> control.tab.select(control.worldListTab)); AdvancedListBox sideBar = new AdvancedListBox() .add(versionSettingsItem)