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:
Leon Hofmeister 2020-10-13 23:51:02 +02:00
parent 7bdcfad08c
commit a91181b4dd
Signed by: delvh
GPG Key ID: 3DECE05F6D9A647C
6 changed files with 45 additions and 21 deletions

View File

@ -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.

View File

@ -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())); });
} }
/** /**

View File

@ -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

View File

@ -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());
}
} }

View File

@ -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);

View File

@ -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.");
}); });
} }
} }