diff --git a/src/main/java/envoy/client/ui/ClearableTextField.java b/src/main/java/envoy/client/ui/ClearableTextField.java
new file mode 100644
index 0000000..f19155b
--- /dev/null
+++ b/src/main/java/envoy/client/ui/ClearableTextField.java
@@ -0,0 +1,174 @@
+package envoy.client.ui;
+
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.StringProperty;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.control.*;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.ColumnConstraints;
+import javafx.scene.layout.GridPane;
+
+import envoy.client.data.Settings;
+
+/**
+ * This class offers a text field that is automatically equipped with a clear
+ * button.
+ *
+ * Project: envoy-client
+ * File: ClearableTextField.java
+ * Created: 25.06.2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Client v0.1-beta
+ */
+public class ClearableTextField extends GridPane {
+
+ private final TextField textField;
+
+ private final Button clearButton;
+
+ /**
+ * Constructs a new {@code ClearableTextField} with no initial text and icon
+ * size 16.
+ *
+ * @since Envoy Client v0.1-beta
+ */
+ public ClearableTextField() { this("", 16); }
+
+ /**
+ * Constructs a new {@code ClearableTextField} with initial text and a
+ * predetermined icon size.
+ *
+ * @param text the text that should be displayed by default
+ * @param size the size of the icon
+ * @since Envoy Client v0.1-beta
+ */
+ public ClearableTextField(String text, int size) {
+ // initializing the textField and the button
+ textField = new TextField(text);
+ clearButton = new Button("",
+ new ImageView(IconUtil.load(
+ Settings.getInstance().getCurrentTheme().equals("dark") ? "/icons/clear_button_white.png" : "/icons/clear_button_black.png",
+ size)));
+ clearButton.setOnAction(e -> textField.clear());
+ clearButton.setFocusTraversable(false);
+ clearButton.getStyleClass().clear();
+ clearButton.setBackground(Background.EMPTY);
+ // Adding the two elements to the GridPane
+ add(textField, 0, 0, 2, 1);
+ add(clearButton, 1, 0, 1, 1);
+ // Setting the percent - widths of the two columns.
+ // Used to locate the button on the right.
+ final var columnConstraints = new ColumnConstraints();
+ columnConstraints.setPercentWidth(90);
+ getColumnConstraints().add(columnConstraints);
+ final var columnConstraints2 = new ColumnConstraints();
+ columnConstraints2.setPercentWidth(10);
+ getColumnConstraints().add(columnConstraints2);
+ }
+
+ /**
+ * @return the underlying {@code textField}
+ * @since Envoy Client v0.1-beta
+ */
+ public TextField getTextField() { return textField; }
+
+ /**
+ * This method offers the freedom to perform custom actions when the
+ * {@code clearButton} has been pressed.
+ *
+ * The default is
+ * e -> {clearableTextField.getTextField().clear();}
+ *
+ * @param onClearButtonAction the action that should be performed
+ * @since Envoy Client v0.1-beta
+ */
+ public void setClearButtonListener(EventHandler onClearButtonAction) { clearButton.setOnAction(onClearButtonAction); }
+
+ /**
+ * @return the current property of the prompt text
+ * @see javafx.scene.control.TextInputControl#promptTextProperty()
+ * @since Envoy Client v0.1-beta
+ */
+ public final StringProperty promptTextProperty() { return textField.promptTextProperty(); }
+
+ /**
+ * @return the current prompt text
+ * @see javafx.scene.control.TextInputControl#getPromptText()
+ * @since Envoy Client v0.1-beta
+ */
+ public final String getPromptText() { return textField.getPromptText(); }
+
+ /**
+ * @param value the prompt text to display
+ * @see javafx.scene.control.TextInputControl#setPromptText(java.lang.String)
+ * @since Envoy Client v0.1-beta
+ */
+ public final void setPromptText(String value) { textField.setPromptText(value); }
+
+ /**
+ * @return the current property of the tooltip
+ * @see javafx.scene.control.Control#tooltipProperty()
+ * @since Envoy Client v0.1-beta
+ */
+ public final ObjectProperty tooltipProperty() { return textField.tooltipProperty(); }
+
+ /**
+ * @param value the new tooltip
+ * @see javafx.scene.control.Control#setTooltip(javafx.scene.control.Tooltip)
+ * @since Envoy Client v0.1-beta
+ */
+ public final void setTooltip(Tooltip value) { textField.setTooltip(value); }
+
+ /**
+ * @return the current tooltip
+ * @see javafx.scene.control.Control#getTooltip()
+ * @since Envoy Client v0.1-beta
+ */
+ public final Tooltip getTooltip() { return textField.getTooltip(); }
+
+ /**
+ * @return the current property of the context menu
+ * @see javafx.scene.control.Control#contextMenuProperty()
+ * @since Envoy Client v0.1-beta
+ */
+ public final ObjectProperty contextMenuProperty() { return textField.contextMenuProperty(); }
+
+ /**
+ * @param value the new context menu
+ * @see javafx.scene.control.Control#setContextMenu(javafx.scene.control.ContextMenu)
+ * @since Envoy Client v0.1-beta
+ */
+ public final void setContextMenu(ContextMenu value) { textField.setContextMenu(value); }
+
+ /**
+ * @return the current context menu
+ * @see javafx.scene.control.Control#getContextMenu()
+ * @since Envoy Client v0.1-beta
+ */
+ public final ContextMenu getContextMenu() { return textField.getContextMenu(); }
+
+ /**
+ * @param value whether this ClearableTextField should be editable
+ * @see javafx.scene.control.TextInputControl#setEditable(boolean)
+ * @since Envoy Client v0.1-beta
+ */
+ public final void setEditable(boolean value) { textField.setEditable(value); }
+
+ /**
+ * @return the current property whether this ClearableTextField is editable
+ * @see javafx.scene.control.TextInputControl#editableProperty()
+ * @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/MessageListCell.java b/src/main/java/envoy/client/ui/MessageListCell.java
deleted file mode 100644
index e33c502..0000000
--- a/src/main/java/envoy/client/ui/MessageListCell.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package envoy.client.ui;
-
-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.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 Label("", new ImageView(statusImages.get(message.getStatus())));
- statusIcon.setPadding(new Insets(1, 0, 5, 5));
- 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));
- 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/SceneContext.java b/src/main/java/envoy/client/ui/SceneContext.java
index 52c847b..6b6757e 100644
--- a/src/main/java/envoy/client/ui/SceneContext.java
+++ b/src/main/java/envoy/client/ui/SceneContext.java
@@ -40,21 +40,21 @@ public final class SceneContext {
public enum SceneInfo {
/**
- * The main scene in which chats are displayed.
+ * The main scene in which the chat screen is displayed.
*
* @since Envoy Client v0.1-beta
*/
CHAT_SCENE("/fxml/ChatScene.fxml"),
/**
- * The scene in which settings are displayed.
+ * The scene in which the settings screen is displayed.
*
* @since Envoy Client v0.1-beta
*/
SETTINGS_SCENE("/fxml/SettingsScene.fxml"),
/**
- * The scene in which the contact search is displayed.
+ * The scene in which the contact search screen is displayed.
*
* @since Envoy Client v0.1-beta
*/
@@ -72,7 +72,14 @@ public final class SceneContext {
*
* @since Envoy Client v0.1-beta
*/
- LOGIN_SCENE("/fxml/LoginScene.fxml");
+ LOGIN_SCENE("/fxml/LoginScene.fxml"),
+
+ /**
+ * The scene in which the info screen is displayed.
+ *
+ * @since Envoy Client v0.1-beta
+ */
+ MESSAGE_INFO_SCENE("/fxml/MessageInfoScene.fxml");
/**
* The path to the FXML resource.
diff --git a/src/main/java/envoy/client/ui/controller/ChatScene.java b/src/main/java/envoy/client/ui/controller/ChatScene.java
index 38f3aa1..ed35cda 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;
@@ -24,7 +23,11 @@ import envoy.client.data.Settings;
import envoy.client.event.MessageCreationEvent;
import envoy.client.net.Client;
import envoy.client.net.WriteProxy;
-import envoy.client.ui.*;
+import envoy.client.ui.IconUtil;
+import envoy.client.ui.SceneContext;
+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;
@@ -92,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)));
@@ -166,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");
}
/**
@@ -179,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
@@ -187,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
@@ -257,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");
}
}
@@ -302,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();
@@ -345,13 +350,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);
}
@@ -387,4 +393,7 @@ public final class ChatScene {
updateRemainingCharsLabel();
postButton.setDisable(messageText.isBlank());
}
+
+ @FXML
+ private void loadMessageInfoScene() { try {} catch (final NullPointerException e) {} }
}
diff --git a/src/main/java/envoy/client/ui/controller/ContactSearchScene.java b/src/main/java/envoy/client/ui/controller/ContactSearchScene.java
index 7e70a80..957a52b 100644
--- a/src/main/java/envoy/client/ui/controller/ContactSearchScene.java
+++ b/src/main/java/envoy/client/ui/controller/ContactSearchScene.java
@@ -5,13 +5,16 @@ import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.fxml.FXML;
-import javafx.scene.control.*;
+import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.ListView;
import envoy.client.data.LocalDB;
import envoy.client.event.SendEvent;
-import envoy.client.ui.ContactListCell;
+import envoy.client.ui.ClearableTextField;
import envoy.client.ui.SceneContext;
+import envoy.client.ui.listcell.ContactListCellFactory;
import envoy.data.Contact;
import envoy.event.ElementOperation;
import envoy.event.EventBus;
@@ -31,19 +34,7 @@ import envoy.util.EnvoyLog;
public class ContactSearchScene {
@FXML
- private Button backButton;
-
- @FXML
- private Button clearButton;
-
- @FXML
- private Button searchButton;
-
- @FXML
- private Button newGroupButton;
-
- @FXML
- private TextField searchBar;
+ private ClearableTextField searchBar;
@FXML
private ListView contactList;
@@ -67,7 +58,8 @@ 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()); }));
}
@@ -78,20 +70,12 @@ public class ContactSearchScene {
* @since Envoy Client v0.1-beta
*/
@FXML
- private void checkClearButton() {
- final var containsContent = searchBar.getText().strip().isEmpty();
- clearButton.setDisable(containsContent);
- searchButton.setDisable(containsContent);
+ private void sendRequest() {
+ final var text = searchBar.getTextField().getText().strip();
+ if (!text.isBlank()) eventBus.dispatch(new SendEvent(new ContactSearchRequest(text)));
+ else contactList.getItems().clear();
}
- /**
- * Sends a {@link ContactSearchRequest} to the server.
- *
- * @since Envoy Client v0.1-beta
- */
- @FXML
- private void suggestContacts() { eventBus.dispatch(new SendEvent(new ContactSearchRequest(searchBar.getText()))); }
-
/**
* Clears the text in the search bar and the items shown in the list.
* Additionally disables both clear and search button.
@@ -100,10 +84,8 @@ public class ContactSearchScene {
*/
@FXML
private void clear() {
- searchBar.setText(null);
+ searchBar.getTextField().setText(null);
contactList.getItems().clear();
- clearButton.setDisable(true);
- searchButton.setDisable(true);
}
/**
diff --git a/src/main/java/envoy/client/ui/controller/GroupCreationScene.java b/src/main/java/envoy/client/ui/controller/GroupCreationScene.java
index 9234fa2..76573b8 100644
--- a/src/main/java/envoy/client/ui/controller/GroupCreationScene.java
+++ b/src/main/java/envoy/client/ui/controller/GroupCreationScene.java
@@ -9,8 +9,9 @@ import javafx.scene.control.Alert.AlertType;
import envoy.client.data.LocalDB;
import envoy.client.event.SendEvent;
-import envoy.client.ui.ContactListCell;
+import envoy.client.ui.ClearableTextField;
import envoy.client.ui.SceneContext;
+import envoy.client.ui.listcell.ContactListCellFactory;
import envoy.data.Contact;
import envoy.event.EventBus;
import envoy.event.GroupCreation;
@@ -30,7 +31,7 @@ public class GroupCreationScene {
private Button createButton;
@FXML
- private TextField groupNameField;
+ private ClearableTextField groupNameField;
@FXML
private ListView contactList;
@@ -41,8 +42,9 @@ 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); });
}
/**
@@ -63,7 +65,18 @@ public class GroupCreationScene {
* @since Envoy Client v0.1-beta
*/
@FXML
- private void contactListClicked() { createButton.setDisable(contactList.getSelectionModel().isEmpty()); }
+ private void contactListClicked() {
+ createButton.setDisable(contactList.getSelectionModel().isEmpty() || groupNameField.getTextField().getText().isBlank());
+ }
+
+ /**
+ * Checks, whether the {@code createButton} can be enabled because text is
+ * present in the textfield.
+ *
+ * @since Envoy Client v0.1-beta
+ */
+ @FXML
+ private void textUpdated() { createButton.setDisable(groupNameField.getTextField().getText().isBlank()); }
/**
* Sends a {@link GroupCreation} to the server and closes this scene.
@@ -74,10 +87,10 @@ public class GroupCreationScene {
*/
@FXML
private void createButtonClicked() {
- final var name = groupNameField.getText();
+ final var name = groupNameField.getTextField().getText();
if (!Bounds.isValidContactName(name)) {
new Alert(AlertType.ERROR, "The entered group name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
- groupNameField.clear();
+ groupNameField.getTextField().clear();
} else {
eventBus.dispatch(new SendEvent(new GroupCreation(name,
contactList.getSelectionModel().getSelectedItems().stream().map(Contact::getID).collect(Collectors.toSet()))));
diff --git a/src/main/java/envoy/client/ui/controller/LoginScene.java b/src/main/java/envoy/client/ui/controller/LoginScene.java
index 3ec2338..5933665 100644
--- a/src/main/java/envoy/client/ui/controller/LoginScene.java
+++ b/src/main/java/envoy/client/ui/controller/LoginScene.java
@@ -13,6 +13,7 @@ import javafx.scene.control.Alert.AlertType;
import envoy.client.data.*;
import envoy.client.net.Client;
+import envoy.client.ui.ClearableTextField;
import envoy.client.ui.SceneContext;
import envoy.client.ui.Startup;
import envoy.data.LoginCredentials;
@@ -38,7 +39,7 @@ import envoy.util.EnvoyLog;
public final class LoginScene {
@FXML
- private TextField userTextField;
+ private ClearableTextField userTextField;
@FXML
private PasswordField passwordField;
@@ -116,17 +117,17 @@ public final class LoginScene {
if (registerCheckBox.isSelected() && !passwordField.getText().equals(repeatPasswordField.getText())) {
new Alert(AlertType.ERROR, "The entered password is unequal to the repeated one").showAndWait();
repeatPasswordField.clear();
- } else if (!Bounds.isValidContactName(userTextField.getText())) {
+ } else if (!Bounds.isValidContactName(userTextField.getTextField().getText())) {
new Alert(AlertType.ERROR, "The entered user name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
- userTextField.clear();
- } else
- performHandshake(
- new LoginCredentials(userTextField.getText(), passwordField.getText().toCharArray(), registerCheckBox.isSelected(), Startup.VERSION));
+ userTextField.getTextField().clear();
+ } else performHandshake(new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText().toCharArray(),
+ registerCheckBox.isSelected(), Startup.VERSION));
}
@FXML
private void offlineModeButtonPressed() {
- attemptOfflineMode(new LoginCredentials(userTextField.getText(), passwordField.getText().toCharArray(), false, Startup.VERSION));
+ attemptOfflineMode(
+ new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText().toCharArray(), false, Startup.VERSION));
}
@FXML
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..2a802fc
--- /dev/null
+++ b/src/main/java/envoy/client/ui/listcell/ContactControl.java
@@ -0,0 +1,40 @@
+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/ContactListCell.java b/src/main/java/envoy/client/ui/listcell/ContactListCellFactory.java
similarity index 51%
rename from src/main/java/envoy/client/ui/ContactListCell.java
rename to src/main/java/envoy/client/ui/listcell/ContactListCellFactory.java
index b13543b..8f8d3f0 100644
--- a/src/main/java/envoy/client/ui/ContactListCell.java
+++ b/src/main/java/envoy/client/ui/listcell/ContactListCellFactory.java
@@ -1,13 +1,9 @@
-package envoy.client.ui;
+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
@@ -17,7 +13,7 @@ import envoy.data.User;
* @author Kai S. K. Engelbart
* @since Envoy Client v0.1-beta
*/
-public class ContactListCell extends ListCell {
+public class ContactListCellFactory extends ListCell {
private final ListView listView;
@@ -25,7 +21,7 @@ public class ContactListCell extends ListCell {
* @param listView the list view inside which this cell is contained
* @since Envoy Client v0.1-beta
*/
- public ContactListCell(ListView listView) { this.listView = listView; }
+ public ContactListCellFactory(ListView listView) { this.listView = listView; }
/**
* Displays the name of a contact. If the contact is a user, their online status
@@ -40,20 +36,9 @@ public class ContactListCell extends ListCell {
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"));
+ final var control = new ContactControl(contact);
prefWidthProperty().bind(listView.widthProperty().subtract(40));
- setGraphic(vbox);
+ 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/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/java/envoy/client/ui/listcell/package-info.java b/src/main/java/envoy/client/ui/listcell/package-info.java
new file mode 100644
index 0000000..ab0788e
--- /dev/null
+++ b/src/main/java/envoy/client/ui/listcell/package-info.java
@@ -0,0 +1,12 @@
+/**
+ * This package contains custom list cells that are used to display certain
+ * things.
+ *