优化导航底部工具区
This commit is contained in:
@@ -8,10 +8,7 @@ import javafx.geometry.Insets;
|
|||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.ContentDisplay;
|
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.Tooltip;
|
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
@@ -88,9 +85,9 @@ public class MainWindow {
|
|||||||
stage.setOnCloseRequest(event -> embeddedCache.clear());
|
stage.setOnCloseRequest(event -> embeddedCache.clear());
|
||||||
|
|
||||||
BorderPane root = new BorderPane();
|
BorderPane root = new BorderPane();
|
||||||
root.setTop(buildUnifiedHeader(openSettings));
|
root.setTop(buildUnifiedHeader());
|
||||||
|
|
||||||
navigationRail = new NavigationRail(navItems, this::navigateTo);
|
navigationRail = new NavigationRail(navItems, this::navigateTo, openSettings);
|
||||||
contentArea = new StackPane();
|
contentArea = new StackPane();
|
||||||
contentArea.getStyleClass().add(Theme.CSS_CONTENT_AREA);
|
contentArea.getStyleClass().add(Theme.CSS_CONTENT_AREA);
|
||||||
HBox.setHgrow(contentArea, Priority.ALWAYS);
|
HBox.setHgrow(contentArea, Priority.ALWAYS);
|
||||||
@@ -104,7 +101,7 @@ public class MainWindow {
|
|||||||
showWelcomePage();
|
showWelcomePage();
|
||||||
}
|
}
|
||||||
|
|
||||||
private HBox buildUnifiedHeader(Runnable openSettings) {
|
private HBox buildUnifiedHeader() {
|
||||||
HBox bar = new HBox(Theme.S1);
|
HBox bar = new HBox(Theme.S1);
|
||||||
bar.setId("app-header");
|
bar.setId("app-header");
|
||||||
bar.setAlignment(Pos.CENTER_LEFT);
|
bar.setAlignment(Pos.CENTER_LEFT);
|
||||||
@@ -114,13 +111,6 @@ public class MainWindow {
|
|||||||
bar.setMaxHeight(DesignTokens.HEADER_HEIGHT);
|
bar.setMaxHeight(DesignTokens.HEADER_HEIGHT);
|
||||||
bar.getStyleClass().add(Theme.CSS_HEADER_BAR);
|
bar.getStyleClass().add(Theme.CSS_HEADER_BAR);
|
||||||
|
|
||||||
Button menuButton = new Button(null, IconFactory.createButtonIcon(AppIcon.MENU, "切换导航栏"));
|
|
||||||
menuButton.setId("menu-button");
|
|
||||||
menuButton.setTooltip(new Tooltip("切换导航栏"));
|
|
||||||
menuButton.setAccessibleText("切换导航栏");
|
|
||||||
menuButton.setFocusTraversable(true);
|
|
||||||
menuButton.setOnAction(event -> navigationRail.toggle());
|
|
||||||
|
|
||||||
FontIcon brandIcon = IconFactory.create(AppIcon.APP, 18);
|
FontIcon brandIcon = IconFactory.create(AppIcon.APP, 18);
|
||||||
StackPane brandIconContainer = new StackPane(brandIcon);
|
StackPane brandIconContainer = new StackPane(brandIcon);
|
||||||
brandIconContainer.setId("app-brand-icon-container");
|
brandIconContainer.setId("app-brand-icon-container");
|
||||||
@@ -148,17 +138,7 @@ public class MainWindow {
|
|||||||
Region spacerRight = new Region();
|
Region spacerRight = new Region();
|
||||||
HBox.setHgrow(spacerRight, Priority.ALWAYS);
|
HBox.setHgrow(spacerRight, Priority.ALWAYS);
|
||||||
|
|
||||||
Button settingsButton = new Button(
|
bar.getChildren().addAll(brand, toolbarChevron, toolbarTitle, spacerRight);
|
||||||
"系统设置", IconFactory.createButtonIcon(AppIcon.SETTINGS, "系统设置"));
|
|
||||||
settingsButton.setId("settings-button");
|
|
||||||
settingsButton.setTooltip(new Tooltip("系统设置"));
|
|
||||||
settingsButton.setAccessibleText("系统设置");
|
|
||||||
settingsButton.setContentDisplay(ContentDisplay.LEFT);
|
|
||||||
settingsButton.setFocusTraversable(true);
|
|
||||||
settingsButton.setOnAction(event -> openSettings.run());
|
|
||||||
|
|
||||||
bar.getChildren().addAll(
|
|
||||||
menuButton, brand, toolbarChevron, toolbarTitle, spacerRight, settingsButton);
|
|
||||||
return bar;
|
return bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +217,7 @@ public class MainWindow {
|
|||||||
|
|
||||||
private void switchToEmbedded(String pluginId, EmbeddedEntry entry) {
|
private void switchToEmbedded(String pluginId, EmbeddedEntry entry) {
|
||||||
if ("__settings__".equals(pluginId)) {
|
if ("__settings__".equals(pluginId)) {
|
||||||
navigationRail.clearSelection();
|
navigationRail.selectSettings();
|
||||||
}
|
}
|
||||||
if (currentEmbedded != null && currentEmbedded != entry) {
|
if (currentEmbedded != null && currentEmbedded != entry) {
|
||||||
contentArea.getChildren().remove(currentEmbedded.wrapper);
|
contentArea.getChildren().remove(currentEmbedded.wrapper);
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ public final class NavigationRail extends VBox {
|
|||||||
private final List<ItemView> itemViews = new ArrayList<>();
|
private final List<ItemView> itemViews = new ArrayList<>();
|
||||||
private final Map<String, ItemView> viewsByPluginId = new LinkedHashMap<>();
|
private final Map<String, ItemView> viewsByPluginId = new LinkedHashMap<>();
|
||||||
private final VBox itemBox = new VBox();
|
private final VBox itemBox = new VBox();
|
||||||
|
private final VBox utilityBox = new VBox();
|
||||||
|
private final ToggleButton settingsButton = new ToggleButton();
|
||||||
private final Button collapseButton = new Button();
|
private final Button collapseButton = new Button();
|
||||||
|
|
||||||
private MainWindow.NavItem selectedItem;
|
private MainWindow.NavItem selectedItem;
|
||||||
@@ -46,14 +48,26 @@ public final class NavigationRail extends VBox {
|
|||||||
|
|
||||||
public NavigationRail(List<MainWindow.NavItem> items,
|
public NavigationRail(List<MainWindow.NavItem> items,
|
||||||
Consumer<MainWindow.NavItem> navigator) {
|
Consumer<MainWindow.NavItem> navigator) {
|
||||||
|
this(items, navigator, () -> { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavigationRail(List<MainWindow.NavItem> items,
|
||||||
|
Consumer<MainWindow.NavItem> navigator,
|
||||||
|
Runnable openSettings) {
|
||||||
requireFxThread();
|
requireFxThread();
|
||||||
this.navigator = Objects.requireNonNull(navigator, "navigator must not be null");
|
this.navigator = Objects.requireNonNull(navigator, "navigator must not be null");
|
||||||
|
Objects.requireNonNull(openSettings, "openSettings must not be null");
|
||||||
|
|
||||||
getStyleClass().addAll(Theme.CSS_NAV_BAR, "navigation-rail");
|
getStyleClass().addAll(Theme.CSS_NAV_BAR, "navigation-rail");
|
||||||
itemBox.getStyleClass().add("navigation-rail-items");
|
itemBox.getStyleClass().add("navigation-rail-items");
|
||||||
VBox.setVgrow(itemBox, Priority.ALWAYS);
|
VBox.setVgrow(itemBox, Priority.ALWAYS);
|
||||||
|
buildSettingsEntry(openSettings);
|
||||||
buildBottomToggle();
|
buildBottomToggle();
|
||||||
|
|
||||||
|
utilityBox.setId("navigation-rail-tools");
|
||||||
|
utilityBox.getStyleClass().add("navigation-rail-tools");
|
||||||
|
utilityBox.getChildren().addAll(settingsButton, collapseButton);
|
||||||
|
|
||||||
Separator separator = new Separator();
|
Separator separator = new Separator();
|
||||||
separator.setId("navigation-rail-separator");
|
separator.setId("navigation-rail-separator");
|
||||||
separator.getStyleClass().add(Theme.CSS_NAV_SEP);
|
separator.getStyleClass().add(Theme.CSS_NAV_SEP);
|
||||||
@@ -62,7 +76,7 @@ public final class NavigationRail extends VBox {
|
|||||||
separator.setPrefHeight(1);
|
separator.setPrefHeight(1);
|
||||||
separator.setMaxHeight(1);
|
separator.setMaxHeight(1);
|
||||||
separator.setFocusTraversable(false);
|
separator.setFocusTraversable(false);
|
||||||
getChildren().addAll(itemBox, separator, collapseButton);
|
getChildren().addAll(itemBox, separator, utilityBox);
|
||||||
|
|
||||||
expanded.addListener((observable, oldValue, newValue) -> updateAppearance());
|
expanded.addListener((observable, oldValue, newValue) -> updateAppearance());
|
||||||
setItems(items);
|
setItems(items);
|
||||||
@@ -106,6 +120,18 @@ public final class NavigationRail extends VBox {
|
|||||||
requireFxThread();
|
requireFxThread();
|
||||||
selection.selectToggle(null);
|
selection.selectToggle(null);
|
||||||
itemViews.forEach(view -> view.button().getStyleClass().remove(Theme.CSS_NAV_CELL_ACTIVE));
|
itemViews.forEach(view -> view.button().getStyleClass().remove(Theme.CSS_NAV_CELL_ACTIVE));
|
||||||
|
settingsButton.getStyleClass().remove(Theme.CSS_NAV_CELL_ACTIVE);
|
||||||
|
selectedItem = null;
|
||||||
|
selectedPluginId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void selectSettings() {
|
||||||
|
requireFxThread();
|
||||||
|
selection.selectToggle(settingsButton);
|
||||||
|
itemViews.forEach(view -> view.button().getStyleClass().remove(Theme.CSS_NAV_CELL_ACTIVE));
|
||||||
|
if (!settingsButton.getStyleClass().contains(Theme.CSS_NAV_CELL_ACTIVE)) {
|
||||||
|
settingsButton.getStyleClass().add(Theme.CSS_NAV_CELL_ACTIVE);
|
||||||
|
}
|
||||||
selectedItem = null;
|
selectedItem = null;
|
||||||
selectedPluginId = null;
|
selectedPluginId = null;
|
||||||
}
|
}
|
||||||
@@ -137,6 +163,24 @@ public final class NavigationRail extends VBox {
|
|||||||
return view == null ? null : view.tooltip();
|
return view == null ? null : view.tooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void buildSettingsEntry(Runnable openSettings) {
|
||||||
|
settingsButton.setId("navigation-rail-settings");
|
||||||
|
settingsButton.getStyleClass().addAll(Theme.CSS_NAV_CELL, "navigation-rail-settings");
|
||||||
|
settingsButton.setToggleGroup(selection);
|
||||||
|
settingsButton.setContentDisplay(ContentDisplay.LEFT);
|
||||||
|
settingsButton.setGraphicTextGap(Theme.S3);
|
||||||
|
settingsButton.setMinHeight(DesignTokens.ROW_HEIGHT);
|
||||||
|
settingsButton.setPrefHeight(DesignTokens.ROW_HEIGHT);
|
||||||
|
settingsButton.setMaxHeight(DesignTokens.ROW_HEIGHT);
|
||||||
|
settingsButton.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
settingsButton.setAccessibleText("系统设置");
|
||||||
|
settingsButton.setFocusTraversable(true);
|
||||||
|
settingsButton.setOnAction(event -> {
|
||||||
|
selectSettings();
|
||||||
|
openSettings.run();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void buildBottomToggle() {
|
private void buildBottomToggle() {
|
||||||
collapseButton.setId("navigation-rail-toggle");
|
collapseButton.setId("navigation-rail-toggle");
|
||||||
collapseButton.getStyleClass().addAll(Theme.CSS_NAV_CELL, "navigation-rail-toggle");
|
collapseButton.getStyleClass().addAll(Theme.CSS_NAV_CELL, "navigation-rail-toggle");
|
||||||
@@ -182,6 +226,7 @@ public final class NavigationRail extends VBox {
|
|||||||
|
|
||||||
private void activate(MainWindow.NavItem item, ToggleButton button) {
|
private void activate(MainWindow.NavItem item, ToggleButton button) {
|
||||||
selection.selectToggle(button);
|
selection.selectToggle(button);
|
||||||
|
settingsButton.getStyleClass().remove(Theme.CSS_NAV_CELL_ACTIVE);
|
||||||
itemViews.forEach(view -> view.button().getStyleClass().remove(Theme.CSS_NAV_CELL_ACTIVE));
|
itemViews.forEach(view -> view.button().getStyleClass().remove(Theme.CSS_NAV_CELL_ACTIVE));
|
||||||
if (!button.getStyleClass().contains(Theme.CSS_NAV_CELL_ACTIVE)) {
|
if (!button.getStyleClass().contains(Theme.CSS_NAV_CELL_ACTIVE)) {
|
||||||
button.getStyleClass().add(Theme.CSS_NAV_CELL_ACTIVE);
|
button.getStyleClass().add(Theme.CSS_NAV_CELL_ACTIVE);
|
||||||
@@ -212,6 +257,10 @@ public final class NavigationRail extends VBox {
|
|||||||
collapseButton.setAccessibleText(accessibleText);
|
collapseButton.setAccessibleText(accessibleText);
|
||||||
collapseButton.setTooltip(new Tooltip(accessibleText));
|
collapseButton.setTooltip(new Tooltip(accessibleText));
|
||||||
collapseButton.setAlignment(isExpanded() ? Pos.CENTER_LEFT : Pos.CENTER);
|
collapseButton.setAlignment(isExpanded() ? Pos.CENTER_LEFT : Pos.CENTER);
|
||||||
|
settingsButton.setGraphic(IconFactory.createButtonIcon(AppIcon.SETTINGS, "系统设置"));
|
||||||
|
settingsButton.setText(isExpanded() ? "系统设置" : null);
|
||||||
|
settingsButton.setTooltip(isExpanded() ? null : new Tooltip("系统设置"));
|
||||||
|
settingsButton.setAlignment(isExpanded() ? Pos.CENTER_LEFT : Pos.CENTER);
|
||||||
updateItemAppearance();
|
updateItemAppearance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ class MainWindowArchitectureTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void settingsIsAUniqueHeaderActionInsteadOfANavigationItem() throws Exception {
|
void settingsUsesTheExplicitShellActionWithoutBecomingABusinessItem() throws Exception {
|
||||||
String application = source("src/main/java/com/example/workutils/WorkUtilsApplication.java");
|
String application = source("src/main/java/com/example/workutils/WorkUtilsApplication.java");
|
||||||
String buildNavItems = between(application,
|
String buildNavItems = between(application,
|
||||||
"private List<MainWindow.NavItem> buildNavItems()",
|
"private List<MainWindow.NavItem> buildNavItems()",
|
||||||
"// ==================== 内嵌优先打开");
|
"// ==================== 内嵌优先打开");
|
||||||
String mainWindow = source("src/main/java/com/example/workutils/system/ui/MainWindow.java");
|
String mainWindow = source("src/main/java/com/example/workutils/system/ui/MainWindow.java");
|
||||||
|
String navigationRail = source(
|
||||||
|
"src/main/java/com/example/workutils/system/ui/shell/NavigationRail.java");
|
||||||
|
|
||||||
assertFalse(buildNavItems.contains("__settings__"));
|
assertFalse(buildNavItems.contains("__settings__"));
|
||||||
assertFalse(buildNavItems.contains("系统设置"));
|
assertFalse(buildNavItems.contains("系统设置"));
|
||||||
@@ -39,8 +41,8 @@ class MainWindowArchitectureTest {
|
|||||||
"new MainWindow(navItems, properties, this::openSettingsEmbedded)"));
|
"new MainWindow(navItems, properties, this::openSettingsEmbedded)"));
|
||||||
assertTrue(mainWindow.contains(
|
assertTrue(mainWindow.contains(
|
||||||
"MainWindow(List<NavItem> navItems, WorkUtilsProperties properties, Runnable openSettings)"));
|
"MainWindow(List<NavItem> navItems, WorkUtilsProperties properties, Runnable openSettings)"));
|
||||||
assertTrue(mainWindow.contains("IconFactory.createButtonIcon(AppIcon.SETTINGS"));
|
assertTrue(mainWindow.contains("new NavigationRail(navItems, this::navigateTo, openSettings)"));
|
||||||
assertTrue(mainWindow.contains("openSettings.run()"));
|
assertTrue(navigationRail.contains("openSettings.run()"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -71,13 +73,12 @@ class MainWindowArchitectureTest {
|
|||||||
String header = between(mainWindow, "private HBox buildUnifiedHeader", "private void navigateTo");
|
String header = between(mainWindow, "private HBox buildUnifiedHeader", "private void navigateTo");
|
||||||
|
|
||||||
assertTrue(header.contains("DesignTokens.HEADER_HEIGHT"));
|
assertTrue(header.contains("DesignTokens.HEADER_HEIGHT"));
|
||||||
assertTrue(header.contains("IconFactory.createButtonIcon(AppIcon.MENU"));
|
|
||||||
assertTrue(header.contains("navigationRail.toggle()"));
|
|
||||||
assertTrue(header.contains("IconFactory.create(AppIcon.APP"));
|
assertTrue(header.contains("IconFactory.create(AppIcon.APP"));
|
||||||
assertTrue(header.contains("IconFactory.create(AppIcon.CHEVRON_RIGHT"));
|
assertTrue(header.contains("IconFactory.create(AppIcon.CHEVRON_RIGHT"));
|
||||||
assertTrue(header.contains("IconFactory.createButtonIcon(AppIcon.SETTINGS"));
|
assertFalse(header.contains("AppIcon.MENU"));
|
||||||
assertEquals(1, occurrences(header, "AppIcon.SETTINGS"));
|
assertFalse(header.contains("AppIcon.SETTINGS"));
|
||||||
assertEquals(1, occurrences(header, "openSettings.run()"));
|
assertFalse(header.contains("navigationRail.toggle()"));
|
||||||
|
assertFalse(header.contains("openSettings.run()"));
|
||||||
assertFalse(header.contains("toolbarIcon"));
|
assertFalse(header.contains("toolbarIcon"));
|
||||||
assertFalse(header.contains("SVGPath"));
|
assertFalse(header.contains("SVGPath"));
|
||||||
assertFalse(header.contains("<svg"));
|
assertFalse(header.contains("<svg"));
|
||||||
|
|||||||
+11
-20
@@ -19,7 +19,6 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ButtonBase;
|
import javafx.scene.control.ButtonBase;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.Labeled;
|
|
||||||
import javafx.scene.control.ProgressIndicator;
|
import javafx.scene.control.ProgressIndicator;
|
||||||
import javafx.scene.control.ToggleButton;
|
import javafx.scene.control.ToggleButton;
|
||||||
import javafx.scene.image.WritableImage;
|
import javafx.scene.image.WritableImage;
|
||||||
@@ -47,6 +46,7 @@ import org.kordamp.ikonli.javafx.FontIcon;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@@ -384,26 +384,17 @@ final class NativeUiVisualAcceptanceFixture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void validateSettingsControl(Scene scene, Node header) {
|
private void validateSettingsControl(Scene scene, Node header) {
|
||||||
List<ButtonBase> settingsControls = descendants(scene.getRoot()).stream()
|
ButtonBase settings = (ButtonBase) scene.lookup("#navigation-rail-settings");
|
||||||
.filter(ButtonBase.class::isInstance)
|
assertNotNull(settings);
|
||||||
.map(ButtonBase.class::cast)
|
assertTrue(settings.isVisible());
|
||||||
.filter(Node::isVisible)
|
assertSame(settings, navigationRail.lookup("#navigation-rail-settings"));
|
||||||
.filter(control -> "系统设置".equals(control.getText()))
|
assertFalse(descendants((Parent) header).contains(settings));
|
||||||
.toList();
|
assertEquals("系统设置", settings.getAccessibleText());
|
||||||
assertEquals(1, settingsControls.size(),
|
|
||||||
"Exactly one visible system settings control is required");
|
|
||||||
ButtonBase settings = settingsControls.get(0);
|
|
||||||
assertSame(scene.lookup("#settings-button"), settings);
|
|
||||||
assertTrue(descendants((Parent) header).contains(settings));
|
|
||||||
Bounds position = settings.localToScene(settings.getBoundsInLocal());
|
Bounds position = settings.localToScene(settings.getBoundsInLocal());
|
||||||
assertTrue(position.getMinX() > scene.getWidth() / 2,
|
assertTrue(position.getMaxX() <= navigationRail.getWidth() + 1,
|
||||||
"System settings must remain at the top-right");
|
"System settings must remain inside the navigation rail");
|
||||||
|
assertNull(scene.lookup("#settings-button"));
|
||||||
boolean settingsInNavigation = descendants(navigationRail).stream()
|
assertNull(scene.lookup("#menu-button"));
|
||||||
.filter(Labeled.class::isInstance)
|
|
||||||
.map(Labeled.class::cast)
|
|
||||||
.anyMatch(control -> "系统设置".equals(control.getText()));
|
|
||||||
assertFalse(settingsInNavigation, "System settings must not appear in navigation");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureRequestedSizeFitsDesktop(CaptureSpec spec) {
|
private void ensureRequestedSizeFitsDesktop(CaptureSpec spec) {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class NavigationRailTest {
|
|||||||
"api-doc");
|
"api-doc");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void headerHasOnlyMenuBrandChevronTitleSpacerAndSettings() throws Exception {
|
void headerContainsOnlyBrandBreadcrumbTitleAndSpacer() throws Exception {
|
||||||
fx(() -> {
|
fx(() -> {
|
||||||
MainWindow window = new MainWindow(List.of(), new WorkUtilsProperties(), () -> {
|
MainWindow window = new MainWindow(List.of(), new WorkUtilsProperties(), () -> {
|
||||||
});
|
});
|
||||||
@@ -60,18 +60,14 @@ class NavigationRailTest {
|
|||||||
stage(window).getScene().getRoot().applyCss();
|
stage(window).getScene().getRoot().applyCss();
|
||||||
stage(window).getScene().getRoot().layout();
|
stage(window).getScene().getRoot().layout();
|
||||||
|
|
||||||
assertEquals(6, header.getChildren().size());
|
assertEquals(4, header.getChildren().size());
|
||||||
Button menu = assertInstanceOf(Button.class, header.getChildren().get(0));
|
HBox brand = assertInstanceOf(HBox.class, header.getChildren().get(0));
|
||||||
HBox brand = assertInstanceOf(HBox.class, header.getChildren().get(1));
|
FontIcon chevron = assertInstanceOf(FontIcon.class, header.getChildren().get(1));
|
||||||
FontIcon chevron = assertInstanceOf(FontIcon.class, header.getChildren().get(2));
|
Label title = assertInstanceOf(Label.class, header.getChildren().get(2));
|
||||||
Label title = assertInstanceOf(Label.class, header.getChildren().get(3));
|
assertInstanceOf(Region.class, header.getChildren().get(3));
|
||||||
assertInstanceOf(Region.class, header.getChildren().get(4));
|
|
||||||
Button settings = assertInstanceOf(Button.class, header.getChildren().get(5));
|
|
||||||
|
|
||||||
assertEquals(AppIcon.MENU.glyph(),
|
assertNull(header.lookup("#menu-button"));
|
||||||
assertInstanceOf(FontIcon.class, menu.getGraphic()).getIconCode());
|
assertNull(header.lookup("#settings-button"));
|
||||||
assertEquals("切换导航栏", menu.getAccessibleText());
|
|
||||||
assertTrue(menu.isFocusTraversable());
|
|
||||||
assertEquals(2, brand.getChildren().size());
|
assertEquals(2, brand.getChildren().size());
|
||||||
StackPane brandIconContainer = assertInstanceOf(
|
StackPane brandIconContainer = assertInstanceOf(
|
||||||
StackPane.class, brand.getChildren().get(0));
|
StackPane.class, brand.getChildren().get(0));
|
||||||
@@ -94,12 +90,6 @@ class NavigationRailTest {
|
|||||||
assertEquals("WorkUtils", brandText.getText());
|
assertEquals("WorkUtils", brandText.getText());
|
||||||
assertEquals(AppIcon.CHEVRON_RIGHT.glyph(), chevron.getIconCode());
|
assertEquals(AppIcon.CHEVRON_RIGHT.glyph(), chevron.getIconCode());
|
||||||
assertEquals("API", title.getText());
|
assertEquals("API", title.getText());
|
||||||
assertEquals(AppIcon.SETTINGS.glyph(),
|
|
||||||
assertInstanceOf(FontIcon.class, settings.getGraphic()).getIconCode());
|
|
||||||
assertEquals("系统设置", settings.getText());
|
|
||||||
assertEquals("系统设置", settings.getAccessibleText());
|
|
||||||
assertEquals(ContentDisplay.LEFT, settings.getContentDisplay());
|
|
||||||
assertTrue(settings.isFocusTraversable());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,15 +143,27 @@ class NavigationRailTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void railKeepsCollapseEntryAtBottomWithoutDuplicatingTheApplicationBrand() throws Exception {
|
void railBottomToolsKeepSettingsAboveTheLastCollapseEntry() throws Exception {
|
||||||
fx(() -> {
|
fx(() -> {
|
||||||
NavigationRail rail = new NavigationRail(List.of(API_DOC), item -> {
|
MainWindow window = new MainWindow(List.of(API_DOC), new WorkUtilsProperties(), () -> {
|
||||||
});
|
});
|
||||||
|
NavigationRail rail = assertInstanceOf(
|
||||||
|
NavigationRail.class, stage(window).getScene().getRoot().lookup(".navigation-rail"));
|
||||||
|
|
||||||
|
VBox tools = assertInstanceOf(VBox.class, rail.lookup("#navigation-rail-tools"));
|
||||||
|
ToggleButton settings = assertInstanceOf(
|
||||||
|
ToggleButton.class, rail.lookup("#navigation-rail-settings"));
|
||||||
Button collapse = assertInstanceOf(
|
Button collapse = assertInstanceOf(
|
||||||
Button.class, rail.lookup("#navigation-rail-toggle"));
|
Button.class, rail.lookup("#navigation-rail-toggle"));
|
||||||
assertSame(collapse, rail.getChildren().get(rail.getChildren().size() - 1));
|
assertEquals(List.of(settings, collapse), tools.getChildren());
|
||||||
|
assertSame(tools, rail.getChildren().get(rail.getChildren().size() - 1));
|
||||||
|
assertSame(collapse, tools.getChildren().get(tools.getChildren().size() - 1));
|
||||||
assertTrue(rail.lookupAll(".nav-brand").isEmpty());
|
assertTrue(rail.lookupAll(".nav-brand").isEmpty());
|
||||||
|
assertEquals(AppIcon.SETTINGS.glyph(),
|
||||||
|
assertInstanceOf(FontIcon.class, settings.getGraphic()).getIconCode());
|
||||||
|
assertEquals("系统设置", settings.getText());
|
||||||
|
assertEquals("系统设置", settings.getAccessibleText());
|
||||||
|
assertNull(settings.getTooltip());
|
||||||
assertEquals("收起", collapse.getText());
|
assertEquals("收起", collapse.getText());
|
||||||
assertEquals("收起导航栏", collapse.getAccessibleText());
|
assertEquals("收起导航栏", collapse.getAccessibleText());
|
||||||
assertTrue(collapse.isFocusTraversable());
|
assertTrue(collapse.isFocusTraversable());
|
||||||
@@ -169,6 +171,9 @@ class NavigationRailTest {
|
|||||||
collapse.fire();
|
collapse.fire();
|
||||||
|
|
||||||
assertFalse(rail.isExpanded());
|
assertFalse(rail.isExpanded());
|
||||||
|
assertNull(settings.getText());
|
||||||
|
assertEquals("系统设置", settings.getAccessibleText());
|
||||||
|
assertEquals("系统设置", settings.getTooltip().getText());
|
||||||
assertNull(collapse.getText());
|
assertNull(collapse.getText());
|
||||||
assertEquals("展开导航栏", collapse.getAccessibleText());
|
assertEquals("展开导航栏", collapse.getAccessibleText());
|
||||||
assertEquals("展开导航栏", collapse.getTooltip().getText());
|
assertEquals("展开导航栏", collapse.getTooltip().getText());
|
||||||
@@ -212,26 +217,23 @@ class NavigationRailTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void headerMenuAndBottomCollapseEntryDriveTheSameExpandedState() throws Exception {
|
void headerDoesNotDuplicateTheBottomCollapseEntry() throws Exception {
|
||||||
fx(() -> {
|
fx(() -> {
|
||||||
MainWindow window = new MainWindow(List.of(API_DOC), new WorkUtilsProperties(), () -> {
|
MainWindow window = new MainWindow(List.of(API_DOC), new WorkUtilsProperties(), () -> {
|
||||||
});
|
});
|
||||||
Parent root = stage(window).getScene().getRoot();
|
Parent root = stage(window).getScene().getRoot();
|
||||||
NavigationRail rail = assertInstanceOf(
|
NavigationRail rail = assertInstanceOf(
|
||||||
NavigationRail.class, root.lookup(".navigation-rail"));
|
NavigationRail.class, root.lookup(".navigation-rail"));
|
||||||
Button menu = assertInstanceOf(Button.class, root.lookup("#menu-button"));
|
|
||||||
Button collapse = assertInstanceOf(
|
Button collapse = assertInstanceOf(
|
||||||
Button.class, root.lookup("#navigation-rail-toggle"));
|
Button.class, root.lookup("#navigation-rail-toggle"));
|
||||||
|
|
||||||
menu.fire();
|
assertNull(root.lookup("#menu-button"));
|
||||||
|
assertEquals(1, root.lookupAll("#navigation-rail-toggle").size());
|
||||||
assertFalse(rail.isExpanded());
|
|
||||||
assertEquals("展开导航栏", collapse.getAccessibleText());
|
|
||||||
|
|
||||||
collapse.fire();
|
collapse.fire();
|
||||||
|
|
||||||
assertTrue(rail.isExpanded());
|
assertFalse(rail.isExpanded());
|
||||||
assertEquals("收起导航栏", collapse.getAccessibleText());
|
assertEquals("展开导航栏", collapse.getAccessibleText());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,8 +258,8 @@ class NavigationRailTest {
|
|||||||
Parent root = stage(window).getScene().getRoot();
|
Parent root = stage(window).getScene().getRoot();
|
||||||
ToggleButton pluginButton = assertInstanceOf(
|
ToggleButton pluginButton = assertInstanceOf(
|
||||||
ToggleButton.class, root.lookup("#nav-api-doc"));
|
ToggleButton.class, root.lookup("#nav-api-doc"));
|
||||||
Button settingsButton = assertInstanceOf(
|
ToggleButton settingsButton = assertInstanceOf(
|
||||||
Button.class, root.lookup("#settings-button"));
|
ToggleButton.class, root.lookup("#navigation-rail-settings"));
|
||||||
NavigationRail rail = assertInstanceOf(
|
NavigationRail rail = assertInstanceOf(
|
||||||
NavigationRail.class, root.lookup(".navigation-rail"));
|
NavigationRail.class, root.lookup(".navigation-rail"));
|
||||||
|
|
||||||
@@ -269,11 +271,13 @@ class NavigationRailTest {
|
|||||||
assertEquals("系统设置", toolbarTitle(window).getText());
|
assertEquals("系统设置", toolbarTitle(window).getText());
|
||||||
assertNull(rail.selectedPluginId());
|
assertNull(rail.selectedPluginId());
|
||||||
assertFalse(pluginButton.isSelected());
|
assertFalse(pluginButton.isSelected());
|
||||||
|
assertTrue(settingsButton.isSelected());
|
||||||
|
|
||||||
pluginButton.fire();
|
pluginButton.fire();
|
||||||
|
|
||||||
assertEquals(2, pluginOpens.get());
|
assertEquals(2, pluginOpens.get());
|
||||||
assertEquals("API", toolbarTitle(window).getText());
|
assertEquals("API", toolbarTitle(window).getText());
|
||||||
|
assertFalse(settingsButton.isSelected());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,7 +386,7 @@ class NavigationRailTest {
|
|||||||
|
|
||||||
assertNull(oldButton.getToggleGroup());
|
assertNull(oldButton.getToggleGroup());
|
||||||
assertNull(oldButton.getOnAction());
|
assertNull(oldButton.getOnAction());
|
||||||
assertEquals(1, newButton.getToggleGroup().getToggles().size());
|
assertEquals(2, newButton.getToggleGroup().getToggles().size());
|
||||||
oldButton.fire();
|
oldButton.fire();
|
||||||
assertEquals(1, routed.get());
|
assertEquals(1, routed.get());
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user