diff --git a/src/main/java/staffconnect/commons/core/GuiSettings.java b/src/main/java/staffconnect/commons/core/GuiSettings.java index eac9468c742..39eb4c532b2 100644 --- a/src/main/java/staffconnect/commons/core/GuiSettings.java +++ b/src/main/java/staffconnect/commons/core/GuiSettings.java @@ -12,8 +12,8 @@ */ public class GuiSettings implements Serializable { - private static final double DEFAULT_HEIGHT = 600; - private static final double DEFAULT_WIDTH = 740; + private static final double DEFAULT_HEIGHT = 700; + private static final double DEFAULT_WIDTH = 840; private final double windowWidth; private final double windowHeight; diff --git a/src/main/java/staffconnect/logic/Logic.java b/src/main/java/staffconnect/logic/Logic.java index 86e0c5a8d8e..1dcad6cc655 100644 --- a/src/main/java/staffconnect/logic/Logic.java +++ b/src/main/java/staffconnect/logic/Logic.java @@ -1,6 +1,7 @@ package staffconnect.logic; import java.nio.file.Path; +import java.util.Optional; import javafx.collections.ObservableList; import staffconnect.commons.core.GuiSettings; @@ -33,6 +34,9 @@ public interface Logic { /** Returns an unmodifiable view of the filtered list of persons */ ObservableList getFilteredPersonList(); + /** Returns the first person if it exists. */ + Optional getFirstPersonIfExist(); + /** * Returns the user prefs' StaffConnect file path. */ diff --git a/src/main/java/staffconnect/logic/LogicManager.java b/src/main/java/staffconnect/logic/LogicManager.java index b168b9cdea6..c9f73efcd48 100644 --- a/src/main/java/staffconnect/logic/LogicManager.java +++ b/src/main/java/staffconnect/logic/LogicManager.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.nio.file.AccessDeniedException; import java.nio.file.Path; +import java.util.Optional; import java.util.logging.Logger; import javafx.collections.ObservableList; @@ -71,6 +72,13 @@ public ObservableList getFilteredPersonList() { return model.getSortedFilteredPersonList(); } + @Override + public Optional getFirstPersonIfExist() { + + return model.getSortedFilteredPersonList().isEmpty() + ? Optional.empty() : Optional.of(model.getSortedFilteredPersonList().get(0)); + } + @Override public Path getStaffConnectFilePath() { return model.getStaffConnectFilePath(); diff --git a/src/main/java/staffconnect/ui/MainWindow.java b/src/main/java/staffconnect/ui/MainWindow.java index 24f15192d48..f7ca4ffc5a5 100644 --- a/src/main/java/staffconnect/ui/MainWindow.java +++ b/src/main/java/staffconnect/ui/MainWindow.java @@ -2,12 +2,7 @@ import java.util.logging.Logger; -import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.control.MenuItem; -import javafx.scene.control.TextInputControl; -import javafx.scene.input.KeyCombination; -import javafx.scene.input.KeyEvent; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import staffconnect.commons.core.GuiSettings; @@ -35,11 +30,10 @@ public class MainWindow extends UiPart { private ResultDisplay resultDisplay; private HelpWindow helpWindow; - @FXML - private StackPane commandBoxPlaceholder; + private PersonCard personOnDisplay; @FXML - private MenuItem helpMenuItem; + private StackPane commandBoxPlaceholder; @FXML private StackPane personListPanelPlaceholder; @@ -50,6 +44,9 @@ public class MainWindow extends UiPart { @FXML private StackPane statusbarPlaceholder; + @FXML + private StackPane personCardPanelPlaceholder; + /** * Creates a {@code MainWindow} with the given {@code Stage} and {@code Logic}. */ @@ -63,108 +60,59 @@ public MainWindow(Stage primaryStage, Logic logic) { // Configure the UI setWindowDefaultSize(logic.getGuiSettings()); - setAccelerators(); + personOnDisplay = logic.getFirstPersonIfExist() + .map(PersonCard::new).orElse(new PersonCard()); helpWindow = new HelpWindow(); } - public Stage getPrimaryStage() { - return primaryStage; - } - - private void setAccelerators() { - setAccelerator(helpMenuItem, KeyCombination.valueOf("F1")); - } - /** - * Sets the accelerator of a MenuItem. - * @param keyCombination the KeyCombination value of the accelerator + * Sets the default size based on {@code guiSettings}. */ - private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) { - menuItem.setAccelerator(keyCombination); - - /* - * TODO: the code below can be removed once the bug reported here - * https://bugs.openjdk.java.net/browse/JDK-8131666 - * is fixed in later version of SDK. - * - * According to the bug report, TextInputControl (TextField, TextArea) will - * consume function-key events. Because CommandBox contains a TextField, and - * ResultDisplay contains a TextArea, thus some accelerators (e.g F1) will - * not work when the focus is in them because the key event is consumed by - * the TextInputControl(s). - * - * For now, we add following event filter to capture such key events and open - * help window purposely so to support accelerators even when focus is - * in CommandBox or ResultDisplay. - */ - getRoot().addEventFilter(KeyEvent.KEY_PRESSED, event -> { - if (event.getTarget() instanceof TextInputControl && keyCombination.match(event)) { - menuItem.getOnAction().handle(new ActionEvent()); - event.consume(); - } - }); + private void setWindowDefaultSize(GuiSettings guiSettings) { + primaryStage.setHeight(guiSettings.getWindowHeight()); + primaryStage.setWidth(guiSettings.getWindowWidth()); + if (guiSettings.getWindowCoordinates() != null) { + primaryStage.setX(guiSettings.getWindowCoordinates().getX()); + primaryStage.setY(guiSettings.getWindowCoordinates().getY()); + } + } + + public Stage getPrimaryStage() { + return primaryStage; } /** * Fills up all the placeholders of this window. */ void fillInnerParts() { - personListPanel = new PersonListPanel(logic.getFilteredPersonList()); + + personListPanel = new PersonListPanel(logic.getFilteredPersonList(), this::changePersonCard); + personListPanel.setListSelectedIndex(0); personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); resultDisplay = new ResultDisplay(); resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot()); - StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getStaffConnectFilePath()); - statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot()); - CommandBox commandBox = new CommandBox(this::executeCommand); commandBoxPlaceholder.getChildren().add(commandBox.getRoot()); - } - /** - * Sets the default size based on {@code guiSettings}. - */ - private void setWindowDefaultSize(GuiSettings guiSettings) { - primaryStage.setHeight(guiSettings.getWindowHeight()); - primaryStage.setWidth(guiSettings.getWindowWidth()); - if (guiSettings.getWindowCoordinates() != null) { - primaryStage.setX(guiSettings.getWindowCoordinates().getX()); - primaryStage.setY(guiSettings.getWindowCoordinates().getY()); - } - } + StatusBarFooter statusBarFooter = + new StatusBarFooter(logic.getStaffConnectFilePath(), this::handleExit, this::handleHelp); + statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot()); + + personCardPanelPlaceholder.getChildren().add(personOnDisplay.getRoot()); - /** - * Opens the help window or focuses on it if it's already opened. - */ - @FXML - public void handleHelp() { - if (!helpWindow.isShowing()) { - helpWindow.show(); - } else { - helpWindow.focus(); - } - } - void show() { - primaryStage.show(); - } - /** - * Closes the application. - */ - @FXML - private void handleExit() { - GuiSettings guiSettings = new GuiSettings(primaryStage.getWidth(), primaryStage.getHeight(), - (int) primaryStage.getX(), (int) primaryStage.getY()); - logic.setGuiSettings(guiSettings); - helpWindow.hide(); - primaryStage.hide(); } - public PersonListPanel getPersonListPanel() { - return personListPanel; + private void changePersonCard(PersonCard personToUpdate) { + + personOnDisplay = personToUpdate; + personCardPanelPlaceholder.getChildren().clear(); + personCardPanelPlaceholder.getChildren().add(personOnDisplay.getRoot()); + } /** @@ -178,6 +126,8 @@ private CommandResult executeCommand(String commandText) throws CommandException logger.info("Result: " + commandResult.getFeedbackToUser()); resultDisplay.setFeedbackToUser(commandResult.getFeedbackToUser()); + reloadPersonCardWithRoot(); + if (commandResult.isShowHelp()) { handleHelp(); } @@ -193,4 +143,42 @@ private CommandResult executeCommand(String commandText) throws CommandException throw e; } } + + /** + * Closes the application. + */ + @FXML + public void handleExit() { + GuiSettings guiSettings = new GuiSettings(primaryStage.getWidth(), primaryStage.getHeight(), + (int) primaryStage.getX(), (int) primaryStage.getY()); + logic.setGuiSettings(guiSettings); + helpWindow.hide(); + primaryStage.hide(); + } + + /** + * Opens the help window or focuses on it if it's already opened. + */ + public void handleHelp() { + if (!helpWindow.isShowing()) { + helpWindow.show(); + } else { + helpWindow.focus(); + } + } + + private void reloadPersonCardWithRoot() { + + personOnDisplay = logic.getFirstPersonIfExist().map(PersonCard::new).orElse(new PersonCard()); + + personCardPanelPlaceholder.getChildren().clear(); + personCardPanelPlaceholder.getChildren().add(personOnDisplay.getRoot()); + + personListPanel.setListSelectedIndex(0); + + } + + void show() { + primaryStage.show(); + } } diff --git a/src/main/java/staffconnect/ui/NameCard.java b/src/main/java/staffconnect/ui/NameCard.java new file mode 100644 index 00000000000..14ff11e97a7 --- /dev/null +++ b/src/main/java/staffconnect/ui/NameCard.java @@ -0,0 +1,33 @@ +package staffconnect.ui; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.Region; +import staffconnect.model.person.Person; + +/** + * A UI component that displays the name only of a {@code Person}. + */ +public class NameCard extends UiPart { + + private static final String FXML = "NameCard.fxml"; + @javafx.fxml.FXML + private Label id; + @FXML + private Label name; + + @FXML + private Label favourite; + + /** + * Creates a {@code NameCard} with the given {@code Person} and index to display. + */ + public NameCard(Person person, int index) { + super(FXML); + id.setText(index + ". "); + name.setText(person.getName().fullName); + favourite.setStyle("-fx-text-fill: accent-orange"); + favourite.setText(person.getFavourite().toDisplayString() + " "); + } + +} diff --git a/src/main/java/staffconnect/ui/PersonCard.java b/src/main/java/staffconnect/ui/PersonCard.java index 9c6bbf563c5..e1d77d99332 100644 --- a/src/main/java/staffconnect/ui/PersonCard.java +++ b/src/main/java/staffconnect/ui/PersonCard.java @@ -1,15 +1,24 @@ package staffconnect.ui; import java.util.Comparator; +import java.util.List; import javafx.collections.ObservableList; import javafx.fxml.FXML; +import javafx.geometry.Orientation; import javafx.scene.control.Label; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; +import javafx.scene.control.ScrollBar; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.SplitPane; import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; +import javafx.scene.text.TextAlignment; import staffconnect.model.meeting.Meeting; import staffconnect.model.person.Person; @@ -19,8 +28,10 @@ public class PersonCard extends UiPart { private static final String FXML = "PersonListCard.fxml"; - private static final int ROW_HEIGHT = 33; //row height of each meeting + private static final int ROW_HEIGHT = 60; //row height of each meeting + + private static final int LABEL_MEETING_WIDTH = 10; //the width of the meeting label /** * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX. * As a consequence, UI elements' variable names cannot be set to such keywords @@ -30,13 +41,10 @@ public class PersonCard extends UiPart { */ public final Person person; - @FXML private HBox cardPane; @FXML - private Label name; - @FXML - private Label id; + private Text name; @FXML private Label phone; @FXML @@ -53,24 +61,52 @@ public class PersonCard extends UiPart { private FlowPane availabilities; @FXML private ListView meetingListView; + + @FXML + private VBox displayMeetings; + @FXML - private Label favourite; + private SplitPane splitDisplay; + @FXML + private VBox displayPane; + + @FXML + private VBox detailsCard; /** - * Creates a {@code PersonCode} with the given {@code Person} and index to display. + * Creates a {@code PersonCard} with an empty card that displays nothing. */ - public PersonCard(Person person, int displayedIndex) { + public PersonCard() { + super(FXML); + this.person = null; + + name.setText(""); + phone.setText(""); + faculty.setText(""); + venue.setText(""); + module.setText(""); + email.setText(""); + + meetingListView.setCellFactory(listView -> new MeetingsListViewCell()); + + } + + /** + * Creates a {@code PersonCard} with the given {@code Person} and index to display. + */ + public PersonCard(Person person) { super(FXML); this.person = person; - id.setText(displayedIndex + ". "); name.setText(person.getName().fullName); + name.setTextAlignment(TextAlignment.JUSTIFY); + name.setWrappingWidth(1000); phone.setText(person.getPhone().value); - faculty.setText(person.getFaculty().toString()); - venue.setText(person.getVenue().value); - module.setText(person.getModule().value); - email.setText(person.getEmail().value); + faculty.setText("Faculty: " + person.getFaculty().toString()); + venue.setText("Venue: " + person.getVenue().value); + module.setText("Module: " + person.getModule().value); + email.setText("Email: " + person.getEmail().value); person.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) @@ -82,20 +118,91 @@ public PersonCard(Person person, int displayedIndex) { ObservableList meetingsList = person.getFilteredMeetings(); - //This is probably only feasible workaround for now without messing or revamping UI. - //To set the correct height - meetingListView.setPrefHeight((meetingsList.size() * ROW_HEIGHT) + 10); + setUpMeetingListView(meetingsList); + + setUpScrollPane(displayPane, detailsCard, false, false, new Region()); + + setUpScrollPane(displayMeetings, meetingListView, true, true, displayMeetings); + + } + + private void setUpMeetingListView(ObservableList meetingsList) { + + meetingListView.setFocusTraversable(false); meetingListView.setItems(meetingsList); meetingListView.setCellFactory(listView -> new MeetingsListViewCell()); + //Work around to set the correct height and width of the nested list view. + meetingListView.setPrefHeight((meetingsList.size() * ROW_HEIGHT) + 100); + meetingListView.setPrefWidth(getLongestWidth(meetingsList)); + meetingListView.setFocusTraversable(false); + meetingListView.setMouseTransparent(true); + } + + private double getLongestWidth(List meetingList) { + double maxWidth = 0; + for (Meeting meet : meetingList) { + + //200 is to account for the default spacing within the items + double currentWidth = (meet.getDescription().description.length() + meet.getStartDate().toString().length()) + * LABEL_MEETING_WIDTH + 200; + + if (currentWidth > maxWidth) { + maxWidth = currentWidth; + } + } + return maxWidth; + } - favourite.setText(person.getFavourite().toDisplayString()); + private void setUpScrollPane(VBox display, Region content, boolean enableHbar, boolean swap, Region swapRegion) { + ScrollPane scrollPane = new ScrollPane(); + scrollPane.setContent(content); + //Custom vertical scroll bar on the left + // Inspired from: + // https://stackoverflow.com/questions/35134155/move-the-vertical-scroll-bar-of-a-scroll-panel-to-the-left-side + ScrollBar vScrollBar = new ScrollBar(); + vScrollBar.setPrefWidth(1); + vScrollBar.setOrientation(Orientation.VERTICAL); + vScrollBar.minProperty().bind(scrollPane.vminProperty()); + vScrollBar.maxProperty().bind(scrollPane.vmaxProperty()); + if (swap) { + vScrollBar.visibleAmountProperty().bind(scrollPane.heightProperty().divide(swapRegion.heightProperty())); + } else { + vScrollBar.visibleAmountProperty().bind(scrollPane.heightProperty().divide(content.heightProperty())); + } + scrollPane.vvalueProperty().bindBidirectional(vScrollBar.valueProperty()); + + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + HBox hBox = new HBox(); + HBox.setHgrow(scrollPane, Priority.ALWAYS); + hBox.getChildren().addAll(vScrollBar, scrollPane); + + VBox.setVgrow(hBox, Priority.ALWAYS); + + if (enableHbar) { + ScrollBar hScrollBar = new ScrollBar(); + hScrollBar.setOrientation(Orientation.HORIZONTAL); + hScrollBar.minProperty().bind(scrollPane.hminProperty()); + hScrollBar.maxProperty().bind(scrollPane.hmaxProperty()); + if (swap) { + hScrollBar.visibleAmountProperty().bind(scrollPane.widthProperty().divide(swapRegion.widthProperty())); + } else { + hScrollBar.visibleAmountProperty().bind(scrollPane.widthProperty().divide(content.widthProperty())); + } + scrollPane.hvalueProperty().bindBidirectional(hScrollBar.valueProperty()); + + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + display.getChildren().addAll(hScrollBar, hBox); + } else { + display.getChildren().add(hBox); + } } /** * Custom {@code ListCell} that displays the graphics of a {@code Meetings} using a {@code MeetingsCard}. */ private static class MeetingsListViewCell extends ListCell { + @Override protected void updateItem(Meeting meeting, boolean empty) { super.updateItem(meeting, empty); diff --git a/src/main/java/staffconnect/ui/PersonListPanel.java b/src/main/java/staffconnect/ui/PersonListPanel.java index c79753fb61b..fa751fd33ee 100644 --- a/src/main/java/staffconnect/ui/PersonListPanel.java +++ b/src/main/java/staffconnect/ui/PersonListPanel.java @@ -6,6 +6,7 @@ import javafx.fxml.FXML; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; +import javafx.scene.input.KeyCode; import javafx.scene.layout.Region; import staffconnect.commons.core.LogsCenter; import staffconnect.model.person.Person; @@ -23,16 +24,49 @@ public class PersonListPanel extends UiPart { /** * Creates a {@code PersonListPanel} with the given {@code ObservableList}. */ - public PersonListPanel(ObservableList personList) { + public PersonListPanel(ObservableList personList, PersonDisplay personDisplay) { super(FXML); personListView.setItems(personList); - personListView.setCellFactory(listView -> new PersonListViewCell()); + personListView.setCellFactory(listView -> new NameListViewCell()); + personListView.setOnKeyPressed(event -> { + if (event.getCode() == KeyCode.ENTER) { + personDisplay.changePersonCard(new PersonCard(personListView.getSelectionModel().getSelectedItem())); + } + }); + personListView.setOnMouseClicked(event -> { + personDisplay.changePersonCard(new PersonCard(personListView.getSelectionModel().getSelectedItem())); + }); + } + + /** + * Changes the current highlighted selection item in the personListPanel. + * Only for internal use by the UI. + * @param index to change the selection to. + */ + public void setListSelectedIndex(int index) { + // guard clause to prevent invalid index + if (index >= 0 && index < personListView.getItems().size()) { + personListView.getSelectionModel().clearAndSelect(index); + } + } /** - * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}. + * Represents a function that can change PersonCard. */ - class PersonListViewCell extends ListCell { + @FunctionalInterface + public interface PersonDisplay { + + /** + * Executes the changes to the person + */ + void changePersonCard(PersonCard toChange); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code NameCard}. + */ + class NameListViewCell extends ListCell { @Override protected void updateItem(Person person, boolean empty) { super.updateItem(person, empty); @@ -41,9 +75,10 @@ protected void updateItem(Person person, boolean empty) { setGraphic(null); setText(null); } else { - setGraphic(new PersonCard(person, getIndex() + 1).getRoot()); + setGraphic(new NameCard(person, getIndex() + 1).getRoot()); } } } + } diff --git a/src/main/java/staffconnect/ui/ResultDisplay.java b/src/main/java/staffconnect/ui/ResultDisplay.java index 8124ee47dee..d0b108f54fc 100644 --- a/src/main/java/staffconnect/ui/ResultDisplay.java +++ b/src/main/java/staffconnect/ui/ResultDisplay.java @@ -7,7 +7,7 @@ import javafx.scene.layout.Region; /** - * A ui for the status bar that is displayed at the header of the application. + * A ui for the status bar that is displayed at the footer of the application. */ public class ResultDisplay extends UiPart { @@ -16,8 +16,12 @@ public class ResultDisplay extends UiPart { @FXML private TextArea resultDisplay; + /** + * Creates a result display for displaying text. + */ public ResultDisplay() { super(FXML); + } public void setFeedbackToUser(String feedbackToUser) { diff --git a/src/main/java/staffconnect/ui/StatusBarFooter.java b/src/main/java/staffconnect/ui/StatusBarFooter.java index b4caecd065e..0763c8c3fd0 100644 --- a/src/main/java/staffconnect/ui/StatusBarFooter.java +++ b/src/main/java/staffconnect/ui/StatusBarFooter.java @@ -3,8 +3,13 @@ import java.nio.file.Path; import java.nio.file.Paths; +import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; +import javafx.scene.control.TextInputControl; +import javafx.scene.input.KeyCombination; +import javafx.scene.input.KeyEvent; import javafx.scene.layout.Region; /** @@ -14,15 +19,99 @@ public class StatusBarFooter extends UiPart { private static final String FXML = "StatusBarFooter.fxml"; + + private ExitExecutor exitExecutor; + + private HelpExecutor helpExecutor; + + @FXML + private MenuItem helpMenuItem; + @FXML private Label saveLocationStatus; /** * Creates a {@code StatusBarFooter} with the given {@code Path}. */ - public StatusBarFooter(Path saveLocation) { + public StatusBarFooter(Path saveLocation, ExitExecutor exitExecutor, HelpExecutor helpExecutor) { + super(FXML); + + this.exitExecutor = exitExecutor; + this.helpExecutor = helpExecutor; + saveLocationStatus.setText(Paths.get(".").resolve(saveLocation).toString()); + + setAccelerators(); + } + + private void setAccelerators() { + setAccelerator(helpMenuItem, KeyCombination.valueOf("F1")); + } + + /** + * Sets the accelerator of a MenuItem. + * + * @param keyCombination the KeyCombination value of the accelerator + */ + private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) { + menuItem.setAccelerator(keyCombination); + + /* + * TODO: the code below can be removed once the bug reported here + * https://bugs.openjdk.java.net/browse/JDK-8131666 + * is fixed in later version of SDK. + * + * According to the bug report, TextInputControl (TextField, TextArea) will + * consume function-key events. Because CommandBox contains a TextField, and + * ResultDisplay contains a TextArea, thus some accelerators (e.g F1) will + * not work when the focus is in them because the key event is consumed by + * the TextInputControl(s). + * + * For now, we add following event filter to capture such key events and open + * help window purposely so to support accelerators even when focus is + * in CommandBox or ResultDisplay. + */ + getRoot().addEventFilter(KeyEvent.KEY_PRESSED, event -> { + if (event.getTarget() instanceof TextInputControl && keyCombination.match(event)) { + menuItem.getOnAction().handle(new ActionEvent()); + event.consume(); + } + }); + } + + @FXML + private void handleExit() { + exitExecutor.handleExit(); + } + + @FXML + private void handleHelp() { + helpExecutor.handleHelp(); + } + + /** + * Represents a function that closes the application. + */ + @FunctionalInterface + public interface ExitExecutor { + + /** + * Exits the application. + */ + void handleExit(); + } + + /** + * Represents a function that shows the help window. + */ + @FunctionalInterface + public interface HelpExecutor { + + /** + * Shows the help window. + */ + void handleHelp(); } } diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 5c895d7f56f..b6e9472c760 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -1,12 +1,27 @@ +.root { + background-blue: #8489B6; + accent-blue: #404A72; + dark-accent-blue: derive(#404A72, -10%); + very-dark-accent-black: derive(#404A72, -85%); + accent-yellow: #F8E9D1; + accent-orange: #F18D1D; + accent-light-blue:#CCDFEF; + panel-background-blue: derive(#8489B6,-5%); + blue-dropshadow: rgba(64,75,115,0.8); + yellow-dropshadow: rgba(249,234,210,0.4); + lightblue-dropshadow: rgba(205,223,239,0.4); + orange-dropshadow: rgba(241,142,29,0.4); +} + .background { - -fx-background-color: derive(#1d1d1d, 20%); - background-color: #383838; /* Used in the default.html file */ + -fx-background-color: dark-accent-blue; + background-color: dark-accent-blue; /* Used in the default.html file */ } .label { -fx-font-size: 11pt; -fx-font-family: "Segoe UI Semibold"; - -fx-text-fill: #555555; + -fx-text-fill: white; -fx-opacity: 0.9; } @@ -40,9 +55,9 @@ } .table-view { - -fx-base: #1d1d1d; - -fx-control-inner-background: #1d1d1d; - -fx-background-color: #1d1d1d; + -fx-base: background-blue; + -fx-control-inner-background: background-blue; + -fx-background-color: background-blue; -fx-table-cell-border-color: transparent; -fx-table-header-border-color: transparent; -fx-padding: 5; @@ -77,20 +92,26 @@ } .split-pane:horizontal .split-pane-divider { - -fx-background-color: derive(#1d1d1d, 20%); - -fx-border-color: transparent transparent transparent #4d4d4d; + -fx-background-color: transparent; + -fx-border-color: transparent transparent transparent transparent; + -fx-padding: 0 0 0 0; +} + +.split-pane:vertical .split-pane-divider { + -fx-background-color: background-blue; + -fx-border-color: background-blue; } .split-pane { - -fx-border-radius: 1; - -fx-border-width: 1; - -fx-background-color: derive(#1d1d1d, 20%); + fx-border-radius: 10; + -fx-background-color: panel-background-blue; } .list-view { -fx-background-insets: 0; -fx-padding: 0; - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: panel-background-blue; + -fx-background-radius: 10 0 0 10; } .list-cell { @@ -100,50 +121,54 @@ } .list-cell:filled:even { - -fx-background-color: #3c3e3f; + -fx-background-color: transparent; } .list-cell:filled:odd { - -fx-background-color: #515658; + -fx-background-color: transparent; } .list-cell:filled:selected { - -fx-background-color: #424d5f; + -fx-background-color: accent-blue; + -fx-background-radius: 20 20 20 20; + -fx-effect: dropshadow(gaussian, blue-dropshadow, 13, 0, 0, 0); } .list-cell:filled:selected #cardPane { - -fx-border-color: #3e7b91; + -fx-border-color: dark-accent-blue; -fx-border-width: 1; } -.list-cell .label { - -fx-text-fill: white; -} - .cell_big_label { -fx-font-family: "Segoe UI Semibold"; -fx-font-size: 16px; - -fx-text-fill: #010504; + -fx-text-fill: accent-yellow; } .cell_small_label { -fx-font-family: "Segoe UI"; -fx-font-size: 13px; - -fx-text-fill: #010504; + -fx-text-fill: accent-yellow; } .stack-pane { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: background-blue; } -.pane-with-border { - -fx-background-color: derive(#1d1d1d, 20%); - -fx-border-color: derive(#1d1d1d, 10%); - -fx-border-top-width: 1px; +.pane-without-border { + -fx-background-color: background-blue; +} +.pane-result { + -fx-background-color: background-blue; + -fx-padding: 0 15 0 15; +} +.pane-command { + -fx-background-color: background-blue; + -fx-padding: 0 15 10 15; } .status-bar { - -fx-background-color: derive(#1d1d1d, 30%); + -fx-background-color: very-dark-accent-black; } .result-display { @@ -154,7 +179,7 @@ } .result-display .label { - -fx-text-fill: black !important; + -fx-text-fill: background-blue !important; } .status-bar .label { @@ -165,8 +190,8 @@ } .status-bar-with-border { - -fx-background-color: derive(#1d1d1d, 30%); - -fx-border-color: derive(#1d1d1d, 25%); + -fx-background-color: background-blue; + -fx-border-color: background-blue; -fx-border-width: 1px; } @@ -175,36 +200,65 @@ } .grid-pane { - -fx-background-color: derive(#1d1d1d, 30%); - -fx-border-color: derive(#1d1d1d, 30%); + -fx-background-color: background-blue; + -fx-border-color: background-blue; -fx-border-width: 1px; } .grid-pane .stack-pane { - -fx-background-color: derive(#1d1d1d, 30%); + -fx-background-color: background-blue; } .context-menu { - -fx-background-color: derive(#1d1d1d, 50%); + -fx-background-color: derive(background-blue,-20%); + -fx-padding: 0 1 0 1; + } .context-menu .label { - -fx-text-fill: white; + -fx-text-fill: accent-yellow; } .menu-bar { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: very-dark-accent-black; + -fx-spacing: 1; + +} +.menu { + -fx-padding: 0 5 0 5; +} +.menu:showing { + -fx-background-color: accent-blue; + -fx-focus-color:accent-blue; +} + +.menu:focused { + -fx-background-color: accent-blue; + -fx-focus-color:accent-blue; +} + +.menu:hover { + -fx-background-color: accent-blue; + -fx-focus-color:accent-blue; } .menu-bar .label { - -fx-font-size: 14pt; + -fx-font-size: 12pt; -fx-font-family: "Segoe UI Light"; -fx-text-fill: white; -fx-opacity: 0.9; } .menu .left-container { - -fx-background-color: black; + -fx-background-color: very-dark-accent-black; +} + +.menu-item{ + -fx-padding: 0 5 0 5; +} +.menu-item:focused { + -fx-background-color: accent-blue; + -fx-text-fill:accent-yellow; } /* @@ -214,18 +268,18 @@ */ .button { -fx-padding: 5 22 5 22; - -fx-border-color: #e2e2e2; + -fx-border-color: transparent; -fx-border-width: 2; -fx-background-radius: 0; - -fx-background-color: #1d1d1d; + -fx-background-color: accent-blue; -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif; - -fx-font-size: 11pt; - -fx-text-fill: #d8d8d8; + -fx-font-size: 10pt; + -fx-text-fill: accent-yellow; -fx-background-insets: 0 0 0 0, 0, 1, 2; } .button:hover { - -fx-background-color: #3a3a3a; + -fx-background-color: dark-accent-blue; } .button:pressed, .button:default:hover:pressed { @@ -248,12 +302,12 @@ } .button:default { - -fx-background-color: -fx-focus-color; + -fx-background-color: very-dark-accent-black; -fx-text-fill: #ffffff; } .button:default:hover { - -fx-background-color: derive(-fx-focus-color, 30%); + -fx-background-color: very-dark-accent-black; } .dialog-pane { @@ -282,12 +336,37 @@ } .scroll-bar { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: transparent; + -fx-background-padding: 0 0 0 0; } .scroll-bar .thumb { - -fx-background-color: derive(#1d1d1d, 50%); - -fx-background-insets: 3; + -fx-background-color: accent-yellow; + -fx-background-insets: 3 0 3 3; +} + +#displayPane .scroll-bar:vertical > .thumb { + -fx-background-color: accent-yellow; + -fx-background-insets: 3 7 3 0; +} + +#displayMeetings .scroll-bar:vertical > .thumb { + -fx-background-color: accent-yellow; + -fx-background-insets: 0 7 0 0; +} +#displayMeetings .scroll-bar:vertical > .track { + -fx-background-color : transparent; + -fx-background-insets: 0 10 0 0; +} + +#displayPane .scroll-bar:horizontal > .thumb { + -fx-background-color: accent-yellow; + -fx-background-insets: 10 3 0 3; +} + +#displayMeetings .scroll-bar:horizontal > .thumb { + -fx-background-color: accent-yellow; + -fx-background-insets: 0 3 10 3; } .scroll-bar .increment-button, .scroll-bar .decrement-button { @@ -306,10 +385,23 @@ .scroll-bar:horizontal .increment-arrow, .scroll-bar:horizontal .decrement-arrow { -fx-padding: 8 1 8 1; } +.scroll-bar:horizontal .thumb { -#cardPane { + -fx-background-insets: 7 3 0 3; +} + +.scroll-pane > .corner { + -fx-background-color: transparent; +} + +.virtual-flow > .corner { -fx-background-color: transparent; +} + +#cardPane { + -fx-background-color: panel-background-blue; -fx-border-width: 0; + -fx-background-radius: 0 10 10 0; } #commandTypeLabel { @@ -318,22 +410,22 @@ } #commandTextField { - -fx-background-color: transparent #383838 transparent #383838; + -fx-background-color: transparent background-blue transparent background-blue; -fx-background-insets: 0; - -fx-border-color: #383838 #383838 #ffffff #383838; + -fx-border-color: transparent transparent accent-yellow transparent; -fx-border-insets: 0; - -fx-border-width: 1; + -fx-border-width: 3; -fx-font-family: "Segoe UI Light"; - -fx-font-size: 13pt; - -fx-text-fill: white; + -fx-font-size: 17pt; + -fx-text-fill: accent-yellow; } #filterField, #personListPanel, #personWebpage { - -fx-effect: innershadow(gaussian, black, 10, 0, 0, 0); + -fx-effect: innershadow(gaussian, background-blue, 10, 0, 0, 0); } #resultDisplay .content { - -fx-background-color: transparent, #383838, transparent, #383838; + -fx-background-color: transparent, background-blue, transparent, background-blue; -fx-background-radius: 0; } @@ -343,12 +435,13 @@ } #tags .label { - -fx-text-fill: white; - -fx-background-color: #3e7b91; + -fx-text-fill: accent-yellow; + -fx-background-color: accent-orange; -fx-padding: 1 3 1 3; -fx-border-radius: 2; -fx-background-radius: 2; - -fx-font-size: 11; + -fx-font-size: 20; + -fx-effect: dropshadow(gaussian, orange-dropshadow, 13, 0, 0, 0); } #availabilities { @@ -357,35 +450,89 @@ } #availabilities .label { - -fx-text-fill: white; - -fx-background-color: #B57EDC; + -fx-text-fill: accent-blue; + -fx-background-color: accent-light-blue; -fx-padding: 1 3 1 3; -fx-border-radius: 2; -fx-background-radius: 2; - -fx-font-size: 11; + -fx-font-size: 15; + -fx-font-weight: 300; + -fx-effect: dropshadow(gaussian, lightblue-dropshadow, 13, 0, 0, 0); } #meetingPane{ -fx-border-radius: 20 20 20 20; -fx-background-radius: 20 20 20 20; - -fx-background-color: #3d549d; + -fx-background-color: accent-yellow; -fx-border-width: 0; -fx-background-insets: 0 0 0 0; -fx-background-padding: 50 100 0 0; - -fx-text-fill: white; - -fx-effect: dropshadow(gaussian, rgba(62,84,158,0.8), 13, 0, 0, 0); + -fx-effect: dropshadow(gaussian, yellow-dropshadow, 13, 0, 0, 0); } -#meetingListView { - -fx-background-color: transparent; - -fx-padding: 7 0 0 0; -} + #nameCard{ + -fx-border-radius: 20 20 20 20; + -fx-background-radius: 20 20 20 20; + -fx-background-color: transparent; + -fx-border-width: 0; + -fx-background-insets: 0 0 0 0; + -fx-background-padding: 50 100 0 0; -#meetingListCell { + } + #nameCard .label { + + -fx-font-family: "Segoe UI Semibold"; + -fx-font-size: 23px; + -fx-text-fill: accent-yellow; + + } + + #meetingListView { -fx-background-color: transparent; -fx-padding: 5 0 0 0; -} + } -#favourite_label { - -fx-text-fill: #FFDF00; -} + #meetingListCell { + -fx-background-color: transparent; + -fx-padding: 20 15 0 15; + } + + .cell_meeting_label { + -fx-font-family: "Segoe UI"; + -fx-font-size: 20px; + -fx-text-fill: accent-blue; + } + + .cell_title_label { + -fx-font-family: "Segoe UI Semibold"; + -fx-font-size: 70px; + -fx-font-weight: 200; + -fx-fill: accent-yellow; + } + + .cell_details_label { + -fx-font-family: "Segoe UI"; + -fx-font-size: 18px; + -fx-font-weight: 100; + -fx-text-fill: accent-yellow; + } + + #personListView { + -fx-border-color: transparent accent-yellow transparent transparent; + -fx-border-width: 2; + } + +.text-area { + -fx-accent: accent-blue ; + -fx-text-fill: accent-yellow; + } + .text-field { + -fx-accent: accent-blue ; + } + + .scroll-pane > .viewport { + -fx-background-color: transparent; + } + .scroll-pane { + -fx-background-color: transparent; + } diff --git a/src/main/resources/view/Extensions.css b/src/main/resources/view/Extensions.css index bfe82a85964..129dfdc1413 100644 --- a/src/main/resources/view/Extensions.css +++ b/src/main/resources/view/Extensions.css @@ -1,11 +1,11 @@ .error { - -fx-text-fill: #d06651 !important; /* The error class should always override the default text-fill style */ + -fx-text-fill: #EB6137 !important; /* The error class should always override the default text-fill style */ } .list-cell:empty { /* Empty cells will not have alternating colours */ - -fx-background: #383838; + -fx-background: transparent; } .tag-selector { diff --git a/src/main/resources/view/HelpWindow.css b/src/main/resources/view/HelpWindow.css index 17e8a8722cd..41e9ed8d2df 100644 --- a/src/main/resources/view/HelpWindow.css +++ b/src/main/resources/view/HelpWindow.css @@ -1,19 +1,29 @@ +.root { + background-blue: #8489B6; + accent-blue: #404A72; + dark-accent-blue: derive(#404A72, -10%); + accent-yellow: #F8E9D1; + accent-light-blue:#CCDFEF; +} + #copyButton, #helpMessage { - -fx-text-fill: white; + -fx-text-fill: accent-yellow; } #copyButton { - -fx-background-color: dimgray; + -fx-background-color: accent-light-blue; + -fx-text-fill: accent-blue; } #copyButton:hover { - -fx-background-color: gray; + -fx-background-color: accent-blue; + -fx-text-fill: accent-yellow; } #copyButton:armed { - -fx-background-color: darkgray; + -fx-background-color: dark-accent-blue; } #helpMessageContainer { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: background-blue; } diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index bdfd006114b..bc065f98741 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -3,58 +3,51 @@ - - - - + - - - - - - - - - + title="StaffConnect App" minWidth="800" minHeight="650" onCloseRequest="#handleExit"> + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + - - - - - + + - - - - - + + + + + - - - - - - - - - - - + + + + diff --git a/src/main/resources/view/MeetingsListCard.fxml b/src/main/resources/view/MeetingsListCard.fxml index f3a3385741a..1b1a9c3e063 100644 --- a/src/main/resources/view/MeetingsListCard.fxml +++ b/src/main/resources/view/MeetingsListCard.fxml @@ -2,24 +2,19 @@ - - - - - - - - - - - - - + + + + + + + diff --git a/src/main/resources/view/NameCard.fxml b/src/main/resources/view/NameCard.fxml new file mode 100644 index 00000000000..98a0766b7cf --- /dev/null +++ b/src/main/resources/view/NameCard.fxml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml index 16ef7ed3bdf..89286b7a8aa 100644 --- a/src/main/resources/view/PersonListCard.fxml +++ b/src/main/resources/view/PersonListCard.fxml @@ -3,37 +3,26 @@ + - - - - - - - - - - - - - - - - + + + + diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/PersonListPanel.fxml index a1bb6bbace8..ae201a87f65 100644 --- a/src/main/resources/view/PersonListPanel.fxml +++ b/src/main/resources/view/PersonListPanel.fxml @@ -4,5 +4,5 @@ - + diff --git a/src/main/resources/view/ResultDisplay.fxml b/src/main/resources/view/ResultDisplay.fxml index 01b691792a9..98dd647d9f3 100644 --- a/src/main/resources/view/ResultDisplay.fxml +++ b/src/main/resources/view/ResultDisplay.fxml @@ -3,7 +3,7 @@ -