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 227c4f599..841ec45d0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -44,7 +44,9 @@ import org.jackhuang.hmcl.ui.construct.PromptDialogPane; import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane; import org.jackhuang.hmcl.ui.decorator.DecoratorController; import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider; +import org.jackhuang.hmcl.ui.main.LauncherSettingsPage; import org.jackhuang.hmcl.ui.main.RootPage; +import org.jackhuang.hmcl.ui.main.SettingsPage; import org.jackhuang.hmcl.ui.versions.GameListPage; import org.jackhuang.hmcl.ui.versions.ModDownloadListPage; import org.jackhuang.hmcl.ui.versions.VersionPage; @@ -91,6 +93,7 @@ public final class Controllers { } }; }); + private static Lazy settingsPage = new Lazy<>(LauncherSettingsPage::new); private Controllers() { } @@ -130,6 +133,11 @@ public final class Controllers { return modDownloadListPage.get(); } + // FXThread + public static LauncherSettingsPage getSettingsPage() { + return settingsPage.get(); + } + // FXThread public static DecoratorController getDecorator() { return decorator; @@ -255,6 +263,7 @@ public final class Controllers { versionPage = null; serversPage = null; gameListPage = null; + settingsPage = null; modDownloadListPage = null; decorator = null; stage = null; 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..664d139cc 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 @@ -85,6 +85,10 @@ public class AdvancedListBox extends ScrollPane { } } + public AdvancedListBox startCategory() { + return add(new ClassTitle()); + } + public AdvancedListBox startCategory(String category) { return add(new ClassTitle(category)); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItem.java index 4d4a40945..846469908 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItem.java @@ -142,12 +142,16 @@ public class AdvancedListItem extends Control { } public static Pair createImageView(Image image) { + return createImageView(image, 32, 32); + } + + public static Pair createImageView(Image image, double width, double height) { StackPane imageViewContainer = new StackPane(); - FXUtils.setLimitWidth(imageViewContainer, 32); - FXUtils.setLimitHeight(imageViewContainer, 32); + FXUtils.setLimitWidth(imageViewContainer, width); + FXUtils.setLimitHeight(imageViewContainer, height); ImageView imageView = new ImageView(); - FXUtils.limitSize(imageView, 32, 32); + FXUtils.limitSize(imageView, width, height); imageView.setPreserveRatio(true); imageView.setImage(image); imageViewContainer.getChildren().setAll(imageView); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ClassTitle.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ClassTitle.java index c4e9bb3f8..a4467bce9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ClassTitle.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ClassTitle.java @@ -17,7 +17,9 @@ */ package org.jackhuang.hmcl.ui.construct; +import javafx.geometry.Insets; import javafx.scene.Node; +import javafx.scene.control.Label; import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; @@ -32,20 +34,29 @@ import org.jackhuang.hmcl.util.Lang; public class ClassTitle extends StackPane { private final Node content; + public ClassTitle() { + this((Node) null); + } + public ClassTitle(String text) { - this(new Text(text)); + this(new Label(text)); } public ClassTitle(Node content) { this.content = content; VBox vbox = new VBox(); - vbox.getChildren().addAll(content); Rectangle rectangle = new Rectangle(); rectangle.widthProperty().bind(vbox.widthProperty()); rectangle.setHeight(1.0); rectangle.setFill(Color.GRAY); vbox.getChildren().add(rectangle); + + if (content != null) { + vbox.getChildren().addAll(content); + VBox.setMargin(content, new Insets(16, 16, 0, 16)); + } + getChildren().setAll(vbox); getStyleClass().add("class-title"); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ComponentList.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ComponentList.java index f070fc543..eba0250c9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ComponentList.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ComponentList.java @@ -17,8 +17,6 @@ */ package org.jackhuang.hmcl.ui.construct; -import org.jackhuang.hmcl.util.javafx.MappedObservableList; - import javafx.beans.DefaultProperty; import javafx.beans.binding.Bindings; import javafx.beans.binding.ObjectBinding; @@ -29,10 +27,15 @@ import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.css.PseudoClass; +import javafx.geometry.Insets; +import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.control.Control; +import javafx.scene.control.Label; import javafx.scene.control.SkinBase; +import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.util.javafx.MappedObservableList; import java.util.function.Consumer; @@ -153,8 +156,21 @@ public class ComponentList extends Control { list.get(list.size() - 1).pseudoClassStateChanged(PSEUDO_CLASS_LAST, true); VBox vbox = new VBox(); + vbox.setFillWidth(true); Bindings.bindContent(vbox.getChildren(), list); getChildren().setAll(vbox); } } + + public static Node createComponentListTitle(String title) { + HBox node = new HBox(); + node.setAlignment(Pos.CENTER_LEFT); + node.setPadding(new Insets(8, 0, 0, 0)); + { + Label advanced = new Label(title); + advanced.setStyle("-fx-text-fill: #616161"); + node.getChildren().setAll(advanced); + } + return node; + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/IconedTwoLineListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/IconedTwoLineListItem.java new file mode 100644 index 000000000..750750982 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/IconedTwoLineListItem.java @@ -0,0 +1,114 @@ +package org.jackhuang.hmcl.ui.construct; + +import com.jfoenix.controls.JFXButton; +import javafx.beans.InvalidationListener; +import javafx.beans.binding.Bindings; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Pos; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import org.jackhuang.hmcl.setting.Theme; +import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.ui.SVG; +import org.jackhuang.hmcl.util.Lazy; +import org.jackhuang.hmcl.util.StringUtils; + +public class IconedTwoLineListItem extends HBox { + private final StringProperty title = new SimpleStringProperty(this, "title"); + private final ObservableList tags = FXCollections.observableArrayList(); + private final StringProperty subtitle = new SimpleStringProperty(this, "subtitle"); + private final StringProperty externalLink = new SimpleStringProperty(this, "externalLink"); + private final ObjectProperty image = new SimpleObjectProperty<>(this, "image"); + + private final ImageView imageView = new ImageView(); + private final TwoLineListItem twoLineListItem = new TwoLineListItem(); + private final Lazy externalLinkButton = new Lazy<>(() -> { + JFXButton button = new JFXButton(); + button.getStyleClass().add("toggle-icon4"); + button.setGraphic(SVG.openInNew(Theme.blackFillBinding(), -1, -1)); + button.setOnAction(e -> FXUtils.openLink(externalLink.get())); + return button; + }); + @SuppressWarnings("FieldCanBeLocal") + private final InvalidationListener observer; + + public IconedTwoLineListItem() { + setAlignment(Pos.CENTER); + setSpacing(16); + imageView.imageProperty().bind(image); + twoLineListItem.titleProperty().bind(title); + twoLineListItem.subtitleProperty().bind(subtitle); + HBox.setHgrow(twoLineListItem, Priority.ALWAYS); + Bindings.bindContent(twoLineListItem.getTags(), tags); + + observer = FXUtils.observeWeak(() -> { + getChildren().clear(); + if (image.get() != null) getChildren().add(imageView); + getChildren().add(twoLineListItem); + if (StringUtils.isNotBlank(externalLink.get())) getChildren().add(externalLinkButton.get()); + }, image, externalLink); + } + + public String getTitle() { + return title.get(); + } + + public StringProperty titleProperty() { + return title; + } + + public void setTitle(String title) { + this.title.set(title); + } + + public ObservableList getTags() { + return tags; + } + + public String getSubtitle() { + return subtitle.get(); + } + + public StringProperty subtitleProperty() { + return subtitle; + } + + public void setSubtitle(String subtitle) { + this.subtitle.set(subtitle); + } + + public String getExternalLink() { + return externalLink.get(); + } + + public StringProperty externalLinkProperty() { + return externalLink; + } + + public void setExternalLink(String externalLink) { + this.externalLink.set(externalLink); + } + + public Image getImage() { + return image.get(); + } + + public ObjectProperty imageProperty() { + return image; + } + + public void setImage(Image image) { + this.image.set(image); + } + + public ImageView getImageView() { + return imageView; + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/AboutPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/AboutPage.java new file mode 100644 index 000000000..c4ab15689 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/AboutPage.java @@ -0,0 +1,142 @@ +package org.jackhuang.hmcl.ui.main; + +import javafx.geometry.Insets; +import javafx.scene.control.ScrollPane; +import javafx.scene.image.Image; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.Metadata; +import org.jackhuang.hmcl.ui.construct.ComponentList; +import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem; +import org.jackhuang.hmcl.ui.construct.TwoLineListItem; + +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +public class AboutPage extends StackPane { + + public AboutPage() { + ComponentList about = new ComponentList(); + { + IconedTwoLineListItem launcher = new IconedTwoLineListItem(); + launcher.setImage(new Image("/assets/img/craft_table.png", 32, 32, false, true)); + launcher.setTitle("Hello Minecraft! Launcher"); + launcher.setSubtitle(Metadata.VERSION); + launcher.setExternalLink("https://hmcl.huangyuhui.net"); + + IconedTwoLineListItem author = new IconedTwoLineListItem(); + author.setImage(new Image("/assets/img/yellow_fish.png", 32, 32, false, true)); + author.setTitle("huanghongxun"); + author.setSubtitle("https://www.huangyuhui.net"); + author.setExternalLink("https://www.huangyuhui.net"); + + about.getContent().setAll(launcher, author); + } + + ComponentList thanks = new ComponentList(); + { + IconedTwoLineListItem yushijinhun = new IconedTwoLineListItem(); + yushijinhun.setTitle("yushijinhun"); + yushijinhun.setSubtitle(i18n("about.thanks_to.yushijinhun.statement")); + yushijinhun.setExternalLink("https://yushi.moe/"); + + IconedTwoLineListItem bangbang93 = new IconedTwoLineListItem(); + bangbang93.setTitle("bangbang93"); + bangbang93.setSubtitle(i18n("about.thanks_to.bangbang93.statement")); + bangbang93.setExternalLink("https://bmclapi2.bangbang93.com/"); + + IconedTwoLineListItem gamerteam = new IconedTwoLineListItem(); + gamerteam.setTitle("gamerteam"); + gamerteam.setSubtitle(i18n("about.thanks_to.gamerteam.statement")); + gamerteam.setExternalLink("http://www.zhaisoul.com/"); + + IconedTwoLineListItem contributors = new IconedTwoLineListItem(); + contributors.setTitle(i18n("about.thanks_to.contributors")); + contributors.setSubtitle(i18n("about.thanks_to.contributors.statement")); + contributors.setExternalLink("https://github.com/huanghongxun/HMCL/graphs/contributors"); + + thanks.getContent().setAll(yushijinhun, bangbang93, gamerteam, contributors); + } + + ComponentList dep = new ComponentList(); + { + IconedTwoLineListItem jfoenix = new IconedTwoLineListItem(); + jfoenix.setTitle("JFoenix"); + jfoenix.setSubtitle("Copyright (c) 2016 JFoenix.\nLicensed under the MIT License."); + jfoenix.setExternalLink("http://www.jfoenix.com/"); + + IconedTwoLineListItem gson = new IconedTwoLineListItem(); + gson.setTitle("Gson"); + gson.setSubtitle("Copyright 2008 Google Inc.\nLicensed under the Apache 2.0 License."); + gson.setExternalLink("https://github.com/google/gson"); + + IconedTwoLineListItem xz = new IconedTwoLineListItem(); + xz.setTitle("XZ for Java"); + xz.setSubtitle("Lasse Collin, Igor Pavlov, and/or Brett Okken.\nPublic Domain."); + xz.setExternalLink("https://tukaani.org/xz/java.html"); + + IconedTwoLineListItem fxgson = new IconedTwoLineListItem(); + fxgson.setTitle("fx-gson"); + fxgson.setSubtitle("Copyright (c) 2016 Joffrey Bion.\nLicensed under the MIT License."); + fxgson.setExternalLink("https://github.com/joffrey-bion/fx-gson"); + + IconedTwoLineListItem constantPoolScanner = new IconedTwoLineListItem(); + constantPoolScanner.setTitle("Constant Pool Scanner"); + constantPoolScanner.setSubtitle("Copyright 1997-2010 Oracle and/or its affiliates.\nLicensed under the GPL 2 or the CDDL."); + constantPoolScanner.setExternalLink("https://github.com/jenkinsci/constant-pool-scanner"); + + IconedTwoLineListItem openNBT = new IconedTwoLineListItem(); + openNBT.setTitle("OpenNBT"); + openNBT.setSubtitle("Copyright (C) 2013-2021 Steveice10.\nLicensed under the MIT License."); + openNBT.setExternalLink("https://github.com/Steveice10/OpenNBT"); + + dep.getContent().setAll(jfoenix, gson, xz, fxgson, constantPoolScanner, openNBT); + } + + ComponentList legal = new ComponentList(); + { + TwoLineListItem copyright = new TwoLineListItem(); + copyright.setTitle(i18n("about.copyright")); + copyright.setSubtitle(i18n("about.copyright.statement")); + + TwoLineListItem claim = new TwoLineListItem(); + claim.setTitle(i18n("about.claim")); + claim.setSubtitle(i18n("about.claim.statement")); + + TwoLineListItem openSource = new TwoLineListItem(); + openSource.setTitle(i18n("about.open_source")); + openSource.setSubtitle(i18n("about.open_source.statement")); + + legal.getContent().setAll(copyright, claim, openSource); + } + + ComponentList donations = new ComponentList(); + { + // TODO + } + + VBox content = new VBox(16); + content.setPadding(new Insets(10)); + content.getChildren().setAll( + ComponentList.createComponentListTitle(i18n("about")), + about, + + ComponentList.createComponentListTitle(i18n("about.thanks_to")), + thanks, + + ComponentList.createComponentListTitle(i18n("about.dependency")), + dep, + + ComponentList.createComponentListTitle(i18n("about.legal")), + legal, + + ComponentList.createComponentListTitle(i18n("about.donations")), + donations + ); + + + ScrollPane scrollPane = new ScrollPane(); + scrollPane.setContent(content); + scrollPane.setFitToWidth(true); + getChildren().setAll(scrollPane); + } +} 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 new file mode 100644 index 000000000..d31f45621 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java @@ -0,0 +1,67 @@ +package org.jackhuang.hmcl.ui.main; + +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.scene.layout.BorderPane; +import org.jackhuang.hmcl.ui.FXUtils; +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; + +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, false, 200)); + private final TabHeader tab; + private final TabHeader.Tab settingsTab = new TabHeader.Tab<>("settingsPage"); + private final TabHeader.Tab aboutTab = new TabHeader.Tab<>("aboutPage"); + private final TransitionPane transitionPane = new TransitionPane(); + + public LauncherSettingsPage() { + settingsTab.setNodeSupplier(SettingsPage::new); + aboutTab.setNodeSupplier(AboutPage::new); + tab = new TabHeader(settingsTab, aboutTab); + + tab.getSelectionModel().select(settingsTab); + FXUtils.onChangeAndOperate(tab.getSelectionModel().selectedItemProperty(), newValue -> { + newValue.initializeIfNeeded(); + transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer()); + }); + + { + 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 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(aboutItem); + FXUtils.setLimitWidth(sideBar, 200); + setLeft(sideBar); + } + + setCenter(transitionPane); + } + + @Override + public ReadOnlyObjectProperty stateProperty() { + return state.getReadOnlyProperty(); + } +} 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 4062c4a45..d2c687328 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 @@ -33,6 +33,7 @@ import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.account.AccountAdvancedListItem; import org.jackhuang.hmcl.ui.account.AccountList; import org.jackhuang.hmcl.ui.account.AddAccountPane; @@ -55,8 +56,8 @@ import java.util.Date; import java.util.List; import java.util.stream.Collectors; -import static org.jackhuang.hmcl.ui.FXUtils.newImage; import static org.jackhuang.hmcl.ui.FXUtils.runInFX; +import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class RootPage extends DecoratorTabPage { @@ -64,9 +65,8 @@ public class RootPage extends DecoratorTabPage { private SettingsPage settingsPage = null; private AccountList accountListPage = null; - private final TabHeader.Tab mainTab = new TabHeader.Tab("main"); - private final TabHeader.Tab settingsTab = new TabHeader.Tab("settings"); - private final TabHeader.Tab accountTab = new TabHeader.Tab("account"); + private final TabHeader.Tab mainTab = new TabHeader.Tab<>("main"); + private final TabHeader.Tab accountTab = new TabHeader.Tab<>("account"); public RootPage() { setLeftPaneWidth(200); @@ -78,9 +78,8 @@ public class RootPage extends DecoratorTabPage { onRefreshedVersions(Profiles.selectedProfileProperty().get().getRepository()); mainTab.setNodeSupplier(this::getMainPage); - settingsTab.setNodeSupplier(this::getSettingsPage); accountTab.setNodeSupplier(this::getAccountListPage); - getTabs().setAll(mainTab, settingsTab, accountTab); + getTabs().setAll(mainTab, accountTab); } @Override @@ -155,10 +154,6 @@ public class RootPage extends DecoratorTabPage { return mainTab; } - public Tab getSettingsTab() { - return settingsTab; - } - public Tab getAccountTab() { return accountTab; } @@ -196,22 +191,23 @@ public class RootPage extends DecoratorTabPage { // third item in left sidebar AdvancedListItem gameItem = new AdvancedListItem(); - gameItem.setLeftGraphic(AdvancedListItem.createImageView(newImage("/assets/img/bookshelf.png")).getKey()); + gameItem.getStyleClass().add("navigation-drawer-item"); + gameItem.setLeftGraphic(wrap(SVG.gamepad(null, 20, 20))); gameItem.setTitle(i18n("version.manage")); gameItem.setOnAction(e -> Controllers.navigate(Controllers.getGameListPage())); // fifth item in left sidebar AdvancedListItem launcherSettingsItem = new AdvancedListItem(); - launcherSettingsItem.activeProperty().bind(control.settingsTab.selectedProperty()); - launcherSettingsItem.setLeftGraphic(AdvancedListItem.createImageView(newImage("/assets/img/command.png")).getKey()); + launcherSettingsItem.getStyleClass().add("navigation-drawer-item"); + launcherSettingsItem.setLeftGraphic(wrap(SVG.gearOutline(null, 20, 20))); + launcherSettingsItem.setActionButtonVisible(false); launcherSettingsItem.setTitle(i18n("settings.launcher")); - launcherSettingsItem.setOnAction(e -> control.selectPage(control.settingsTab)); + launcherSettingsItem.setOnAction(e -> Controllers.navigate(Controllers.getSettingsPage())); // the left sidebar AdvancedListBox sideBar = new AdvancedListBox() - .startCategory(i18n("account").toUpperCase()) .add(accountListItem) - .startCategory(i18n("version").toUpperCase()) + .startCategory() .add(gameListItem) .add(gameItem) .startCategory(i18n("launcher").toUpperCase()) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java index fdce83dda..0ea90b12b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java @@ -23,8 +23,6 @@ import javafx.beans.InvalidationListener; import javafx.beans.WeakInvalidationListener; import javafx.beans.binding.Bindings; import javafx.beans.binding.When; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.scene.control.ColorPicker; import javafx.scene.control.ToggleGroup; import javafx.scene.paint.Color; @@ -35,7 +33,6 @@ import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.construct.Validator; -import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.upgrade.RemoteVersion; import org.jackhuang.hmcl.upgrade.UpdateChannel; import org.jackhuang.hmcl.upgrade.UpdateChecker; @@ -65,8 +62,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.reversedSelectedPropertyFor; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor; -public final class SettingsPage extends SettingsView implements DecoratorPage { - private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("settings.launcher"))); +public final class SettingsPage extends SettingsView { private InvalidationListener updateListener; @@ -196,11 +192,6 @@ public final class SettingsPage extends SettingsView implements DecoratorPage { // ==== } - @Override - public ReadOnlyObjectProperty stateProperty() { - return state.getReadOnlyProperty(); - } - @Override protected void onUpdate() { RemoteVersion target = UpdateChecker.getLatestVersion(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java index b6e43b475..d336f0540 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java @@ -25,6 +25,7 @@ import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.geometry.Insets; import javafx.geometry.Pos; +import javafx.scene.Node; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.image.Image; @@ -246,14 +247,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag componentList.getContent().setAll(javaItem, gameDirItem, maxMemoryPane, launcherVisibilityPane, dimensionPane, showLogsPane); } - HBox advancedHintPane = new HBox(); - advancedHintPane.setAlignment(Pos.CENTER_LEFT); - advancedHintPane.setPadding(new Insets(8, 0, 0, 0)); - { - Label advanced = new Label(i18n("settings.advanced")); - advanced.setStyle("-fx-text-fill: #616161"); - advancedHintPane.getChildren().setAll(advanced); - } + Node advancedHintPane = ComponentList.createComponentListTitle(i18n("settings.advanced")); advancedSettingsPane = new ComponentList(); advancedSettingsPane.setDepth(1); diff --git a/HMCL/src/main/resources/assets/css/root.css b/HMCL/src/main/resources/assets/css/root.css index c725e271e..a022728dd 100644 --- a/HMCL/src/main/resources/assets/css/root.css +++ b/HMCL/src/main/resources/assets/css/root.css @@ -131,7 +131,8 @@ .class-title { -fx-font-size: 12px; - -fx-padding: 16 16 8 16; + -fx-text-fill: gray; + -fx-padding: 8 0 8 0; } .advanced-list-box-item { diff --git a/HMCL/src/main/resources/assets/img/yellow_fish.png b/HMCL/src/main/resources/assets/img/yellow_fish.png new file mode 100644 index 000000000..1b57f07f3 Binary files /dev/null and b/HMCL/src/main/resources/assets/img/yellow_fish.png differ