From 9bef8b432b9095bdb470f7a1e7c1ce8fcab37c01 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Sat, 28 Aug 2021 16:35:28 +0800 Subject: [PATCH] feat: account list page left pane --- .../org/jackhuang/hmcl/ui/Controllers.java | 13 +++ .../main/java/org/jackhuang/hmcl/ui/SVG.java | 32 +++++- .../hmcl/ui/account/AccountList.java | 58 ---------- .../hmcl/ui/account/AccountListPage.java | 104 ++++++++++++++++++ .../hmcl/ui/construct/AdvancedListBox.java | 10 ++ .../hmcl/ui/decorator/DecoratorPage.java | 4 + .../hmcl/ui/main/LauncherSettingsPage.java | 63 +++++------ .../org/jackhuang/hmcl/ui/main/RootPage.java | 96 +++++----------- .../hmcl/ui/versions/GameListPage.java | 2 +- .../hmcl/ui/versions/VersionPage.java | 2 +- .../src/main/resources/assets/img/red_lnn.jpg | Bin 0 -> 23469 bytes 11 files changed, 218 insertions(+), 166 deletions(-) delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java create mode 100644 HMCL/src/main/resources/assets/img/red_lnn.jpg 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 0000000000000000000000000000000000000000..264cbf04296717224882264160d7548edbf842fa GIT binary patch literal 23469 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 literal 0 HcmV?d00001