From bc355f190f782d79092a54e0a722244f561734b3 Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 16 Jul 2020 17:35:15 +0200 Subject: [PATCH 1/7] Added deepRefresh - mechanism additionally fixed bug not updating messageList when a MessageStatusChange occurs (seriously, why did no one notice it before?) --- .../java/envoy/client/ui/ListViewRefresh.java | 36 +++++++++++++++++++ .../envoy/client/ui/controller/ChatScene.java | 15 ++++---- 2 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 client/src/main/java/envoy/client/ui/ListViewRefresh.java diff --git a/client/src/main/java/envoy/client/ui/ListViewRefresh.java b/client/src/main/java/envoy/client/ui/ListViewRefresh.java new file mode 100644 index 0000000..b718c98 --- /dev/null +++ b/client/src/main/java/envoy/client/ui/ListViewRefresh.java @@ -0,0 +1,36 @@ +package envoy.client.ui; + +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; + +/** + * This is a utility class that provides access to a refreshing mechanism for + * elements that were added without notifying the underlying {@link ListView}. + *

+ * Project: envoy-client
+ * File: ListViewRefresh.java
+ * Created: 16.07.2020
+ * + * @author Leon Hofmeister + * @since Envoy Client v0.1-beta + */ +public class ListViewRefresh { + + private ListViewRefresh() {} + + /** + * Deeply refreshes a {@code listview}, meaning it recomputes every single of + * its {@link ListCell}s. + *

+ * While it does work, it is not the most efficient algorithm possible. + * + * @param toRefresh the listView to refresh + * @param the type of its {@code listcells} + * @since Envoy Client v0.1-beta + */ + public static void deepRefresh(ListView toRefresh) { + final var items = toRefresh.getItems(); + toRefresh.setItems(null); + toRefresh.setItems(items); + } +} diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index 920d93f..c431aad 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -31,9 +31,7 @@ import envoy.client.data.audio.AudioRecorder; import envoy.client.event.MessageCreationEvent; import envoy.client.net.Client; import envoy.client.net.WriteProxy; -import envoy.client.ui.IconUtil; -import envoy.client.ui.Restorable; -import envoy.client.ui.SceneContext; +import envoy.client.ui.*; import envoy.client.ui.listcell.ChatControl; import envoy.client.ui.listcell.ListCellFactory; import envoy.client.ui.listcell.MessageControl; @@ -144,7 +142,7 @@ public final class ChatScene implements Restorable { } catch (final IOException e1) { logger.log(Level.WARNING, "Could not read current chat: ", e1); } - Platform.runLater(() -> { messageList.refresh(); scrollToMessageListEnd(); }); + Platform.runLater(() -> { ListViewRefresh.deepRefresh(messageList); scrollToMessageListEnd(); }); } else chat.incrementUnreadAmount(); // Moving chat with most recent unreadMessages to the top Platform.runLater(() -> { @@ -158,8 +156,9 @@ public final class ChatScene implements Restorable { // Listen to message status changes eventBus.register(MessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(message -> { message.setStatus(e.get()); - // Update UI if in current chat - if (currentChat != null && message.getSenderID() == currentChat.getRecipient().getID()) Platform.runLater(messageList::refresh); + // Update UI if in current chat and the current user was the sender of the + // message + if (currentChat != null && message.getSenderID() == client.getSender().getID()) Platform.runLater(messageList::refresh); })); eventBus.register(GroupMessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(groupMessage -> { @@ -184,7 +183,7 @@ public final class ChatScene implements Restorable { switch (e.getOperationType()) { case ADD: localDB.getUsers().put(contact.getName(), contact); - Chat chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact); + final Chat chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact); Platform.runLater(() -> chatList.getItems().add(chat)); break; case REMOVE: @@ -499,7 +498,7 @@ public final class ChatScene implements Restorable { localDB.getChats().remove(currentChat); localDB.getChats().add(0, currentChat); }); - messageList.refresh(); + ListViewRefresh.deepRefresh(messageList); scrollToMessageListEnd(); // Request a new ID generator if all IDs were used From fb4fd85fe45b3cbd52bced1acb176b763347dc7f Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 16 Jul 2020 17:36:57 +0200 Subject: [PATCH 2/7] Removed the selected user from ContactSearchScene upon addition --- .../java/envoy/client/ui/controller/ContactSearchScene.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/main/java/envoy/client/ui/controller/ContactSearchScene.java b/client/src/main/java/envoy/client/ui/controller/ContactSearchScene.java index 5b5c448..e21c646 100644 --- a/client/src/main/java/envoy/client/ui/controller/ContactSearchScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ContactSearchScene.java @@ -118,7 +118,8 @@ public class ContactSearchScene { final var event = new ContactOperation(user, ElementOperation.ADD); // Sends the event to the server eventBus.dispatch(new SendEvent(event)); - // Updates the UI + // Removes the chosen user and updates the UI + userList.getItems().remove(user); eventBus.dispatch(event); logger.log(Level.INFO, "Added user " + user); })); From c0f4a8e212a47f2cff1dc7161dfbea62913fa483 Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 16 Jul 2020 17:47:59 +0200 Subject: [PATCH 3/7] Warned user on group creation if he already has a Group with that name --- .../ui/controller/GroupCreationScene.java | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java b/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java index e6ca29a..88f66d7 100644 --- a/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java +++ b/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java @@ -16,6 +16,8 @@ import envoy.client.ui.ClearableTextField; import envoy.client.ui.SceneContext; import envoy.client.ui.listcell.ContactControl; import envoy.client.ui.listcell.ListCellFactory; +import envoy.data.Contact; +import envoy.data.Group; import envoy.data.User; import envoy.event.EventBus; import envoy.event.GroupCreation; @@ -50,6 +52,8 @@ public class GroupCreationScene { private SceneContext sceneContext; + private LocalDB localDB; + private static final EventBus eventBus = EventBus.getInstance(); @FXML @@ -66,7 +70,8 @@ public class GroupCreationScene { * @since Envoy Client v0.1-beta */ public void initializeData(SceneContext sceneContext, LocalDB localDB) { - this.sceneContext = sceneContext; + this.sceneContext = sceneContext; + this.localDB = localDB; Platform.runLater(() -> userList.getItems() .addAll(localDB.getChats() .stream() @@ -109,14 +114,47 @@ public class GroupCreationScene { if (!Bounds.isValidContactName(name)) { new Alert(AlertType.ERROR, "The entered group name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait(); groupNameField.getTextField().clear(); + } else if (groupNameAlreadyPresent(name)) { + final var alert = new Alert(AlertType.WARNING, "You already have a group with that name.", ButtonType.OK, ButtonType.CANCEL); + alert.setTitle("Create Group?"); + alert.setHeaderText("Proceed?"); + alert.showAndWait().filter(btn -> btn == ButtonType.OK).ifPresent(btn -> createGroup(name)); } else { - eventBus.dispatch(new SendEvent( - new GroupCreation(name, userList.getSelectionModel().getSelectedItems().stream().map(User::getID).collect(Collectors.toSet())))); new Alert(AlertType.INFORMATION, String.format("Group '%s' successfully created.", name)).showAndWait(); - sceneContext.pop(); + createGroup(name); } } + /** + * Creates a new group with the given name and all selected members.
+ * Additionally pops the scene automatically. + * + * @param name the chosen group name + * @since Envoy Client v0.1-beta + */ + private void createGroup(String name) { + eventBus.dispatch(new SendEvent( + new GroupCreation(name, userList.getSelectionModel().getSelectedItems().stream().map(User::getID).collect(Collectors.toSet())))); + sceneContext.pop(); + } + + /** + * Returns true if the proposed group name is already present in the users + * {@code LocalDB}. + * + * @param newName the chosen group name + * @return true if this name is already present + * @since Envoy Client v0.1-beta + */ + public boolean groupNameAlreadyPresent(String newName) { + return localDB.getChats() + .stream() + .map(Chat::getRecipient) + .filter(Group.class::isInstance) + .map(Contact::getName) + .anyMatch(groupName -> groupName.equals(newName)); + } + @FXML private void backButtonClicked() { sceneContext.pop(); } } From 176f6c6463540516d961eb672e7c598d8bde4819 Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 16 Jul 2020 18:23:06 +0200 Subject: [PATCH 4/7] Fixed bug not enabling the post-button when an attachment is present --- .../src/main/java/envoy/client/ui/controller/ChatScene.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index c431aad..c261ed6 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -355,6 +355,7 @@ public final class ChatScene implements Restorable { try { final var fileBytes = Files.readAllBytes(file.toPath()); pendingAttachment = new Attachment(fileBytes, type); + checkPostConditions(false); // Setting the preview image as image of the attachmentView if (type == AttachmentType.PICTURE) attachmentView.setImage(new Image(new ByteArrayInputStream(fileBytes), DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, true, true)); @@ -413,9 +414,9 @@ public final class ChatScene implements Restorable { || !settings.isEnterToSend() && e.getCode() == KeyCode.ENTER && e.isControlDown()); } - private void checkPostConditions(boolean sendKeyPressed) { + private void checkPostConditions(boolean postMessage) { if (!postingPermanentlyDisabled) { - if (!postButton.isDisabled() && sendKeyPressed) postMessage(); + if (!postButton.isDisabled() && postMessage) postMessage(); postButton.setDisable(messageTextArea.getText().isBlank() && pendingAttachment == null || currentChat == null); } else { final var noMoreMessaging = "Go online to send messages"; From 698b57d99d6bbd27f6ade4a5621fa4f5062de7ff Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 16 Jul 2020 20:34:24 +0200 Subject: [PATCH 5/7] Fixed Bug not updating MessageStatusChanges --- client/src/main/java/envoy/client/ui/ListViewRefresh.java | 2 +- client/src/main/java/envoy/client/ui/controller/ChatScene.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/main/java/envoy/client/ui/ListViewRefresh.java b/client/src/main/java/envoy/client/ui/ListViewRefresh.java index b718c98..962b18c 100644 --- a/client/src/main/java/envoy/client/ui/ListViewRefresh.java +++ b/client/src/main/java/envoy/client/ui/ListViewRefresh.java @@ -14,7 +14,7 @@ import javafx.scene.control.ListView; * @author Leon Hofmeister * @since Envoy Client v0.1-beta */ -public class ListViewRefresh { +public final class ListViewRefresh { private ListViewRefresh() {} diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index c261ed6..83e64fe 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -175,7 +175,7 @@ public final class ChatScene implements Restorable { .filter(c -> c.getRecipient().getID() == e.getID()) .findAny() .map(Chat::getRecipient) - .ifPresent(u -> { ((User) u).setStatus(e.get()); Platform.runLater(chatList::refresh); })); + .ifPresent(u -> { ((User) u).setStatus(e.get()); Platform.runLater(() -> ListViewRefresh.deepRefresh(chatList)); })); // Listen to contacts changes eventBus.register(ContactOperation.class, e -> { From 96bfe489da0ec8e9ee30427b7e4c2faa5b329ead Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 16 Jul 2020 20:54:15 +0200 Subject: [PATCH 6/7] Update client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java Co-authored-by: CyB3RC0nN0R --- .../java/envoy/client/ui/controller/GroupCreationScene.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java b/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java index 88f66d7..be19bed 100644 --- a/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java +++ b/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java @@ -115,7 +115,7 @@ public class GroupCreationScene { new Alert(AlertType.ERROR, "The entered group name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait(); groupNameField.getTextField().clear(); } else if (groupNameAlreadyPresent(name)) { - final var alert = new Alert(AlertType.WARNING, "You already have a group with that name.", ButtonType.OK, ButtonType.CANCEL); + final var alert = new Alert(AlertType.WARNING, "You already have a group with that name.", ButtonType.OK, ButtonType.CANCEL); alert.setTitle("Create Group?"); alert.setHeaderText("Proceed?"); alert.showAndWait().filter(btn -> btn == ButtonType.OK).ifPresent(btn -> createGroup(name)); From 00603bedf6de18c6230229c5c75b1ddf0152e1b7 Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 16 Jul 2020 20:54:47 +0200 Subject: [PATCH 7/7] Update client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java Co-authored-by: CyB3RC0nN0R --- .../java/envoy/client/ui/controller/GroupCreationScene.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java b/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java index be19bed..71c7dd4 100644 --- a/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java +++ b/client/src/main/java/envoy/client/ui/controller/GroupCreationScene.java @@ -152,7 +152,7 @@ public class GroupCreationScene { .map(Chat::getRecipient) .filter(Group.class::isInstance) .map(Contact::getName) - .anyMatch(groupName -> groupName.equals(newName)); + .anyMatch(newName::equals); } @FXML