From ebe19c00c934991c158c8774485f395e61602fb4 Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 14 Oct 2020 23:41:24 +0200 Subject: [PATCH] Move context menu from ChatScene globally to ChatControl specific Additionally fixed a small bug in UserCreationProcessor and when deleting a contact offline --- .../envoy/client/ui/control/ChatControl.java | 31 ++++++++---- .../envoy/client/ui/controller/ChatScene.java | 19 +------- .../main/java/envoy/client/util/UserUtil.java | 2 +- client/src/main/resources/fxml/ChatScene.fxml | 9 ---- .../src/main/java/envoy/server/Startup.java | 2 +- .../envoy/server/data/PersistenceManager.java | 48 ++++++++++++++----- .../processors/GroupCreationProcessor.java | 18 +++---- ...essor.java => UserOperationProcessor.java} | 36 ++++---------- 8 files changed, 76 insertions(+), 89 deletions(-) rename server/src/main/java/envoy/server/processors/{ContactOperationProcessor.java => UserOperationProcessor.java} (51%) diff --git a/client/src/main/java/envoy/client/ui/control/ChatControl.java b/client/src/main/java/envoy/client/ui/control/ChatControl.java index 6d4b535..c42ec28 100644 --- a/client/src/main/java/envoy/client/ui/control/ChatControl.java +++ b/client/src/main/java/envoy/client/ui/control/ChatControl.java @@ -1,12 +1,13 @@ package envoy.client.ui.control; import javafx.geometry.*; -import javafx.scene.control.Label; +import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.layout.*; import envoy.client.data.*; -import envoy.client.util.IconUtil; +import envoy.client.util.*; +import envoy.data.User; /** * Displays a chat using a contact control for the recipient and a label for the @@ -16,7 +17,7 @@ import envoy.client.util.IconUtil; * @author Leon Hofmeister * @since Envoy Client v0.1-beta */ -public final class ChatControl extends HBox { +public final class ChatControl extends Label { private static final Image userIcon = IconUtil.loadIconThemeSensitive("user_icon", 32), groupIcon = IconUtil.loadIconThemeSensitive("group_icon", 32); @@ -31,25 +32,35 @@ public final class ChatControl extends HBox { setAlignment(Pos.CENTER_LEFT); setPadding(new Insets(0, 0, 3, 0)); + final var menu = new ContextMenu(); + final var removeMI = new MenuItem(); + removeMI + .setText(chat.isDisabled() ? "Delete " : chat.getRecipient() instanceof User ? "Block " : "Leave group " + chat.getRecipient().getName()); + removeMI.setOnAction(chat.isDisabled() ? e -> UserUtil.deleteContact(chat.getRecipient()) : e -> UserUtil.blockContact(chat.getRecipient())); + menu.getItems().add(removeMI); + setContextMenu(menu); + + final var display = new HBox(); + // Profile picture final var contactProfilePic = new ProfilePicImageView(chat instanceof GroupChat ? groupIcon : userIcon, 32); - getChildren().add(contactProfilePic); + display.getChildren().add(contactProfilePic); // Spacing final var leftSpacing = new Region(); leftSpacing.setPrefSize(8, 0); leftSpacing.setMinSize(8, 0); leftSpacing.setMaxSize(8, 0); - getChildren().add(leftSpacing); + display.getChildren().add(leftSpacing); // Contact control - getChildren().add(new ContactControl(chat.getRecipient())); + display.getChildren().add(new ContactControl(chat.getRecipient())); // Unread messages if (chat.getUnreadAmount() != 0) { final var spacing = new Region(); - setHgrow(spacing, Priority.ALWAYS); - getChildren().add(spacing); + HBox.setHgrow(spacing, Priority.ALWAYS); + display.getChildren().add(spacing); final var unreadMessagesLabel = new Label(Integer.toString(chat.getUnreadAmount())); unreadMessagesLabel.setMinSize(15, 15); final var vbox = new VBox(); @@ -57,9 +68,11 @@ public final class ChatControl extends HBox { unreadMessagesLabel.setAlignment(Pos.CENTER); unreadMessagesLabel.getStyleClass().add("unread-messages-amount"); vbox.getChildren().add(unreadMessagesLabel); - getChildren().add(vbox); + display.getChildren().add(vbox); } + setGraphic(display); + // Set background depending on whether it is disabled or not getStyleClass().add(chat.isDisabled() ? "disabled-chat" : "list-element"); } 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 ca845ed..b28e428 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -91,9 +91,6 @@ public final class ChatScene implements EventListener, Restorable { @FXML private Label topBarStatusLabel; - @FXML - private MenuItem deleteContactMenuItem; - @FXML private ImageView attachmentView; @@ -278,12 +275,13 @@ public final class ChatScene implements EventListener, Restorable { @Event private void onGroupResize(GroupResize resize) { final var chatFound = localDB.getChat(resize.getGroupID()); + if (chatFound.isEmpty()) return; Platform.runLater(() -> { chatList.refresh(); // Update the top-bar status label if all conditions apply if (currentChat != null && currentChat.getRecipient().equals(chatFound.get().getRecipient())) - chatFound.ifPresent(chat -> topBarStatusLabel.setText(chat.getRecipient().getContacts().size() + " members")); + topBarStatusLabel.setText(chatFound.get().getRecipient().getContacts().size() + " members"); }); } @@ -348,7 +346,6 @@ public final class ChatScene implements EventListener, Restorable { final var scrollIndex = messageList.getItems().size() - currentChat.getUnreadAmount(); messageList.scrollTo(scrollIndex); logger.log(Level.FINEST, "Loading chat with " + user + " at index " + scrollIndex); - deleteContactMenuItem.setText("Delete " + user.getName()); // Read the current chat currentChat.read(writeProxy); @@ -746,18 +743,6 @@ public final class ChatScene implements EventListener, Restorable { } } - // Context menu actions - - @FXML - private void blockOrDeleteContact() { - final var selectedChat = chatList.getSelectionModel().getSelectedItem(); - - if (selectedChat == null) return; - // If a contact has already been blocked deletes this chat else only blocks him - if (selectedChat.isDisabled()) UserUtil.deleteContact(selectedChat.getRecipient()); - else UserUtil.blockContact(selectedChat.getRecipient()); - } - /** * Redesigns the UI when the {@link Chat} of the given contact has been marked * as disabled. diff --git a/client/src/main/java/envoy/client/util/UserUtil.java b/client/src/main/java/envoy/client/util/UserUtil.java index 8e38ae3..c6477b1 100644 --- a/client/src/main/java/envoy/client/util/UserUtil.java +++ b/client/src/main/java/envoy/client/util/UserUtil.java @@ -102,7 +102,7 @@ public final class UserUtil { * @since Envoy Client v0.3-beta */ public static void deleteContact(Contact delete) { - if (!context.getClient().isOnline() || delete == null) return; + if (delete == null) return; else { final var alert = new Alert(AlertType.CONFIRMATION); alert.setContentText("Are you sure you want to delete " + delete.getName() diff --git a/client/src/main/resources/fxml/ChatScene.fxml b/client/src/main/resources/fxml/ChatScene.fxml index 8368e4b..d61325c 100644 --- a/client/src/main/resources/fxml/ChatScene.fxml +++ b/client/src/main/resources/fxml/ChatScene.fxml @@ -126,15 +126,6 @@ - - - - - - - diff --git a/server/src/main/java/envoy/server/Startup.java b/server/src/main/java/envoy/server/Startup.java index 6beafee..db890ac 100755 --- a/server/src/main/java/envoy/server/Startup.java +++ b/server/src/main/java/envoy/server/Startup.java @@ -51,7 +51,7 @@ public final class Startup { new UserStatusChangeProcessor(), new IDGeneratorRequestProcessor(), new UserSearchProcessor(), - new ContactOperationProcessor(), + new UserOperationProcessor(), new IsTypingProcessor(), new NameChangeProcessor(), new ProfilePicChangeProcessor(), diff --git a/server/src/main/java/envoy/server/data/PersistenceManager.java b/server/src/main/java/envoy/server/data/PersistenceManager.java index 9350569..2c9bf33 100755 --- a/server/src/main/java/envoy/server/data/PersistenceManager.java +++ b/server/src/main/java/envoy/server/data/PersistenceManager.java @@ -2,11 +2,13 @@ package envoy.server.data; import java.time.Instant; import java.util.List; +import java.util.logging.Level; import javax.persistence.*; import envoy.data.User.UserStatus; import envoy.server.net.ConnectionManager; +import envoy.util.EnvoyLog; /** * Contains operations used for persistence. @@ -240,17 +242,24 @@ public final class PersistenceManager { * @since Envoy Server Standalone v0.1-alpha */ public void addContactBidirectional(long contactID1, long contactID2) { + addContactBidirectional(getContactByID(contactID1), getContactByID(contactID2)); + } - // Get users by ID - final var c1 = getContactByID(contactID1); - final var c2 = getContactByID(contactID2); + /** + * Adds a contact to the contact list of another contact and vice versa. + * + * @param contact1 the first contact + * @param contact2 the second contact + * @since Envoy Server v0.3-beta + */ + public void addContactBidirectional(Contact contact1, Contact contact2) { // Add users to each others contact list - c1.getContacts().add(c2); - c2.getContacts().add(c1); + contact1.getContacts().add(contact2); + contact2.getContacts().add(contact1); // Synchronize changes with the database - transaction(() -> { entityManager.merge(c1); entityManager.merge(c2); }); + transaction(() -> { entityManager.merge(contact1); entityManager.merge(contact2); }); } /** @@ -261,17 +270,24 @@ public final class PersistenceManager { * @since Envoy Server v0.3-beta */ public void removeContactBidirectional(long contactID1, long contactID2) { + removeContactBidirectional(getContactByID(contactID1), getContactByID(contactID2)); + } - // Get users by ID - final var c1 = getContactByID(contactID1); - final var c2 = getContactByID(contactID2); + /** + * Removes a contact from the contact list of another contact and vice versa. + * + * @param contact1 the first contact + * @param contact2 the second contact + * @since Envoy Server v0.3-beta + */ + public void removeContactBidirectional(Contact contact1, Contact contact2) { // Remove users from each others contact list - c1.getContacts().remove(c2); - c2.getContacts().remove(c1); + contact1.getContacts().remove(contact2); + contact2.getContacts().remove(contact1); // Synchronize changes with the database - transaction(() -> { entityManager.merge(c1); entityManager.merge(c2); }); + transaction(() -> { entityManager.merge(contact1); entityManager.merge(contact2); }); } /** @@ -311,6 +327,14 @@ public final class PersistenceManager { entityManagerRelatedAction.run(); transaction.commit(); } + } catch (final RollbackException e2) { + + // Apparently a major problem exists. Discard faulty transaction and then go on. + if (transaction.isActive()) { + transaction.rollback(); + EnvoyLog.getLogger(PersistenceManager.class) + .log(Level.SEVERE, "Could not perform transaction, hence discarding it. It's likely that a serious issue exists."); + } else throw e2; } } } diff --git a/server/src/main/java/envoy/server/processors/GroupCreationProcessor.java b/server/src/main/java/envoy/server/processors/GroupCreationProcessor.java index 3540238..28ec8f7 100644 --- a/server/src/main/java/envoy/server/processors/GroupCreationProcessor.java +++ b/server/src/main/java/envoy/server/processors/GroupCreationProcessor.java @@ -5,7 +5,7 @@ import static envoy.server.Startup.config; import java.util.HashSet; import envoy.event.*; -import envoy.server.data.*; +import envoy.server.data.PersistenceManager; import envoy.server.net.*; /** @@ -27,18 +27,12 @@ public final class GroupCreationProcessor implements ObjectProcessor()); - groupCreation.getInitialMemberIDs().stream().map(persistenceManager::getUserByID).forEach(group.getContacts()::add); - group.getContacts().add(persistenceManager.getContactByID(connectionManager.getUserIDBySocketID(socketID))); - group.getContacts().forEach(c -> c.getContacts().add(group)); - group.getContacts().add(persistenceManager.getUserByID(connectionManager.getUserIDBySocketID(socketID))); persistenceManager.addContact(group); - final var resultGroup = group.toCommon(); - group.getContacts() + groupCreation.getInitialMemberIDs() .stream() - .map(Contact::getID) - .filter(connectionManager::isOnline) - .map(connectionManager::getSocketID) - .forEach(memberSocketID -> writeProxy.write(memberSocketID, new GroupCreationResult(resultGroup))); - writeProxy.write(socketID, new GroupCreationResult(resultGroup)); + .map(persistenceManager::getUserByID) + .forEach(member -> persistenceManager.addContactBidirectional(member, group)); + persistenceManager.addContactBidirectional(persistenceManager.getUserByID(connectionManager.getUserIDBySocketID(socketID)), group); + writeProxy.writeToOnlineContacts(group.getContacts(), new GroupCreationResult(group.toCommon())); } } diff --git a/server/src/main/java/envoy/server/processors/ContactOperationProcessor.java b/server/src/main/java/envoy/server/processors/UserOperationProcessor.java similarity index 51% rename from server/src/main/java/envoy/server/processors/ContactOperationProcessor.java rename to server/src/main/java/envoy/server/processors/UserOperationProcessor.java index 1fa74fb..b3d28be 100755 --- a/server/src/main/java/envoy/server/processors/ContactOperationProcessor.java +++ b/server/src/main/java/envoy/server/processors/UserOperationProcessor.java @@ -5,7 +5,7 @@ import java.util.logging.*; import envoy.event.ElementOperation; import envoy.event.contact.UserOperation; -import envoy.server.data.*; +import envoy.server.data.PersistenceManager; import envoy.server.net.*; import envoy.util.EnvoyLog; @@ -13,10 +13,10 @@ import envoy.util.EnvoyLog; * @author Kai S. K. Engelbart * @since Envoy Server Standalone v0.1-alpha */ -public final class ContactOperationProcessor implements ObjectProcessor { +public final class UserOperationProcessor implements ObjectProcessor { private static final ConnectionManager connectionManager = ConnectionManager.getInstance(); - private static final Logger logger = EnvoyLog.getLogger(ContactOperationProcessor.class); + private static final Logger logger = EnvoyLog.getLogger(UserOperationProcessor.class); private static final PersistenceManager persistenceManager = PersistenceManager.getInstance(); @Override @@ -38,35 +38,15 @@ public final class ContactOperationProcessor implements ObjectProcessor ((User) c).setLatestContactDeletion(Instant.now())); - } - } + // Notify the removed contact if online + if (connectionManager.isOnline(contactID)) + writeProxy.write(connectionManager.getSocketID(contactID), new UserOperation(sender.toCommon(), ElementOperation.REMOVE)); break; - default: - logger.warning(String.format("Received %s with an unsupported operation.", evt)); } } }