diff --git a/src/main/java/envoy/client/ui/ClearableTextField.java b/src/main/java/envoy/client/ui/ClearableTextField.java index 81b3f86..f19155b 100644 --- a/src/main/java/envoy/client/ui/ClearableTextField.java +++ b/src/main/java/envoy/client/ui/ClearableTextField.java @@ -164,4 +164,11 @@ public class ClearableTextField extends GridPane { * @since Envoy Client v0.1-beta */ public final BooleanProperty editableProperty() { return textField.editableProperty(); } + + /** + * @return whether this {@code ClearableTextField} is editable + * @see javafx.scene.control.TextInputControl#isEditable() + * @since Envoy Client v0.1-beta + */ + public final boolean isEditable() { return textField.isEditable(); } } diff --git a/src/main/java/envoy/client/ui/controller/ChatScene.java b/src/main/java/envoy/client/ui/controller/ChatScene.java index f53a8cb..5eda0f0 100644 --- a/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -16,7 +16,6 @@ import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; import envoy.client.data.Chat; import envoy.client.data.LocalDB; @@ -26,8 +25,9 @@ import envoy.client.net.Client; import envoy.client.net.WriteProxy; import envoy.client.ui.IconUtil; import envoy.client.ui.SceneContext; -import envoy.client.ui.listcell.ContactListCell; -import envoy.client.ui.listcell.MessageListCell; +import envoy.client.ui.listcell.ContactListCellFactory; +import envoy.client.ui.listcell.MessageControl; +import envoy.client.ui.listcell.MessageListCellFactory; import envoy.data.*; import envoy.event.EventBus; import envoy.event.MessageStatusChange; @@ -95,8 +95,8 @@ public final class ChatScene { private void initialize() { // Initialize message and user rendering - messageList.setCellFactory(MessageListCell::new); - userList.setCellFactory(ContactListCell::new); + messageList.setCellFactory(MessageListCellFactory::new); + userList.setCellFactory(ContactListCellFactory::new); settingsButton.setGraphic(new ImageView(IconUtil.load("/icons/settings.png", 16))); @@ -169,8 +169,8 @@ public final class ChatScene { userList.setItems(FXCollections.observableList(localDB.getChats().stream().map(Chat::getRecipient).collect(Collectors.toList()))); contactLabel.setText(localDB.getUser().getName()); - MessageListCell.setUser(localDB.getUser()); - if (!client.isOnline()) updateInfoLabel("You are offline", Color.YELLOW); + MessageControl.setUser(localDB.getUser()); + if (!client.isOnline()) updateInfoLabel("You are offline", "infoLabel-info"); } /** @@ -182,7 +182,6 @@ public final class ChatScene { private void userListClicked() { final Contact user = userList.getSelectionModel().getSelectedItem(); if (user != null && (currentChat == null || !user.equals(currentChat.getRecipient()))) { - logger.log(Level.FINEST, "Loading chat with " + user); // LEON: JFC <===> JAVA FRIED CHICKEN <=/=> Java Foundation Classes @@ -190,6 +189,9 @@ public final class ChatScene { currentChat = localDB.getChat(user.getID()).get(); messageList.setItems(FXCollections.observableList(currentChat.getMessages())); + final var scrollIndex = messageList.getItems().size() - 1; + messageList.scrollTo(scrollIndex); + logger.log(Level.FINEST, "Loading chat with " + user + " at index " + scrollIndex); deleteContactMenuItem.setText("Delete " + user.getName()); // Read the current chat @@ -260,7 +262,7 @@ public final class ChatScene { if (!infoLabel.getText().equals(noMoreMessaging)) // Informing the user that he is a f*cking moron and should use Envoy online // because he ran out of messageIDs to use - updateInfoLabel(noMoreMessaging, Color.RED); + updateInfoLabel(noMoreMessaging, "infoLabel-error"); } } @@ -305,7 +307,7 @@ public final class ChatScene { postButton.setDisable(true); messageTextArea.setDisable(true); messageTextArea.clear(); - updateInfoLabel("You need to go online to send more messages", Color.RED); + updateInfoLabel("You need to go online to send more messages", "infoLabel-error"); return; } final var text = messageTextArea.getText().strip(); @@ -347,13 +349,14 @@ public final class ChatScene { /** * Updates the {@code infoLabel}. * - * @param text the text to use - * @param textfill the color in which to display information + * @param text the text to use + * @param infoLabelID the id the the {@code infoLabel} should have so that it + * can be styled accordingly in CSS * @since Envoy Client v0.1-beta */ - private void updateInfoLabel(String text, Paint textfill) { + private void updateInfoLabel(String text, String infoLabelID) { infoLabel.setText(text); - infoLabel.setTextFill(textfill); + infoLabel.setId(infoLabelID); infoLabel.setVisible(true); } diff --git a/src/main/java/envoy/client/ui/controller/ContactSearchScene.java b/src/main/java/envoy/client/ui/controller/ContactSearchScene.java index a215f44..957a52b 100644 --- a/src/main/java/envoy/client/ui/controller/ContactSearchScene.java +++ b/src/main/java/envoy/client/ui/controller/ContactSearchScene.java @@ -14,7 +14,7 @@ import envoy.client.data.LocalDB; import envoy.client.event.SendEvent; import envoy.client.ui.ClearableTextField; import envoy.client.ui.SceneContext; -import envoy.client.ui.listcell.ContactListCell; +import envoy.client.ui.listcell.ContactListCellFactory; import envoy.data.Contact; import envoy.event.ElementOperation; import envoy.event.EventBus; @@ -58,7 +58,7 @@ public class ContactSearchScene { @FXML private void initialize() { - contactList.setCellFactory(ContactListCell::new); + contactList.setCellFactory(ContactListCellFactory::new); searchBar.setClearButtonListener(e -> { searchBar.getTextField().clear(); contactList.getItems().clear(); }); eventBus.register(ContactSearchResult.class, response -> Platform.runLater(() -> { contactList.getItems().clear(); contactList.getItems().addAll(response.get()); })); diff --git a/src/main/java/envoy/client/ui/controller/GroupCreationScene.java b/src/main/java/envoy/client/ui/controller/GroupCreationScene.java index e6594f5..76573b8 100644 --- a/src/main/java/envoy/client/ui/controller/GroupCreationScene.java +++ b/src/main/java/envoy/client/ui/controller/GroupCreationScene.java @@ -11,7 +11,7 @@ import envoy.client.data.LocalDB; import envoy.client.event.SendEvent; import envoy.client.ui.ClearableTextField; import envoy.client.ui.SceneContext; -import envoy.client.ui.listcell.ContactListCell; +import envoy.client.ui.listcell.ContactListCellFactory; import envoy.data.Contact; import envoy.event.EventBus; import envoy.event.GroupCreation; @@ -42,7 +42,7 @@ public class GroupCreationScene { @FXML private void initialize() { - contactList.setCellFactory(ContactListCell::new); + contactList.setCellFactory(ContactListCellFactory::new); contactList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); groupNameField.setClearButtonListener(e -> { groupNameField.getTextField().clear(); createButton.setDisable(true); }); } diff --git a/src/main/java/envoy/client/ui/listcell/ContactControl.java b/src/main/java/envoy/client/ui/listcell/ContactControl.java new file mode 100644 index 0000000..359c41d --- /dev/null +++ b/src/main/java/envoy/client/ui/listcell/ContactControl.java @@ -0,0 +1,41 @@ +package envoy.client.ui.listcell; + +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; + +import envoy.data.Contact; +import envoy.data.Group; +import envoy.data.User; + +/** + * This class formats a single {@link Contact} into a UI component. + *

+ * Project: envoy-client
+ * File: ContactControl.java
+ * Created: 01.07.2020
+ * + * @author Leon Hofmeister + * @since Envoy Client v0.1-beta + */ +public class ContactControl extends VBox { + + /** + * + * @param contact the contact that should be formatted + * @since Envoy Client v0.1-beta + */ + public ContactControl(Contact contact) { + // Container with contact name + final var nameLabel = new Label(contact.getName()); + nameLabel.setWrapText(true); + getChildren().add(nameLabel); + if (contact instanceof User) { + // Online status + final var user = (User) contact; + final var statusLabel = new Label(user.getStatus().toString()); + statusLabel.getStyleClass().add(user.getStatus().toString().toLowerCase()); + getChildren().add(statusLabel); + } else // Member count + getChildren().add(new Label(((Group) contact).getContacts().size() + " members")); + } +} diff --git a/src/main/java/envoy/client/ui/listcell/ContactListCell.java b/src/main/java/envoy/client/ui/listcell/ContactListCell.java deleted file mode 100644 index 526e2b8..0000000 --- a/src/main/java/envoy/client/ui/listcell/ContactListCell.java +++ /dev/null @@ -1,59 +0,0 @@ -package envoy.client.ui.listcell; - -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.layout.VBox; - -import envoy.data.Contact; -import envoy.data.Group; -import envoy.data.User; - -/** - * Project: envoy-client
- * File: UserListCell.java
- * Created: 28.03.2020
- * - * @author Kai S. K. Engelbart - * @since Envoy Client v0.1-beta - */ -public class ContactListCell extends ListCell { - - private final ListView listView; - - /** - * @param listView the list view inside which this cell is contained - * @since Envoy Client v0.1-beta - */ - public ContactListCell(ListView listView) { this.listView = listView; } - - /** - * Displays the name of a contact. If the contact is a user, their online status - * is displayed as well. - * - * @since Envoy Client v0.1-beta - */ - @Override - protected void updateItem(Contact contact, boolean empty) { - super.updateItem(contact, empty); - if (empty || contact == null) { - setText(null); - setGraphic(null); - } else { - // Container with contact name - final var nameLabel = new Label(contact.getName()); - nameLabel.setWrapText(true); - final var vbox = new VBox(nameLabel); - if (contact instanceof User) { - // Online status - final var user = (User) contact; - final var statusLabel = new Label(user.getStatus().toString()); - statusLabel.getStyleClass().add(user.getStatus().toString().toLowerCase()); - vbox.getChildren().add(statusLabel); - } else // Member count - vbox.getChildren().add(new Label(((Group) contact).getContacts().size() + " members")); - if (listView != null) prefWidthProperty().bind(listView.widthProperty().subtract(40)); - setGraphic(vbox); - } - } -} diff --git a/src/main/java/envoy/client/ui/listcell/ContactListCellFactory.java b/src/main/java/envoy/client/ui/listcell/ContactListCellFactory.java new file mode 100644 index 0000000..8f8d3f0 --- /dev/null +++ b/src/main/java/envoy/client/ui/listcell/ContactListCellFactory.java @@ -0,0 +1,44 @@ +package envoy.client.ui.listcell; + +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; + +import envoy.data.Contact; + +/** + * Project: envoy-client
+ * File: UserListCell.java
+ * Created: 28.03.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy Client v0.1-beta + */ +public class ContactListCellFactory extends ListCell { + + private final ListView listView; + + /** + * @param listView the list view inside which this cell is contained + * @since Envoy Client v0.1-beta + */ + public ContactListCellFactory(ListView listView) { this.listView = listView; } + + /** + * Displays the name of a contact. If the contact is a user, their online status + * is displayed as well. + * + * @since Envoy Client v0.1-beta + */ + @Override + protected void updateItem(Contact contact, boolean empty) { + super.updateItem(contact, empty); + if (empty || contact == null) { + setText(null); + setGraphic(null); + } else { + final var control = new ContactControl(contact); + prefWidthProperty().bind(listView.widthProperty().subtract(40)); + setGraphic(control); + } + } +} diff --git a/src/main/java/envoy/client/ui/listcell/MessageControl.java b/src/main/java/envoy/client/ui/listcell/MessageControl.java new file mode 100644 index 0000000..d68acdd --- /dev/null +++ b/src/main/java/envoy/client/ui/listcell/MessageControl.java @@ -0,0 +1,60 @@ +package envoy.client.ui.listcell; + +import java.time.format.DateTimeFormatter; +import java.util.Map; + +import javafx.geometry.Insets; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.VBox; + +import envoy.client.ui.IconUtil; +import envoy.data.Message; +import envoy.data.Message.MessageStatus; +import envoy.data.User; + +/** + * This class formats a single {@link Message} into a UI component. + *

+ * Project: envoy-client
+ * File: MessageControl.java
+ * Created: 01.07.2020
+ * + * @author Leon Hofmeister + * @since Envoy Client v0.1-beta + */ +public class MessageControl extends VBox { + + private static User client; + private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"); + private static final Map statusImages = IconUtil.loadByEnum(MessageStatus.class, 16); + + /** + * + * @param message the message that should be formatted + * @since Envoy Client v0.1-beta + */ + public MessageControl(Message message) { + // Creating the underlying VBox, the dateLabel and the textLabel + super(new Label(dateFormat.format(message.getCreationDate()))); + final var textLabel = new Label(message.getText()); + textLabel.setWrapText(true); + getChildren().add(textLabel); + // Setting the message status icon and background color + if (message.getRecipientID() != client.getID()) { + final var statusIcon = new ImageView(statusImages.get(message.getStatus())); + statusIcon.setPreserveRatio(true); + getChildren().add(statusIcon); + getStyleClass().add("own-message"); + } else getStyleClass().add("received-message"); + // Adjusting height and weight of the cell to the corresponding ListView + paddingProperty().setValue(new Insets(5, 20, 5, 20)); + } + + /** + * @param client the user who has logged in + * @since Envoy Client v0.1-beta + */ + public static void setUser(User client) { MessageControl.client = client; } +} diff --git a/src/main/java/envoy/client/ui/listcell/MessageListCell.java b/src/main/java/envoy/client/ui/listcell/MessageListCell.java deleted file mode 100644 index 8edd772..0000000 --- a/src/main/java/envoy/client/ui/listcell/MessageListCell.java +++ /dev/null @@ -1,82 +0,0 @@ -package envoy.client.ui.listcell; - -import java.time.format.DateTimeFormatter; -import java.util.Map; - -import javafx.geometry.Insets; -import javafx.scene.control.*; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.VBox; -import javafx.stage.PopupWindow.AnchorLocation; - -import envoy.client.ui.IconUtil; -import envoy.data.Message; -import envoy.data.Message.MessageStatus; -import envoy.data.User; - -/** - * Displays a single message inside the message list. - *

- * Project: envoy-client
- * File: MessageListCell.java
- * Created: 28.03.2020
- * - * @author Kai S. K. Engelbart - * @since Envoy Client v0.1-beta - */ -public class MessageListCell extends ListCell { - - private final ListView listView; - - private static User client; - private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"); - private static final Map statusImages = IconUtil.loadByEnum(MessageStatus.class, 16); - - /** - * @param listView the list view inside which this cell is contained - * @since Envoy Client v0.1-beta - */ - public MessageListCell(ListView listView) { this.listView = listView; } - - /** - * Displays the text, the data of creation and the status of a message. - * - * @since Envoy v0.1-beta - */ - @Override - protected void updateItem(Message message, boolean empty) { - super.updateItem(message, empty); - if (empty || message == null) { - setText(null); - setGraphic(null); - } else { - // Creating the underlying VBox, the dateLabel and the textLabel - final var cell = new VBox(new Label(dateFormat.format(message.getCreationDate()))); - final var textLabel = new Label(message.getText()); - textLabel.setWrapText(true); - cell.getChildren().add(textLabel); - // Setting the message status icon and background color - if (message.getRecipientID() != client.getID()) { - final var statusIcon = new ImageView(statusImages.get(message.getStatus())); - cell.getChildren().add(statusIcon); - cell.getStyleClass().add("own-message"); - } else cell.getStyleClass().add("received-message"); - // Adjusting height and weight of the cell to the corresponding ListView - cell.paddingProperty().setValue(new Insets(5, 20, 5, 20)); - if (listView != null) cell.prefWidthProperty().bind(listView.widthProperty().subtract(40)); - // Creating the Tooltip to deselect a message - final var tooltip = new Tooltip("You can select a message by clicking on it \nand deselect it by pressing \"ctrl\" and clicking on it"); - tooltip.setWrapText(true); - tooltip.setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT); - setTooltip(tooltip); - setGraphic(cell); - } - } - - /** - * @param client the user who chats with another person - * @since Envoy Client v0.1-beta - */ - public static void setUser(User client) { MessageListCell.client = client; } -} diff --git a/src/main/java/envoy/client/ui/listcell/MessageListCellFactory.java b/src/main/java/envoy/client/ui/listcell/MessageListCellFactory.java new file mode 100644 index 0000000..f8e4fa2 --- /dev/null +++ b/src/main/java/envoy/client/ui/listcell/MessageListCellFactory.java @@ -0,0 +1,52 @@ +package envoy.client.ui.listcell; + +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.Tooltip; +import javafx.stage.PopupWindow.AnchorLocation; + +import envoy.data.Message; + +/** + * Displays a single message inside the message list. + *

+ * Project: envoy-client
+ * File: MessageListCellFactory.java
+ * Created: 28.03.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy Client v0.1-beta + */ +public class MessageListCellFactory extends ListCell { + + private final ListView listView; + + /** + * @param listView the list view inside which this cell is contained + * @since Envoy Client v0.1-beta + */ + public MessageListCellFactory(ListView listView) { this.listView = listView; } + + /** + * Displays the text, the data of creation and the status of a message. + * + * @since Envoy v0.1-beta + */ + @Override + protected void updateItem(Message message, boolean empty) { + super.updateItem(message, empty); + if (empty || message == null) { + setText(null); + setGraphic(null); + } else { + final var control = new MessageControl(message); + control.prefWidthProperty().bind(listView.widthProperty().subtract(40)); + // Creating the Tooltip to deselect a message + final var tooltip = new Tooltip("You can select a message by clicking on it \nand deselect it by pressing \"ctrl\" and clicking on it"); + tooltip.setWrapText(true); + tooltip.setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT); + setTooltip(tooltip); + setGraphic(control); + } + } +} diff --git a/src/main/resources/css/base.css b/src/main/resources/css/base.css index f9f1ce2..9230b0f 100644 --- a/src/main/resources/css/base.css +++ b/src/main/resources/css/base.css @@ -3,7 +3,7 @@ } .context-menu, .context-menu > * { - -fx-background-radius: 15px; + -fx-background-radius: 15.0px; /*TODO: solution below does not work */ -fx-background-color: transparent; } @@ -58,3 +58,19 @@ -fx-text-fill: #00FF00; -fx-background-color: transparent; } + +#infoLabel-success { + -fx-text-fill: #00FF00; +} + +#infoLabel-info { + -fx-text-fill: yellow; +} + +#infoLabel-warning { + -fx-text-fill: orange; +} + +#infoLabel-error { + -fx-text-fill: red; +}