diff --git a/.github/PULL_REQUEST_TEMPLATE/bugfix.md b/.github/PULL_REQUEST_TEMPLATE/bugfix.md
index e189f31..2a918ad 100644
--- a/.github/PULL_REQUEST_TEMPLATE/bugfix.md
+++ b/.github/PULL_REQUEST_TEMPLATE/bugfix.md
@@ -5,6 +5,7 @@ labels: bug
assignees: CyB3RC0nN0R, delvh, DieGurke
reviewers: CyB3RC0nN0R, delvh
projects: Envoy
-milestone: Envoy v0.3-alpha
+milestone: Envoy v0.1-beta
+
---
Fixes #{issue}
diff --git a/.github/PULL_REQUEST_TEMPLATE/feature_integration.md b/.github/PULL_REQUEST_TEMPLATE/feature_integration.md
index 945e7d3..7d5e167 100644
--- a/.github/PULL_REQUEST_TEMPLATE/feature_integration.md
+++ b/.github/PULL_REQUEST_TEMPLATE/feature_integration.md
@@ -1,9 +1,10 @@
---
name: Feature integration
title: Added feature
-labels: enhancement
+labels: feature
assignees: CyB3RC0nN0R, delvh, DieGurke
reviewers: CyB3RC0nN0R, delvh
projects: Envoy
-milestone: Envoy v0.3-alpha
+milestone: Envoy v0.1-beta
+
---
diff --git a/.github/PULL_REQUEST_TEMPLATE/javadoc_upgrade.md b/.github/PULL_REQUEST_TEMPLATE/javadoc_update.md
similarity index 84%
rename from .github/PULL_REQUEST_TEMPLATE/javadoc_upgrade.md
rename to .github/PULL_REQUEST_TEMPLATE/javadoc_update.md
index 7f1786d..68b0afd 100644
--- a/.github/PULL_REQUEST_TEMPLATE/javadoc_upgrade.md
+++ b/.github/PULL_REQUEST_TEMPLATE/javadoc_update.md
@@ -5,5 +5,6 @@ labels: documentation
assignees: CyB3RC0nN0R, delvh
reviewers: CyB3RC0nN0R, delvh
projects: Envoy
-milestone: Envoy v0.3-alpha
+milestone: Envoy v0.1-beta
+
---
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index da5f736..e9f97db 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -4,14 +4,25 @@ on: [push]
jobs:
build:
-
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
+ - name: Cache Maven packages
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
- name: Build with Maven
run: mvn -B package --file pom.xml
+ - name: Stage build artifacts
+ run: mkdir staging && cp target/*.jar staging
+ - uses: actions/upload-artifact@v1
+ with:
+ name: envoy-client-artifacts
+ path: staging
diff --git a/src/main/java/envoy/client/data/Chat.java b/src/main/java/envoy/client/data/Chat.java
index 207fb1f..318cf24 100644
--- a/src/main/java/envoy/client/data/Chat.java
+++ b/src/main/java/envoy/client/data/Chat.java
@@ -114,6 +114,21 @@ public final class Chat implements Serializable {
*/
public boolean isUnread() { return !messages.isEmpty() && messages.get(messages.size() - 1).getStatus() != MessageStatus.READ; }
+ /**
+ * Inserts a message at the correct place according to its creation date.
+ *
+ * @param message the message to insert
+ * @since Envoy Client v0.1-beta
+ */
+ public void insert(Message message) {
+ for (int i = messages.size() - 1; i >= 0; --i)
+ if (message.getCreationDate().isAfter(messages.get(i).getCreationDate())) {
+ messages.add(i + 1, message);
+ return;
+ }
+ messages.add(0, message);
+ }
+
/**
* @return all messages in the current chat
* @since Envoy Client v0.1-beta
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/ContactListCell.java b/src/main/java/envoy/client/ui/ContactListCell.java
deleted file mode 100644
index 283a89a..0000000
--- a/src/main/java/envoy/client/ui/ContactListCell.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package envoy.client.ui;
-
-import javafx.scene.control.Label;
-import javafx.scene.control.ListCell;
-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 {
-
- /**
- * 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 vbox = new VBox(new Label(contact.getName()));
- 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"));
- }
- setGraphic(vbox);
- }
- }
-}
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 21a094e..0000000
--- a/src/main/java/envoy/client/ui/MessageListCell.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package envoy.client.ui;
-
-import java.time.format.DateTimeFormatter;
-import java.util.Map;
-
-import javafx.geometry.Insets;
-import javafx.scene.control.Label;
-import javafx.scene.control.ListCell;
-import javafx.scene.image.Image;
-import javafx.scene.image.ImageView;
-import javafx.scene.layout.VBox;
-
-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 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);
-
- /**
- * 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 cell = new VBox(new Label(dateFormat.format(message.getCreationDate())), new Label(message.getText()));
- if (message.getRecipientID() == client.getID()) {
- cell.getChildren().add(new Label("", new ImageView(statusImages.get(message.getStatus()))));
- cell.getStyleClass().add("own-message");
- } else cell.getStyleClass().add("received-message");
- cell.paddingProperty().setValue(new Insets(5, 20, 5, 20));
- 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/Restorable.java b/src/main/java/envoy/client/ui/Restorable.java
new file mode 100644
index 0000000..e9e40eb
--- /dev/null
+++ b/src/main/java/envoy/client/ui/Restorable.java
@@ -0,0 +1,25 @@
+package envoy.client.ui;
+
+/**
+ * This interface defines an action that should be performed when a scene gets
+ * restored from the scene stack in {@link SceneContext}.
+ *
+ * Project: envoy-client
+ * File: Restorable.java
+ * Created: 03.07.2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Client v0.1-beta
+ */
+@FunctionalInterface
+public interface Restorable {
+
+ /**
+ * This method is getting called when a scene gets restored.
+ * Hence, it can contain anything that should be done when the underlying scene
+ * gets restored.
+ *
+ * @since Envoy Client v0.1-beta
+ */
+ void onRestore();
+}
diff --git a/src/main/java/envoy/client/ui/SceneContext.java b/src/main/java/envoy/client/ui/SceneContext.java
index 52c847b..a027395 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.
@@ -83,8 +90,9 @@ public final class SceneContext {
}
private final Stage stage;
- private final FXMLLoader loader = new FXMLLoader();
- private final Stack sceneStack = new Stack<>();
+ private final FXMLLoader loader = new FXMLLoader();
+ private final Stack sceneStack = new Stack<>();
+ private final Stack