From a91181b4dd6d6062fe712af897be4837937d4c36 Mon Sep 17 00:00:00 2001 From: delvh Date: Tue, 13 Oct 2020 23:51:02 +0200 Subject: [PATCH] Fix several bugs These are: - not immediately updating ChatScene if a contact was blocked and both are online - ContactSearchTab showing previously entered text on reopening (without showing suggestions) - users not getting notified if someone else blocked them while they were offline - no logger statements in UserUtil Still to do: - Move ContextMenu from chatList to ChatControl - Test behavior for groups --- .../src/main/java/envoy/client/data/Chat.java | 4 +- .../main/java/envoy/client/data/LocalDB.java | 39 +++++++++++++------ .../envoy/client/ui/controller/ChatScene.java | 3 +- .../ui/controller/ContactSearchTab.java | 5 ++- .../ui/controller/GroupCreationTab.java | 6 +-- .../main/java/envoy/client/util/UserUtil.java | 9 ++++- 6 files changed, 45 insertions(+), 21 deletions(-) diff --git a/client/src/main/java/envoy/client/data/Chat.java b/client/src/main/java/envoy/client/data/Chat.java index ba40bbe..d8b2ee8 100644 --- a/client/src/main/java/envoy/client/data/Chat.java +++ b/client/src/main/java/envoy/client/data/Chat.java @@ -57,7 +57,9 @@ public class Chat implements Serializable { } @Override - public String toString() { return String.format("%s[recipient=%s,messages=%d]", getClass().getSimpleName(), recipient, messages.size()); } + public String toString() { + return String.format("%s[recipient=%s,messages=%d, disabled=%b]", getClass().getSimpleName(), recipient, messages.size(), disabled); + } /** * Generates a hash code based on the recipient. diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index 691a878..28b7ccd 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -1,11 +1,14 @@ package envoy.client.data; +import static java.util.function.Predicate.not; + import java.io.*; import java.nio.channels.*; import java.nio.file.StandardOpenOption; import java.time.Instant; import java.util.*; import java.util.logging.*; +import java.util.stream.Stream; import javafx.application.Platform; import javafx.collections.*; @@ -35,12 +38,13 @@ public final class LocalDB implements EventListener { // Data private User user; - private Map users = Collections.synchronizedMap(new HashMap<>()); - private ObservableList chats = FXCollections.observableArrayList(); + private Map users = Collections.synchronizedMap(new HashMap<>()); + private ObservableList chats = FXCollections.observableArrayList(); private IDGenerator idGenerator; - private CacheMap cacheMap = new CacheMap(); + private CacheMap cacheMap = new CacheMap(); private String authToken; - private Set originalContacts = Set.of(); + private boolean contactsChanged; + private Stream changedChats; // Auto save timer private Timer autoSaver; @@ -138,7 +142,19 @@ public final class LocalDB implements EventListener { if (user == null) throw new IllegalStateException("Client user is null, cannot initialize user storage"); userFile = new File(dbDir, user.getID() + ".db"); try (var in = new ObjectInputStream(new FileInputStream(userFile))) { - chats = FXCollections.observableList((List) in.readObject()); + chats = FXCollections.observableList((List) in.readObject()); + + // Some chats have changed and should not be overridden by the saved values + if (changedChats != null) { + changedChats.forEach(chat -> { + final var chatIndex = chats.indexOf(chat); + if (chatIndex == -1) return; + else chats.set(chatIndex, chat); + }); + + // loadUserData can get called two (or more?) times during application lifecycle + changedChats = null; + } cacheMap = (CacheMap) in.readObject(); lastSync = (Instant) in.readObject(); } finally { @@ -324,7 +340,7 @@ public final class LocalDB implements EventListener { private void onOwnStatusChange(OwnStatusChange statusChange) { user.setStatus(statusChange.get()); } @Event(eventType = ContactsChangedSinceLastLogin.class, priority = 500) - private void onContactsChangedSinceLastLogin() { if (user != null) originalContacts = user.getContacts(); } + private void onContactsChangedSinceLastLogin() { if (user != null) contactsChanged = true; } /** * @return a {@code Map} of all users stored locally with their @@ -363,13 +379,12 @@ public final class LocalDB implements EventListener { */ public void setUserAndMergeContacts(User user) { this.user = user; - if (originalContacts.isEmpty()) return; - else { + if (contactsChanged) - // mark all chats of deleted contacts - originalContacts.removeAll(user.getContacts()); - originalContacts.forEach(contact -> getChat(contact.getID()).ifPresent(chat -> chat.setDisabled(true))); - } + // Mark chats as disabled if a contact is no longer in this users contact list + changedChats = chats.stream() + .filter(not(chat -> user.getContacts().contains(chat.getRecipient()))) + .peek(chat -> { chat.setDisabled(true); logger.log(Level.INFO, String.format("Marked %s as blocked.", chat.getRecipient())); }); } /** 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 4c98c76..ca845ed 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -272,8 +272,7 @@ public final class ChatScene implements EventListener, Restorable { @Event private void onUserOperation(UserOperation operation) { // All ADD dependant logic resides in LocalDB - if (operation.getOperationType().equals(ElementOperation.REMOVE)) - if (currentChat != null && currentChat.getRecipient().equals(operation.get())) Platform.runLater(this::resetState); + if (operation.getOperationType().equals(ElementOperation.REMOVE)) Platform.runLater(() -> disableChat(operation.get(), true)); } @Event diff --git a/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java b/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java index 380c549..a31b664 100644 --- a/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java +++ b/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java @@ -124,5 +124,8 @@ public class ContactSearchTab implements EventListener { } @FXML - private void backButtonClicked() { eventBus.dispatch(new BackEvent()); } + private void backButtonClicked() { + searchBar.setText(""); + eventBus.dispatch(new BackEvent()); + } } diff --git a/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java b/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java index d262214..ce085a7 100644 --- a/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java +++ b/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java @@ -82,7 +82,7 @@ public class GroupCreationTab implements EventListener { .map(User.class::cast) .collect(Collectors.toList())); resizeQuickSelectSpace(0); - quickSelectList.addEventFilter(MouseEvent.MOUSE_PRESSED, evt -> evt.consume()); + quickSelectList.addEventFilter(MouseEvent.MOUSE_PRESSED, MouseEvent::consume); } /** @@ -169,7 +169,7 @@ public class GroupCreationTab implements EventListener { /** * Removes an element from the quickSelectList. - * + * * @param element the element to be removed. * @since Envoy Client v0.3-beta */ @@ -238,7 +238,7 @@ public class GroupCreationTab implements EventListener { Platform.runLater(() -> { switch (operation.getOperationType()) { case ADD: - userList.getItems().add((User) operation.get()); + userList.getItems().add(operation.get()); break; case REMOVE: userList.getItems().removeIf(operation.get()::equals); diff --git a/client/src/main/java/envoy/client/util/UserUtil.java b/client/src/main/java/envoy/client/util/UserUtil.java index dc34455..8e38ae3 100644 --- a/client/src/main/java/envoy/client/util/UserUtil.java +++ b/client/src/main/java/envoy/client/util/UserUtil.java @@ -1,6 +1,6 @@ package envoy.client.util; -import java.util.logging.Level; +import java.util.logging.*; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; @@ -26,7 +26,8 @@ import dev.kske.eventbus.EventBus; */ public final class UserUtil { - private static final Context context = Context.getInstance(); + private static final Context context = Context.getInstance(); + private static final Logger logger = EnvoyLog.getLogger(UserUtil.class); private UserUtil() {} @@ -46,6 +47,7 @@ public final class UserUtil { EventBus.getInstance().dispatch(new EnvoyCloseEvent()); EventBus.getInstance().dispatch(new Logout()); context.getSceneContext().load(SceneInfo.LOGIN_SCENE); + logger.log(Level.INFO, "A logout occurred."); }); } @@ -63,6 +65,7 @@ public final class UserUtil { else { EventBus.getInstance().dispatch(new OwnStatusChange(newStatus)); if (context.getClient().isOnline()) context.getClient().send(new UserStatusChange(context.getLocalDB().getUser().getID(), newStatus)); + logger.log(Level.INFO, "A manual status change occurred."); } } @@ -87,6 +90,7 @@ public final class UserUtil { context.getLocalDB().getChat(block.getID()).ifPresent(chat -> chat.setDisabled(true)); final var controller = context.getSceneContext().getController(); if (controller instanceof ChatScene) ((ChatScene) controller).disableChat(block, true); + logger.log(Level.INFO, "A contact was blocked."); }); } } @@ -108,6 +112,7 @@ public final class UserUtil { context.getLocalDB().getChats().removeIf(chat -> chat.getRecipient().equals(delete)); if (context.getSceneContext().getController() instanceof ChatScene) ((ChatScene) context.getSceneContext().getController()).resetState(); + logger.log(Level.INFO, "A contact with all his messages was deleted."); }); } }