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 e5db94849..8ec86ddfb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -30,10 +30,12 @@ import org.jackhuang.hmcl.Launcher; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.download.java.JavaRepository; import org.jackhuang.hmcl.mod.curse.CurseModManager; +import org.jackhuang.hmcl.setting.Accounts; import org.jackhuang.hmcl.setting.EnumCommonDirectory; 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.account.AuthlibInjectorServersPage; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.construct.InputDialogPane; @@ -91,6 +93,12 @@ public final class Controllers { } }; }); + private static Lazy accountListPage = new Lazy<>(() -> { + AccountListPage accountListPage = new AccountListPage(); + accountListPage.selectedAccountProperty().bindBidirectional(Accounts.selectedAccountProperty()); + accountListPage.accountsProperty().bindContent(Accounts.accountsProperty()); + return accountListPage; + }); private static Lazy settingsPage = new Lazy<>(LauncherSettingsPage::new); private Controllers() { @@ -136,6 +144,11 @@ public final class Controllers { return settingsPage.get(); } + // FXThread + public static AccountListPage getAccountListPage() { + return accountListPage.get(); + } + // FXThread public static DecoratorController getDecorator() { return decorator; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java index f69d95746..4269efafb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java @@ -54,7 +54,7 @@ public final class SVG { return svg; } - // default fill: white, width: 20, height 20 + // default fill: white, width: 24, height 24 public static Node gear(ObjectBinding fill, double width, double height) { return createSVGPath( @@ -360,4 +360,34 @@ public final class SVG { "M16 3.23C16.71 2.41 17.61 2 18.7 2C19.61 2 20.37 2.33 21 3C21.63 3.67 21.96 4.43 22 5.3C22 6 21.67 6.81 21 7.76S19.68 9.5 19.03 10.15C18.38 10.79 17.37 11.74 16 13C14.61 11.74 13.59 10.79 12.94 10.15S11.63 8.71 10.97 7.76C10.31 6.81 10 6 10 5.3C10 4.39 10.32 3.63 10.97 3C11.62 2.37 12.4 2.04 13.31 2C14.38 2 15.27 2.41 16 3.23M22 19V20L14 22.5L7 20.56V22H1V11H8.97L15.13 13.3C16.25 13.72 17 14.8 17 16H19C20.66 16 22 17.34 22 19M5 20V13H3V20H5M19.9 18.57C19.74 18.24 19.39 18 19 18H13.65C13.11 18 12.58 17.92 12.07 17.75L9.69 16.96L10.32 15.06L12.7 15.85C13 15.95 15 16 15 16C15 15.63 14.77 15.3 14.43 15.17L8.61 13H7V18.5L13.97 20.41L19.9 18.57Z", fill, width, height); } + + public static Node mojang(ObjectBinding fill, double width, double height) { + return createSVGPath( + "m 13.965847,0 c -1.010612,0.82802228 -1.197232,2.1950303 -1.265172,3.4179557 0.02123,1.0021189 1.341654,1.2994159 1.953117,0.590289 C 15.091158,2.6579315 14.369242,1.2738804 13.965847,0 Z M 10.913012,2.9296764 C 10.755901,3.6982508 10.628413,4.4668999 10.492533,5.2354744 8.9893533,3.9913178 7.1504705,3.0824837 5.1419856,3.2947971 3.4944341,3.4646478 0.94293227,2.6961479 0.14038761,4.645185 -0.12288102,8.3139606 0.07223999,12.01236 0.03402357,15.689629 c -0.12314178,1.222925 0.86170213,2.420422 2.14407513,2.280295 4.2207899,0.03397 8.4502143,0.04723 12.6710043,-0.0038 1.265389,0.135918 1.957646,-1.010748 2.13599,-2.0893 C 13.269608,16.437357 9.1760813,16.929609 5.7111265,15.129192 2.5986124,13.58355 2.246023,8.3138817 5.5581114,6.7979639 9.3203049,5.1758896 13.859607,8.0382886 14.942405,11.787743 15.613316,12.11046 16.284433,12.424684 16.95959,12.743154 16.624135,10.348258 16.653651,7.800456 15.579346,5.5881508 15.057054,4.7473897 14.097531,6.2714182 13.379911,5.6217388 12.416008,4.865903 11.749527,3.8128948 10.913012,2.9296713 Z", + fill, width, height); + } + + public static Node microsoft(ObjectBinding fill, double width, double height) { + return createSVGPath( + "M2,3H11V12H2V3M11,22H2V13H11V22M21,3V12H12V3H21M21,22H12V13H21V22Z", + fill, width, height); + } + + public static Node accountOutline(ObjectBinding fill, double width, double height) { + return createSVGPath( + "M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,6A2,2 0 0,0 10,8A2,2 0 0,0 12,10A2,2 0 0,0 14,8A2,2 0 0,0 12,6M12,13C14.67,13 20,14.33 20,17V20H4V17C4,14.33 9.33,13 12,13M12,14.9C9.03,14.9 5.9,16.36 5.9,17V18.1H18.1V17C18.1,16.36 14.97,14.9 12,14.9Z", + fill, width, height); + } + + public static Node accountGroupOutline(ObjectBinding fill, double width, double height) { + return createSVGPath( + "M12,5A3.5,3.5 0 0,0 8.5,8.5A3.5,3.5 0 0,0 12,12A3.5,3.5 0 0,0 15.5,8.5A3.5,3.5 0 0,0 12,5M12,7A1.5,1.5 0 0,1 13.5,8.5A1.5,1.5 0 0,1 12,10A1.5,1.5 0 0,1 10.5,8.5A1.5,1.5 0 0,1 12,7M5.5,8A2.5,2.5 0 0,0 3,10.5C3,11.44 3.53,12.25 4.29,12.68C4.65,12.88 5.06,13 5.5,13C5.94,13 6.35,12.88 6.71,12.68C7.08,12.47 7.39,12.17 7.62,11.81C6.89,10.86 6.5,9.7 6.5,8.5C6.5,8.41 6.5,8.31 6.5,8.22C6.2,8.08 5.86,8 5.5,8M18.5,8C18.14,8 17.8,8.08 17.5,8.22C17.5,8.31 17.5,8.41 17.5,8.5C17.5,9.7 17.11,10.86 16.38,11.81C16.5,12 16.63,12.15 16.78,12.3C16.94,12.45 17.1,12.58 17.29,12.68C17.65,12.88 18.06,13 18.5,13C18.94,13 19.35,12.88 19.71,12.68C20.47,12.25 21,11.44 21,10.5A2.5,2.5 0 0,0 18.5,8M12,14C9.66,14 5,15.17 5,17.5V19H19V17.5C19,15.17 14.34,14 12,14M4.71,14.55C2.78,14.78 0,15.76 0,17.5V19H3V17.07C3,16.06 3.69,15.22 4.71,14.55M19.29,14.55C20.31,15.22 21,16.06 21,17.07V19H24V17.5C24,15.76 21.22,14.78 19.29,14.55M12,16C13.53,16 15.24,16.5 16.23,17H7.77C8.76,16.5 10.47,16 12,16Z", + fill, width, height); + } + + public static Node styleOutline(ObjectBinding fill, double width, double height) { + return createSVGPath( + "M2.5 19.6L3.8 20.2V11.2L1.4 17C1 18.1 1.5 19.2 2.5 19.6M15.2 4.8L20.2 16.8L12.9 19.8L7.9 7.9V7.8L15.2 4.8M15.3 2.8C15 2.8 14.8 2.8 14.5 2.9L7.1 6C6.4 6.3 5.9 7 5.9 7.8C5.9 8 5.9 8.3 6 8.6L11 20.5C11.3 21.3 12 21.7 12.8 21.7C13.1 21.7 13.3 21.7 13.6 21.6L21 18.5C22 18.1 22.5 16.9 22.1 15.9L17.1 4C16.8 3.2 16 2.8 15.3 2.8M10.5 9.9C9.9 9.9 9.5 9.5 9.5 8.9S9.9 7.9 10.5 7.9C11.1 7.9 11.5 8.4 11.5 8.9S11.1 9.9 10.5 9.9M5.9 19.8C5.9 20.9 6.8 21.8 7.9 21.8H9.3L5.9 13.5V19.8Z", + fill, width, height); + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java deleted file mode 100644 index e3848c3c5..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 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.account; - -import javafx.beans.property.*; -import javafx.collections.FXCollections; -import org.jackhuang.hmcl.auth.Account; -import org.jackhuang.hmcl.ui.Controllers; -import org.jackhuang.hmcl.ui.ListPage; -import org.jackhuang.hmcl.ui.decorator.DecoratorPage; -import org.jackhuang.hmcl.util.javafx.MappedObservableList; - -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor; - -public class AccountList extends ListPage implements DecoratorPage { - private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.manage"))); - private final ListProperty accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList()); - private final ObjectProperty selectedAccount; - - public AccountList() { - setItems(MappedObservableList.create(accounts, AccountListItem::new)); - selectedAccount = createSelectedItemPropertyFor(getItems(), Account.class); - } - - public ObjectProperty selectedAccountProperty() { - return selectedAccount; - } - - public ListProperty accountsProperty() { - return accounts; - } - - @Override - public void add() { - Controllers.dialog(new AddAccountPane()); - } - - @Override - public ReadOnlyObjectProperty stateProperty() { - return state.getReadOnlyProperty(); - } -} 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 new file mode 100644 index 000000000..74932bbf8 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java @@ -0,0 +1,104 @@ +/* + * 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.account; + +import com.jfoenix.controls.JFXScrollPane; +import javafx.beans.binding.Bindings; +import javafx.beans.property.*; +import javafx.collections.FXCollections; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.Skin; +import javafx.scene.control.SkinBase; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.auth.Account; +import org.jackhuang.hmcl.ui.*; +import org.jackhuang.hmcl.ui.construct.AdvancedListBox; +import org.jackhuang.hmcl.ui.decorator.DecoratorPage; +import org.jackhuang.hmcl.util.javafx.MappedObservableList; + +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"), 200)); + private final ListProperty accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList()); + private final ObjectProperty selectedAccount; + + public AccountListPage() { + setItems(MappedObservableList.create(accounts, AccountListItem::new)); + selectedAccount = createSelectedItemPropertyFor(getItems(), Account.class); + } + + public ObjectProperty selectedAccountProperty() { + return selectedAccount; + } + + public ListProperty accountsProperty() { + return accounts; + } + + @Override + public ReadOnlyObjectProperty stateProperty() { + return state.getReadOnlyProperty(); + } + + @Override + protected Skin createDefaultSkin() { + return new AccountListPageSkin(this); + } + + private static class AccountListPageSkin extends SkinBase { + public AccountListPageSkin(AccountListPage skinnable) { + super(skinnable); + + BorderPane root = new BorderPane(); + + { + AdvancedListBox sideBar = new AdvancedListBox() + .addNavigationDrawerItem(settingsItem -> { + settingsItem.setTitle(i18n("account.create")); + settingsItem.setLeftGraphic(wrap(SVG.plusCircleOutline(null, 20, 20))); + settingsItem.setOnAction(e -> Controllers.dialog(new AddAccountPane())); + }); + FXUtils.setLimitWidth(sideBar, 200); + root.setLeft(sideBar); + } + + ScrollPane scrollPane = new ScrollPane(); + VBox list = new VBox(); + { + scrollPane.setFitToWidth(true); + + list.maxWidthProperty().bind(scrollPane.widthProperty()); + list.setSpacing(10); + list.getStyleClass().add("card-list"); + + Bindings.bindContent(list.getChildren(), skinnable.itemsProperty()); + + scrollPane.setContent(list); + JFXScrollPane.smoothScrolling(scrollPane); + + root.setCenter(scrollPane); + } + + getChildren().setAll(root); + } + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java index e16e6a5bb..31f33061e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java @@ -25,6 +25,8 @@ import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import org.jackhuang.hmcl.ui.FXUtils; +import java.util.function.Consumer; + public class AdvancedListBox extends ScrollPane { private final VBox container = new VBox(); @@ -52,6 +54,14 @@ public class AdvancedListBox extends ScrollPane { return this; } + public AdvancedListBox addNavigationDrawerItem(Consumer fn) { + AdvancedListItem item = new AdvancedListItem(); + item.getStyleClass().add("navigation-drawer-item"); + item.setActionButtonVisible(false); + fn.accept(item); + return add(item); + } + public AdvancedListBox add(int index, Node child) { if (child instanceof Pane || child instanceof AdvancedListItem) container.getChildren().add(index, child); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorPage.java index 5ffc22f7d..babad5095 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorPage.java @@ -69,6 +69,10 @@ public interface DecoratorPage extends Refreshable { return new State(title, null, true, false, true); } + public static State fromTitle(String title, double leftPaneWidth) { + return new State(title, null, true, false, true, leftPaneWidth); + } + public static State fromTitleNode(Node titleNode) { return new State(null, titleNode, true, false, true); } 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 447e70172..4dabfc101 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 @@ -25,7 +25,6 @@ import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.ui.construct.AdvancedListBox; -import org.jackhuang.hmcl.ui.construct.AdvancedListItem; import org.jackhuang.hmcl.ui.construct.TabHeader; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; @@ -33,7 +32,7 @@ import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class LauncherSettingsPage extends BorderPane implements DecoratorPage { - private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(new State(i18n("settings.launcher"), null, true, false, true, 200)); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("settings.launcher"), 200)); private final TabHeader tab; private final TabHeader.Tab settingsTab = new TabHeader.Tab<>("settingsPage"); private final TabHeader.Tab helpTab = new TabHeader.Tab<>("helpPage"); @@ -55,43 +54,31 @@ public class LauncherSettingsPage extends BorderPane implements DecoratorPage { }); { - AdvancedListItem settingsItem = new AdvancedListItem(); - settingsItem.getStyleClass().add("navigation-drawer-item"); - settingsItem.setTitle(i18n("settings.launcher")); - settingsItem.setLeftGraphic(wrap(SVG.gearOutline(null, 20, 20))); - settingsItem.setActionButtonVisible(false); - settingsItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(settingsTab)); - settingsItem.setOnAction(e -> tab.getSelectionModel().select(settingsTab)); - - AdvancedListItem helpItem = new AdvancedListItem(); - helpItem.getStyleClass().add("navigation-drawer-item"); - helpItem.setTitle(i18n("help")); - helpItem.setLeftGraphic(wrap(SVG.helpCircleOutline(null, 20, 20))); - helpItem.setActionButtonVisible(false); - helpItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(helpTab)); - helpItem.setOnAction(e -> tab.getSelectionModel().select(helpTab)); - - AdvancedListItem sponsorItem = new AdvancedListItem(); - sponsorItem.getStyleClass().add("navigation-drawer-item"); - sponsorItem.setTitle(i18n("sponsor")); - sponsorItem.setLeftGraphic(wrap(SVG.handHearOutline(null, 20, 20))); - sponsorItem.setActionButtonVisible(false); - sponsorItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(sponsorTab)); - sponsorItem.setOnAction(e -> tab.getSelectionModel().select(sponsorTab)); - - AdvancedListItem aboutItem = new AdvancedListItem(); - aboutItem.getStyleClass().add("navigation-drawer-item"); - aboutItem.setTitle(i18n("about")); - aboutItem.setLeftGraphic(wrap(SVG.informationOutline(null, 20, 20))); - aboutItem.setActionButtonVisible(false); - aboutItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(aboutTab)); - aboutItem.setOnAction(e -> tab.getSelectionModel().select(aboutTab)); - AdvancedListBox sideBar = new AdvancedListBox() - .add(settingsItem) - .add(helpItem) - .add(sponsorItem) - .add(aboutItem); + .addNavigationDrawerItem(settingsItem -> { + settingsItem.setTitle(i18n("settings.launcher")); + settingsItem.setLeftGraphic(wrap(SVG.gearOutline(null, 20, 20))); + settingsItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(settingsTab)); + settingsItem.setOnAction(e -> tab.getSelectionModel().select(settingsTab)); + }) + .addNavigationDrawerItem(helpItem -> { + helpItem.setTitle(i18n("help")); + helpItem.setLeftGraphic(wrap(SVG.helpCircleOutline(null, 20, 20))); + helpItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(helpTab)); + helpItem.setOnAction(e -> tab.getSelectionModel().select(helpTab)); + }) + .addNavigationDrawerItem(sponsorItem -> { + sponsorItem.setTitle(i18n("sponsor")); + sponsorItem.setLeftGraphic(wrap(SVG.handHearOutline(null, 20, 20))); + sponsorItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(sponsorTab)); + sponsorItem.setOnAction(e -> tab.getSelectionModel().select(sponsorTab)); + }) + .addNavigationDrawerItem(aboutItem -> { + aboutItem.setTitle(i18n("about")); + aboutItem.setLeftGraphic(wrap(SVG.informationOutline(null, 20, 20))); + aboutItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(aboutTab)); + aboutItem.setOnAction(e -> tab.getSelectionModel().select(aboutTab)); + }); FXUtils.setLimitWidth(sideBar, 200); setLeft(sideBar); } 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 739e8fd80..1670695e1 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 @@ -34,7 +34,6 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.account.AccountAdvancedListItem; -import org.jackhuang.hmcl.ui.account.AccountList; import org.jackhuang.hmcl.ui.account.AddAccountPane; import org.jackhuang.hmcl.ui.construct.AdvancedListBox; import org.jackhuang.hmcl.ui.construct.AdvancedListItem; @@ -61,29 +60,27 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class RootPage extends DecoratorTabPage { private MainPage mainPage = null; - private SettingsPage settingsPage = null; - private AccountList accountListPage = null; private final TabHeader.Tab mainTab = new TabHeader.Tab<>("main"); - private final TabHeader.Tab accountTab = new TabHeader.Tab<>("account"); public RootPage() { setLeftPaneWidth(200); - EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(event -> onRefreshedVersions((HMCLGameRepository) event.getSource())); + EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class) + .register(event -> onRefreshedVersions((HMCLGameRepository) event.getSource())); Profile profile = Profiles.getSelectedProfile(); if (profile != null && profile.getRepository().isLoaded()) onRefreshedVersions(Profiles.selectedProfileProperty().get().getRepository()); mainTab.setNodeSupplier(this::getMainPage); - accountTab.setNodeSupplier(this::getAccountListPage); - getTabs().setAll(mainTab, accountTab); + getTabs().setAll(mainTab); } @Override public boolean back() { - if (mainTab.isSelected()) return true; + if (mainTab.isSelected()) + return true; else { getSelectionModel().select(mainTab); return false; @@ -107,20 +104,23 @@ public class RootPage extends DecoratorTabPage { MainPage mainPage = new MainPage(); FXUtils.applyDragListener(mainPage, it -> "zip".equals(FileUtils.getExtension(it)), modpacks -> { File modpack = modpacks.get(0); - Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), i18n("install.modpack")); + Controllers.getDecorator().startWizard( + new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), + i18n("install.modpack")); }); FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), mainPage::setCurrentGame); mainPage.showUpdateProperty().bind(UpdateChecker.outdatedProperty()); - mainPage.latestVersionProperty().bind( - BindingMapping.of(UpdateChecker.latestVersionProperty()) - .map(version -> version == null ? "" : i18n("update.bubble.title", version.getVersion()))); + mainPage.latestVersionProperty().bind(BindingMapping.of(UpdateChecker.latestVersionProperty()) + .map(version -> version == null ? "" : i18n("update.bubble.title", version.getVersion()))); Profiles.registerVersionsListener(profile -> { HMCLGameRepository repository = profile.getRepository(); List children = repository.getVersions().parallelStream() .filter(version -> !version.isHidden()) - .sorted(Comparator.comparing((Version version) -> version.getReleaseTime() == null ? new Date(0L) : version.getReleaseTime()) + .sorted(Comparator + .comparing((Version version) -> version.getReleaseTime() == null ? new Date(0L) + : version.getReleaseTime()) .thenComparing(a -> VersionNumber.asVersion(a.getId()))) .collect(Collectors.toList()); runInFX(() -> { @@ -133,42 +133,6 @@ public class RootPage extends DecoratorTabPage { return mainPage; } - private SettingsPage getSettingsPage() { - if (settingsPage == null) - settingsPage = new SettingsPage(); - return settingsPage; - } - - private AccountList getAccountListPage() { - if (accountListPage == null) { - accountListPage = new AccountList(); - accountListPage.selectedAccountProperty().bindBidirectional(Accounts.selectedAccountProperty()); - accountListPage.accountsProperty().bindContent(Accounts.accountsProperty()); - } - return accountListPage; - } - - public Tab getMainTab() { - return mainTab; - } - - public Tab getAccountTab() { - return accountTab; - } - - /** - * @return true if the tab is being opened, or false if the tab is being closed - */ - private boolean selectPage(Tab tab) { - if (getSelectionModel().getSelectedItem() == tab) { - getSelectionModel().select(getMainTab()); - return false; - } else { - getSelectionModel().select(tab); - return true; - } - } - private static class Skin extends SkinBase { protected Skin(RootPage control) { @@ -176,13 +140,11 @@ public class RootPage extends DecoratorTabPage { // first item in left sidebar AccountAdvancedListItem accountListItem = new AccountAdvancedListItem(); - accountListItem.activeProperty().bind(control.accountTab.selectedProperty()); accountListItem.setOnAction(e -> { - if (control.selectPage(control.accountTab)) { - // open create account dialog if no account exists - if (Accounts.getAccounts().isEmpty()) { - Controllers.dialog(new AddAccountPane()); - } + Controllers.navigate(Controllers.getAccountListPage()); + + if (Accounts.getAccounts().isEmpty()) { + Controllers.dialog(new AddAccountPane()); } }); accountListItem.accountProperty().bind(Accounts.selectedAccountProperty()); @@ -207,20 +169,16 @@ public class RootPage extends DecoratorTabPage { // fifth item in left sidebar AdvancedListItem launcherSettingsItem = new AdvancedListItem(); - launcherSettingsItem.setLeftGraphic(AdvancedListItem.createImageView(newImage("/assets/img/command.png")).getKey()); + launcherSettingsItem + .setLeftGraphic(AdvancedListItem.createImageView(newImage("/assets/img/command.png")).getKey()); launcherSettingsItem.setActionButtonVisible(false); launcherSettingsItem.setTitle(i18n("settings.launcher")); launcherSettingsItem.setOnAction(e -> Controllers.navigate(Controllers.getSettingsPage())); // the left sidebar - AdvancedListBox sideBar = new AdvancedListBox() - .startCategory(i18n("account").toUpperCase()) - .add(accountListItem) - .startCategory(i18n("version").toUpperCase()) - .add(gameListItem) - .add(gameItem) - .startCategory(i18n("launcher").toUpperCase()) - .add(launcherSettingsItem); + AdvancedListBox sideBar = new AdvancedListBox().startCategory(i18n("account").toUpperCase()) + .add(accountListItem).startCategory(i18n("version").toUpperCase()).add(gameListItem).add(gameItem) + .startCategory(i18n("launcher").toUpperCase()).add(launcherSettingsItem); // the root page, with the sidebar in left, navigator in center. BorderPane root = new BorderPane(); @@ -244,7 +202,8 @@ public class RootPage extends DecoratorTabPage { private boolean checkedAccont = false; public void checkAccount() { - if (checkedAccont) return; + if (checkedAccont) + return; checkedAccont = true; if (Accounts.getAccounts().isEmpty()) Platform.runLater(this::addNewAccount); @@ -266,8 +225,11 @@ public class RootPage extends DecoratorTabPage { File modpackFile = new File("modpack.zip").getAbsoluteFile(); if (modpackFile.exists()) { Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath())) - .thenApplyAsync(encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding)) - .thenApplyAsync(modpack -> ModpackHelper.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack) + .thenApplyAsync( + encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding)) + .thenApplyAsync(modpack -> ModpackHelper + .getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), + modpack) .withRunAsync(Schedulers.javafx(), this::checkAccount).executor()) .thenAcceptAsync(Schedulers.javafx(), executor -> { Controllers.taskDialog(executor, i18n("modpack.installing")); 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 cc7c42bc6..e5d23d17f 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 @@ -244,7 +244,7 @@ public class GameListPage extends ListPageBase implements Decorato public GameListSkin() { super(GameList.this); - state.set(new State(i18n("version.manage"), null, true, false, true, 200)); + state.set(State.fromTitle(i18n("version.manage"), 200)); } @Override 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 309663d48..19e7b30a7 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 @@ -388,7 +388,7 @@ public class VersionPage extends Control implements DecoratorPage, ModDownloadPa } control.state.bind(Bindings.createObjectBinding(() -> - new State(i18n("version.manage.manage.title", getSkinnable().getVersion()), null, true, false, true, 200), + State.fromTitle(i18n("version.manage.manage.title", getSkinnable().getVersion()), 200), getSkinnable().version)); //control.transitionPane.getStyleClass().add("gray-background"); diff --git a/HMCL/src/main/resources/assets/img/red_lnn.jpg b/HMCL/src/main/resources/assets/img/red_lnn.jpg new file mode 100644 index 000000000..264cbf042 Binary files /dev/null and b/HMCL/src/main/resources/assets/img/red_lnn.jpg differ