diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPopupMenu.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPopupMenu.java new file mode 100644 index 000000000..99461c45a --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPopupMenu.java @@ -0,0 +1,79 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2026 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.JFXPopup; +import javafx.beans.InvalidationListener; +import javafx.beans.WeakInvalidationListener; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.StackPane; +import org.jackhuang.hmcl.auth.Account; +import org.jackhuang.hmcl.setting.Accounts; +import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.ui.construct.AdvancedListBox; + +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +public final class AccountListPopupMenu extends StackPane { + public static void show(Node owner, JFXPopup.PopupVPosition vAlign, JFXPopup.PopupHPosition hAlign, + double initOffsetX, double initOffsetY) { + var menu = new AccountListPopupMenu(); + JFXPopup popup = new JFXPopup(menu); + popup.show(owner, vAlign, hAlign, initOffsetX, initOffsetY); + } + + @SuppressWarnings("FieldCanBeLocal") + private final BooleanBinding isEmpty = Bindings.isEmpty(Accounts.getAccounts()); + @SuppressWarnings("FieldCanBeLocal") + private final InvalidationListener listener; + + public AccountListPopupMenu() { + AdvancedListBox box = new AdvancedListBox(); + box.getStyleClass().add("no-padding"); + box.setPrefWidth(220); + box.setPrefHeight(-1); + box.setMaxHeight(260); + + listener = o -> { + box.clear(); + + for (Account account : Accounts.getAccounts()) { + AccountAdvancedListItem item = new AccountAdvancedListItem(account); + item.setOnAction(e -> { + Accounts.setSelectedAccount(account); + if (getScene().getWindow() instanceof JFXPopup popup) + popup.hide(); + }); + box.add(item); + } + }; + listener.invalidated(null); + Accounts.getAccounts().addListener(new WeakInvalidationListener(listener)); + + Label placeholder = new Label(i18n("account.empty")); + placeholder.setStyle("-fx-padding: 10px; -fx-text-fill: -monet-on-surface-variant; -fx-font-style: italic;"); + + FXUtils.onChangeAndOperate(isEmpty, empty -> { + getChildren().setAll(empty ? placeholder : box); + }); + } + +} 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 38a712291..ba086aa16 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 @@ -19,9 +19,7 @@ package org.jackhuang.hmcl.ui.main; import com.jfoenix.controls.JFXPopup; import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.scene.control.Label; import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.event.EventBus; import org.jackhuang.hmcl.event.RefreshedVersionsEvent; import org.jackhuang.hmcl.game.HMCLGameRepository; @@ -37,11 +35,11 @@ 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.AccountListPopupMenu; import org.jackhuang.hmcl.ui.animation.AnimationUtils; import org.jackhuang.hmcl.ui.construct.AdvancedListBox; import org.jackhuang.hmcl.ui.construct.AdvancedListItem; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; -import org.jackhuang.hmcl.ui.construct.PopupMenu; import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider; @@ -148,7 +146,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { // first item in left sidebar AccountAdvancedListItem accountListItem = new AccountAdvancedListItem(); accountListItem.setOnAction(e -> Controllers.navigate(Controllers.getAccountListPage())); - FXUtils.onSecondaryButtonClicked(accountListItem, () -> showAccountListPopupMenu(accountListItem)); + FXUtils.onSecondaryButtonClicked(accountListItem, () -> AccountListPopupMenu.show(accountListItem, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.LEFT, accountListItem.getWidth(), 0)); accountListItem.accountProperty().bind(Accounts.selectedAccountProperty()); // second item in left sidebar @@ -251,36 +249,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { setCenter(getSkinnable().getMainPage()); } - public void showAccountListPopupMenu( - AccountAdvancedListItem accountListItem - ) { - PopupMenu popupMenu = new PopupMenu(); - JFXPopup popup = new JFXPopup(popupMenu); - AdvancedListBox scrollPane = new AdvancedListBox(); - scrollPane.getStyleClass().add("no-padding"); - scrollPane.setPrefWidth(220); - scrollPane.setPrefHeight(-1); - scrollPane.setMaxHeight(260); - - if (Accounts.getAccounts().isEmpty()) { - Label placeholder = new Label(i18n("account.empty")); - placeholder.setStyle("-fx-padding: 10px; -fx-text-fill: -monet-on-surface-variant; -fx-font-style: italic;"); - scrollPane.add(placeholder); - } else { - for (Account account : Accounts.getAccounts()) { - AccountAdvancedListItem item = new AccountAdvancedListItem(account); - item.setOnAction(e -> { - Accounts.setSelectedAccount(account); - popup.hide(); - }); - scrollPane.add(item); - } - } - - popupMenu.getContent().add(scrollPane); - popup.show(accountListItem, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.LEFT, accountListItem.getWidth(), 0); - } - public void showGameListPopupMenu(AdvancedListItem gameListItem) { GameListPopupMenu.show(gameListItem, JFXPopup.PopupVPosition.TOP, diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java index d70e05eed..f08bbf43e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java @@ -25,12 +25,15 @@ import javafx.geometry.Insets; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.setting.Accounts; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.terracotta.TerracottaMetadata; 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.AccountListPopupMenu; import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.ui.construct.*; import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage; @@ -69,7 +72,13 @@ public class TerracottaPage extends DecoratorAnimatedPage implements DecoratorPa .addNavigationDrawerTab(tab, statusPage, i18n("terracotta.status"), SVG.TUNE); left.setTop(sideBar); + AccountAdvancedListItem accountListItem = new AccountAdvancedListItem(); + accountListItem.setOnAction(e -> Controllers.navigate(Controllers.getAccountListPage())); + accountListItem.accountProperty().bind(Accounts.selectedAccountProperty()); + FXUtils.onSecondaryButtonClicked(accountListItem, () -> AccountListPopupMenu.show(accountListItem, JFXPopup.PopupVPosition.BOTTOM, JFXPopup.PopupHPosition.LEFT, accountListItem.getWidth(), 0)); + AdvancedListBox toolbar = new AdvancedListBox() + .add(accountListItem) .addNavigationDrawerItem(i18n("version.launch"), SVG.ROCKET_LAUNCH, () -> { Profile profile = Profiles.getSelectedProfile(); Versions.launch(profile, profile.getSelectedVersion(), launcherHelper -> {