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
This commit is contained in:
		@@ -57,7 +57,9 @@ public class Chat implements Serializable {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@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.
 | 
						 * Generates a hash code based on the recipient.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,14 @@
 | 
				
			|||||||
package envoy.client.data;
 | 
					package envoy.client.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static java.util.function.Predicate.not;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.*;
 | 
					import java.io.*;
 | 
				
			||||||
import java.nio.channels.*;
 | 
					import java.nio.channels.*;
 | 
				
			||||||
import java.nio.file.StandardOpenOption;
 | 
					import java.nio.file.StandardOpenOption;
 | 
				
			||||||
import java.time.Instant;
 | 
					import java.time.Instant;
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.logging.*;
 | 
					import java.util.logging.*;
 | 
				
			||||||
 | 
					import java.util.stream.Stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.application.Platform;
 | 
					import javafx.application.Platform;
 | 
				
			||||||
import javafx.collections.*;
 | 
					import javafx.collections.*;
 | 
				
			||||||
@@ -35,12 +38,13 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Data
 | 
						// Data
 | 
				
			||||||
	private User					user;
 | 
						private User					user;
 | 
				
			||||||
	private Map<String, User>		users				= Collections.synchronizedMap(new HashMap<>());
 | 
						private Map<String, User>		users		= Collections.synchronizedMap(new HashMap<>());
 | 
				
			||||||
	private ObservableList<Chat>	chats				= FXCollections.observableArrayList();
 | 
						private ObservableList<Chat>	chats		= FXCollections.observableArrayList();
 | 
				
			||||||
	private IDGenerator				idGenerator;
 | 
						private IDGenerator				idGenerator;
 | 
				
			||||||
	private CacheMap				cacheMap			= new CacheMap();
 | 
						private CacheMap				cacheMap	= new CacheMap();
 | 
				
			||||||
	private String					authToken;
 | 
						private String					authToken;
 | 
				
			||||||
	private Set<? extends Contact>	originalContacts	= Set.of();
 | 
						private boolean					contactsChanged;
 | 
				
			||||||
 | 
						private Stream<Chat>			changedChats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Auto save timer
 | 
						// Auto save timer
 | 
				
			||||||
	private Timer	autoSaver;
 | 
						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");
 | 
							if (user == null) throw new IllegalStateException("Client user is null, cannot initialize user storage");
 | 
				
			||||||
		userFile = new File(dbDir, user.getID() + ".db");
 | 
							userFile = new File(dbDir, user.getID() + ".db");
 | 
				
			||||||
		try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
 | 
							try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
 | 
				
			||||||
			chats		= FXCollections.observableList((List<Chat>) in.readObject());
 | 
								chats = FXCollections.observableList((List<Chat>) 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();
 | 
								cacheMap	= (CacheMap) in.readObject();
 | 
				
			||||||
			lastSync	= (Instant) in.readObject();
 | 
								lastSync	= (Instant) in.readObject();
 | 
				
			||||||
		} finally {
 | 
							} finally {
 | 
				
			||||||
@@ -324,7 +340,7 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	private void onOwnStatusChange(OwnStatusChange statusChange) { user.setStatus(statusChange.get()); }
 | 
						private void onOwnStatusChange(OwnStatusChange statusChange) { user.setStatus(statusChange.get()); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Event(eventType = ContactsChangedSinceLastLogin.class, priority = 500)
 | 
						@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<String, User>} of all users stored locally with their
 | 
						 * @return a {@code Map<String, User>} of all users stored locally with their
 | 
				
			||||||
@@ -363,13 +379,12 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void setUserAndMergeContacts(User user) {
 | 
						public void setUserAndMergeContacts(User user) {
 | 
				
			||||||
		this.user = user;
 | 
							this.user = user;
 | 
				
			||||||
		if (originalContacts.isEmpty()) return;
 | 
							if (contactsChanged)
 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// mark all chats of deleted contacts
 | 
								// Mark chats as disabled if a contact is no longer in this users contact list
 | 
				
			||||||
			originalContacts.removeAll(user.getContacts());
 | 
								changedChats = chats.stream()
 | 
				
			||||||
			originalContacts.forEach(contact -> getChat(contact.getID()).ifPresent(chat -> chat.setDisabled(true)));
 | 
									.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())); });
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -272,8 +272,7 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
	@Event
 | 
						@Event
 | 
				
			||||||
	private void onUserOperation(UserOperation operation) {
 | 
						private void onUserOperation(UserOperation operation) {
 | 
				
			||||||
		// All ADD dependant logic resides in LocalDB
 | 
							// All ADD dependant logic resides in LocalDB
 | 
				
			||||||
		if (operation.getOperationType().equals(ElementOperation.REMOVE))
 | 
							if (operation.getOperationType().equals(ElementOperation.REMOVE)) Platform.runLater(() -> disableChat(operation.get(), true));
 | 
				
			||||||
			if (currentChat != null && currentChat.getRecipient().equals(operation.get())) Platform.runLater(this::resetState);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Event
 | 
						@Event
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,5 +124,8 @@ public class ContactSearchTab implements EventListener {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private void backButtonClicked() { eventBus.dispatch(new BackEvent()); }
 | 
						private void backButtonClicked() {
 | 
				
			||||||
 | 
							searchBar.setText("");
 | 
				
			||||||
 | 
							eventBus.dispatch(new BackEvent());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,7 +82,7 @@ public class GroupCreationTab implements EventListener {
 | 
				
			|||||||
				.map(User.class::cast)
 | 
									.map(User.class::cast)
 | 
				
			||||||
				.collect(Collectors.toList()));
 | 
									.collect(Collectors.toList()));
 | 
				
			||||||
		resizeQuickSelectSpace(0);
 | 
							resizeQuickSelectSpace(0);
 | 
				
			||||||
		quickSelectList.addEventFilter(MouseEvent.MOUSE_PRESSED, evt -> evt.consume());
 | 
							quickSelectList.addEventFilter(MouseEvent.MOUSE_PRESSED, MouseEvent::consume);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -238,7 +238,7 @@ public class GroupCreationTab implements EventListener {
 | 
				
			|||||||
		Platform.runLater(() -> {
 | 
							Platform.runLater(() -> {
 | 
				
			||||||
			switch (operation.getOperationType()) {
 | 
								switch (operation.getOperationType()) {
 | 
				
			||||||
				case ADD:
 | 
									case ADD:
 | 
				
			||||||
					userList.getItems().add((User) operation.get());
 | 
										userList.getItems().add(operation.get());
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case REMOVE:
 | 
									case REMOVE:
 | 
				
			||||||
					userList.getItems().removeIf(operation.get()::equals);
 | 
										userList.getItems().removeIf(operation.get()::equals);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package envoy.client.util;
 | 
					package envoy.client.util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.scene.control.Alert;
 | 
					import javafx.scene.control.Alert;
 | 
				
			||||||
import javafx.scene.control.Alert.AlertType;
 | 
					import javafx.scene.control.Alert.AlertType;
 | 
				
			||||||
@@ -26,7 +26,8 @@ import dev.kske.eventbus.EventBus;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public final class UserUtil {
 | 
					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() {}
 | 
						private UserUtil() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,6 +47,7 @@ public final class UserUtil {
 | 
				
			|||||||
			EventBus.getInstance().dispatch(new EnvoyCloseEvent());
 | 
								EventBus.getInstance().dispatch(new EnvoyCloseEvent());
 | 
				
			||||||
			EventBus.getInstance().dispatch(new Logout());
 | 
								EventBus.getInstance().dispatch(new Logout());
 | 
				
			||||||
			context.getSceneContext().load(SceneInfo.LOGIN_SCENE);
 | 
								context.getSceneContext().load(SceneInfo.LOGIN_SCENE);
 | 
				
			||||||
 | 
								logger.log(Level.INFO, "A logout occurred.");
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,6 +65,7 @@ public final class UserUtil {
 | 
				
			|||||||
		else {
 | 
							else {
 | 
				
			||||||
			EventBus.getInstance().dispatch(new OwnStatusChange(newStatus));
 | 
								EventBus.getInstance().dispatch(new OwnStatusChange(newStatus));
 | 
				
			||||||
			if (context.getClient().isOnline()) context.getClient().send(new UserStatusChange(context.getLocalDB().getUser().getID(), 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));
 | 
									context.getLocalDB().getChat(block.getID()).ifPresent(chat -> chat.setDisabled(true));
 | 
				
			||||||
				final var controller = context.getSceneContext().getController();
 | 
									final var controller = context.getSceneContext().getController();
 | 
				
			||||||
				if (controller instanceof ChatScene) ((ChatScene) controller).disableChat(block, true);
 | 
									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));
 | 
									context.getLocalDB().getChats().removeIf(chat -> chat.getRecipient().equals(delete));
 | 
				
			||||||
				if (context.getSceneContext().getController() instanceof ChatScene)
 | 
									if (context.getSceneContext().getController() instanceof ChatScene)
 | 
				
			||||||
					((ChatScene) context.getSceneContext().getController()).resetState();
 | 
										((ChatScene) context.getSceneContext().getController()).resetState();
 | 
				
			||||||
 | 
									logger.log(Level.INFO, "A contact with all his messages was deleted.");
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user