Merge pull request #174 from informatik-ag-ngl/f/groupMessages

Group Messages
This commit is contained in:
Kai S. K. Engelbart 2020-07-08 19:15:55 +00:00 committed by GitHub
commit 3e3d651b87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 277 additions and 79 deletions

View File

@ -24,10 +24,10 @@ import envoy.event.MessageStatusChange;
* @author Kai S. K. Engelbart * @author Kai S. K. Engelbart
* @since Envoy Client v0.1-alpha * @since Envoy Client v0.1-alpha
*/ */
public final class Chat implements Serializable { public class Chat implements Serializable {
private final Contact recipient; protected final Contact recipient;
private final List<Message> messages = new ArrayList<>(); protected final List<Message> messages = new ArrayList<>();
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -39,7 +39,9 @@ public final class Chat implements Serializable {
* @param recipient the user who receives the messages * @param recipient the user who receives the messages
* @since Envoy Client v0.1-alpha * @since Envoy Client v0.1-alpha
*/ */
public Chat(Contact recipient) { this.recipient = recipient; } public Chat(Contact recipient) {
this.recipient = recipient;
}
@Override @Override
public String toString() { return String.format("Chat[recipient=%s,messages=%d]", recipient, messages.size()); } public String toString() { return String.format("Chat[recipient=%s,messages=%d]", recipient, messages.size()); }

View File

@ -0,0 +1,54 @@
package envoy.client.data;
import java.io.IOException;
import java.time.LocalDateTime;
import envoy.client.net.WriteProxy;
import envoy.data.Contact;
import envoy.data.GroupMessage;
import envoy.data.Message.MessageStatus;
import envoy.data.User;
import envoy.event.GroupMessageStatusChange;
/**
* Represents a chat between a user and a group
* as a list of messages.
* <p>
* Project: <strong>envoy-client</strong><br>
* File: <strong>GroupChat.java</strong><br>
* Created: <strong>05.07.2020</strong><br>
*
* @author Maximilian K&auml;fer
* @since Envoy Client v0.1-beta
*/
public class GroupChat extends Chat {
private final User sender;
private static final long serialVersionUID = 1L;
/**
* @param sender the user sending the messages
* @param recipient the group whose members receive the messages
* @since Envoy Client v0.1-beta
*/
public GroupChat(User sender, Contact recipient) {
super(recipient);
this.sender = sender;
}
@Override
public void read(WriteProxy writeProxy) throws IOException {
for (int i = messages.size() - 1; i >= 0; --i) {
final GroupMessage gmsg = (GroupMessage) messages.get(i);
if (gmsg.getSenderID() != sender.getID()) {
if (gmsg.getMemberStatuses().get(sender.getID()) == MessageStatus.READ) break;
else {
gmsg.getMemberStatuses().replace(sender.getID(), MessageStatus.READ);
writeProxy
.writeMessageStatusChange(new GroupMessageStatusChange(gmsg.getID(), MessageStatus.READ, LocalDateTime.now(), sender.getID()));
}
}
}
}
}

View File

@ -82,7 +82,11 @@ public abstract class LocalDB {
getChat(contact.getID()).ifPresent(chat -> { ((User) chat.getRecipient()).setStatus(((User) contact).getStatus()); }); getChat(contact.getID()).ifPresent(chat -> { ((User) chat.getRecipient()).setStatus(((User) contact).getStatus()); });
// Create missing chats // Create missing chats
user.getContacts().stream().filter(u -> !u.equals(user) && getChat(u.getID()).isEmpty()).map(Chat::new).forEach(chats::add); user.getContacts()
.stream()
.filter(c -> !c.equals(user) && getChat(c.getID()).isEmpty())
.map(c -> c instanceof User ? new Chat(c) : new GroupChat(user, c))
.forEach(chats::add);
} }
/** /**

View File

@ -53,23 +53,34 @@ public class Client implements Closeable {
* will block for up to 5 seconds. If the handshake does exceed this time limit, * will block for up to 5 seconds. If the handshake does exceed this time limit,
* an exception is thrown. * an exception is thrown.
* *
* @param credentials the login credentials of the user * @param credentials the login credentials of the
* @param receivedMessageCache a message cache containing all unread * user
* messages * @param receivedMessageCache a message cache containing all
* from the server that can be relayed * unread messages from the server
* after * that can be relayed after
* initialization * initialization
* @param receivedMessageStatusChangeCache an event cache containing all * @param receivedGroupMessageCache a groupMessage cache containing
* received messageStatusChangeEvents * all unread groupMessages from
* from the server that can be relayed * the server that can be relayed
* after initialization * after initialization
* @param receivedMessageStatusChangeCache an event cache containing all
* received
* messageStatusChangeEvents from
* the server that can be relayed
* after initialization
* @param receivedGroupMessageStatusChangeCache an event cache containing all
* received
* groupMessageStatusChangeEvents
* from the server that can be
* relayed after initialization
* @throws TimeoutException if the server could not be reached * @throws TimeoutException if the server could not be reached
* @throws IOException if the login credentials could not be written * @throws IOException if the login credentials could not be written
* @throws InterruptedException if the current thread is interrupted while * @throws InterruptedException if the current thread is interrupted while
* waiting for the handshake response * waiting for the handshake response
*/ */
public void performHandshake(LoginCredentials credentials, Cache<Message> receivedMessageCache, public void performHandshake(LoginCredentials credentials, Cache<Message> receivedMessageCache, Cache<GroupMessage> receivedGroupMessageCache,
Cache<MessageStatusChange> receivedMessageStatusChangeCache) throws TimeoutException, IOException, InterruptedException { Cache<MessageStatusChange> receivedMessageStatusChangeCache, Cache<GroupMessageStatusChange> receivedGroupMessageStatusChangeCache)
throws TimeoutException, IOException, InterruptedException {
if (online) throw new IllegalStateException("Handshake has already been performed successfully"); if (online) throw new IllegalStateException("Handshake has already been performed successfully");
// Establish TCP connection // Establish TCP connection
@ -83,7 +94,9 @@ public class Client implements Closeable {
// Register user creation processor, contact list processor and message cache // Register user creation processor, contact list processor and message cache
receiver.registerProcessor(User.class, sender -> this.sender = sender); receiver.registerProcessor(User.class, sender -> this.sender = sender);
receiver.registerProcessor(Message.class, receivedMessageCache); receiver.registerProcessor(Message.class, receivedMessageCache);
receiver.registerProcessor(GroupMessage.class, receivedGroupMessageCache);
receiver.registerProcessor(MessageStatusChange.class, receivedMessageStatusChangeCache); receiver.registerProcessor(MessageStatusChange.class, receivedMessageStatusChangeCache);
receiver.registerProcessor(GroupMessageStatusChange.class, receivedGroupMessageStatusChangeCache);
receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); }); receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); });
rejected = false; rejected = false;
@ -122,38 +135,65 @@ public class Client implements Closeable {
* Initializes the {@link Receiver} used to process data sent from the server to * Initializes the {@link Receiver} used to process data sent from the server to
* this client. * this client.
* *
* @param localDB the local database used to persist * @param localDB the local database used to
* the current * persist
* {@link IDGenerator} * the current
* @param receivedMessageCache a message cache containing all unread * {@link IDGenerator}
* messages * @param receivedMessageCache a message cache containing all
* from the server that can be relayed * unread
* after * messages
* initialization * from the server that can be
* @param receivedMessageStatusChangeCache an event cache containing all * relayed
* received messageStatusChangeEvents * after
* from the server that can be relayed * initialization
* after initialization * @param receivedGroupMessageCache a groupMessage cache containing
* all
* unread
* groupMessages
* from the server that can be
* relayed
* after
* initialization
* @param receivedMessageStatusChangeCache an event cache containing all
* received
* messageStatusChangeEvents
* from the server that can be
* relayed
* after initialization
* @param receivedGroupMessageStatusChangeCache an event cache containing all
* received
* groupMessageStatusChangeEvents
* from the server that can be
* relayed after initialization
* @throws IOException if no {@link IDGenerator} is present and none could be * @throws IOException if no {@link IDGenerator} is present and none could be
* requested from the server * requested from the server
* @since Envoy Client v0.2-alpha * @since Envoy Client v0.2-alpha
*/ */
public void initReceiver(LocalDB localDB, Cache<Message> receivedMessageCache, Cache<MessageStatusChange> receivedMessageStatusChangeCache) public void initReceiver(LocalDB localDB, Cache<Message> receivedMessageCache, Cache<GroupMessage> receivedGroupMessageCache,
Cache<MessageStatusChange> receivedMessageStatusChangeCache, Cache<GroupMessageStatusChange> receivedGroupMessageStatusChangeCache)
throws IOException { throws IOException {
checkOnline(); checkOnline();
// Process incoming messages // Process incoming messages
final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor(); final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor();
final MessageStatusChangeProcessor messageStatusChangeEventProcessor = new MessageStatusChangeProcessor(); final ReceivedGroupMessageProcessor receivedGroupMessageProcessor = new ReceivedGroupMessageProcessor();
final MessageStatusChangeProcessor messageStatusChangeProcessor = new MessageStatusChangeProcessor();
final GroupMessageStatusChangeProcessor groupMessageStatusChangeProcessor = new GroupMessageStatusChangeProcessor();
receiver.registerProcessor(GroupMessage.class, receivedGroupMessageProcessor);
receiver.registerProcessor(Message.class, receivedMessageProcessor); receiver.registerProcessor(Message.class, receivedMessageProcessor);
// Relay cached unread messages receiver.registerProcessor(MessageStatusChange.class, messageStatusChangeProcessor);
receiver.registerProcessor(GroupMessageStatusChange.class, groupMessageStatusChangeProcessor);
// Relay cached unread messages and unread groupMessages
receivedMessageCache.setProcessor(receivedMessageProcessor); receivedMessageCache.setProcessor(receivedMessageProcessor);
receivedGroupMessageCache.setProcessor(receivedGroupMessageProcessor);
// Process message status changes // Process message status changes
receiver.registerProcessor(MessageStatusChange.class, messageStatusChangeEventProcessor); receivedMessageStatusChangeCache.setProcessor(messageStatusChangeProcessor);
receivedMessageStatusChangeCache.setProcessor(messageStatusChangeEventProcessor); receivedGroupMessageStatusChangeCache.setProcessor(groupMessageStatusChangeProcessor);
// Process user status changes // Process user status changes
receiver.registerProcessor(UserStatusChange.class, eventBus::dispatch); receiver.registerProcessor(UserStatusChange.class, eventBus::dispatch);

View File

@ -0,0 +1,29 @@
package envoy.client.net;
import java.util.function.Consumer;
import java.util.logging.Logger;
import envoy.data.Message.MessageStatus;
import envoy.event.EventBus;
import envoy.event.GroupMessageStatusChange;
import envoy.util.EnvoyLog;
/**
* Project: <strong>envoy-client</strong><br>
* File: <strong>GroupMessageStatusChangePocessor.java</strong><br>
* Created: <strong>03.07.2020</strong><br>
*
* @author Maximilian K&auml;fer
* @since Envoy Client v0.1-beta
*/
public class GroupMessageStatusChangeProcessor implements Consumer<GroupMessageStatusChange> {
private static final Logger logger = EnvoyLog.getLogger(GroupMessageStatusChangeProcessor.class);
@Override
public void accept(GroupMessageStatusChange evt) {
if (evt.get().ordinal() < MessageStatus.RECEIVED.ordinal()) logger.warning("Received invalid group message status change " + evt);
else EventBus.getInstance().dispatch(evt);
}
}

View File

@ -0,0 +1,33 @@
package envoy.client.net;
import java.util.function.Consumer;
import java.util.logging.Logger;
import envoy.client.event.MessageCreationEvent;
import envoy.data.GroupMessage;
import envoy.data.Message.MessageStatus;
import envoy.event.EventBus;
import envoy.util.EnvoyLog;
/**
* Project: <strong>envoy-client</strong><br>
* File: <strong>ReceivedGroupMessageProcessor.java</strong><br>
* Created: <strong>13.06.2020</strong><br>
*
* @author Maximilian K&auml;fer
* @since Envoy Client v0.1-beta
*/
public class ReceivedGroupMessageProcessor implements Consumer<GroupMessage> {
private static final Logger logger = EnvoyLog.getLogger(ReceivedGroupMessageProcessor.class);
@Override
public void accept(GroupMessage groupMessage) {
if (groupMessage.getStatus() == MessageStatus.WAITING || groupMessage.getStatus() == MessageStatus.READ)
logger.warning("The groupMessage has the unexpected status " + groupMessage.getStatus());
// Dispatch event
EventBus.getInstance().dispatch(new MessageCreationEvent(groupMessage));
}
}

View File

@ -78,8 +78,10 @@ public class Receiver extends Thread {
// Get appropriate processor // Get appropriate processor
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
final Consumer processor = processors.get(obj.getClass()); final Consumer processor = processors.get(obj.getClass());
if (processor == null) logger.log(Level.WARNING, if (processor == null)
String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); logger.log(Level.WARNING, String.format(
"The received object has the %s for which no processor is defined.",
obj.getClass()));
else processor.accept(obj); else processor.accept(obj);
} }
} catch (final SocketException e) { } catch (final SocketException e) {

View File

@ -15,7 +15,9 @@ import envoy.client.data.*;
import envoy.client.net.Client; import envoy.client.net.Client;
import envoy.client.ui.SceneContext.SceneInfo; import envoy.client.ui.SceneContext.SceneInfo;
import envoy.client.ui.controller.LoginScene; import envoy.client.ui.controller.LoginScene;
import envoy.data.GroupMessage;
import envoy.data.Message; import envoy.data.Message;
import envoy.event.GroupMessageStatusChange;
import envoy.event.MessageStatusChange; import envoy.event.MessageStatusChange;
import envoy.exception.EnvoyException; import envoy.exception.EnvoyException;
import envoy.util.EnvoyLog; import envoy.util.EnvoyLog;
@ -43,7 +45,9 @@ public final class Startup extends Application {
private LocalDB localDB; private LocalDB localDB;
private Client client; private Client client;
private Cache<Message> messageCache; private Cache<Message> messageCache;
private Cache<GroupMessage> groupMessageCache;
private Cache<MessageStatusChange> messageStatusCache; private Cache<MessageStatusChange> messageStatusCache;
private Cache<GroupMessageStatusChange> groupMessageStatusCache;
private static final ClientConfig config = ClientConfig.getInstance(); private static final ClientConfig config = ClientConfig.getInstance();
private static final Logger logger = EnvoyLog.getLogger(Startup.class); private static final Logger logger = EnvoyLog.getLogger(Startup.class);
@ -99,14 +103,17 @@ public final class Startup extends Application {
// Initialize client and unread message cache // Initialize client and unread message cache
client = new Client(); client = new Client();
messageCache = new Cache<>(); messageCache = new Cache<>();
groupMessageCache = new Cache<>();
messageStatusCache = new Cache<>(); messageStatusCache = new Cache<>();
groupMessageStatusCache = new Cache<>();
stage.setTitle("Envoy"); stage.setTitle("Envoy");
stage.getIcons().add(IconUtil.loadIcon("envoy_logo")); stage.getIcons().add(IconUtil.loadIcon("envoy_logo"));
final var sceneContext = new SceneContext(stage); final var sceneContext = new SceneContext(stage);
sceneContext.load(SceneInfo.LOGIN_SCENE); sceneContext.load(SceneInfo.LOGIN_SCENE);
sceneContext.<LoginScene>getController().initializeData(client, localDB, messageCache, messageStatusCache, sceneContext); sceneContext.<LoginScene>getController()
.initializeData(client, localDB, messageCache, groupMessageCache, messageStatusCache, groupMessageStatusCache, sceneContext);
} }
/** /**

View File

@ -17,9 +17,7 @@ import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import envoy.client.data.Chat; import envoy.client.data.*;
import envoy.client.data.LocalDB;
import envoy.client.data.Settings;
import envoy.client.data.audio.AudioRecorder; import envoy.client.data.audio.AudioRecorder;
import envoy.client.event.MessageCreationEvent; import envoy.client.event.MessageCreationEvent;
import envoy.client.net.Client; import envoy.client.net.Client;
@ -32,9 +30,7 @@ import envoy.client.ui.listcell.MessageControl;
import envoy.client.ui.listcell.MessageListCellFactory; import envoy.client.ui.listcell.MessageListCellFactory;
import envoy.data.*; import envoy.data.*;
import envoy.data.Attachment.AttachmentType; import envoy.data.Attachment.AttachmentType;
import envoy.event.EventBus; import envoy.event.*;
import envoy.event.MessageStatusChange;
import envoy.event.UserStatusChange;
import envoy.event.contact.ContactOperation; import envoy.event.contact.ContactOperation;
import envoy.exception.EnvoyException; import envoy.exception.EnvoyException;
import envoy.util.EnvoyLog; import envoy.util.EnvoyLog;
@ -116,9 +112,8 @@ public final class ChatScene implements Restorable {
// Listen to received messages // Listen to received messages
eventBus.register(MessageCreationEvent.class, e -> { eventBus.register(MessageCreationEvent.class, e -> {
final var message = e.get(); final var message = e.get();
localDB.getChat(message.getSenderID()).ifPresent(chat -> { localDB.getChat(message instanceof GroupMessage ? message.getRecipientID() : message.getSenderID()).ifPresent(chat -> {
chat.insert(message); chat.insert(message);
if (chat.equals(currentChat)) { if (chat.equals(currentChat)) {
try { try {
currentChat.read(writeProxy); currentChat.read(writeProxy);
@ -133,11 +128,17 @@ public final class ChatScene implements Restorable {
// Listen to message status changes // Listen to message status changes
eventBus.register(MessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(message -> { eventBus.register(MessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(message -> {
message.setStatus(e.get()); message.setStatus(e.get());
// Update UI if in current chat // Update UI if in current chat
if (currentChat != null && message.getSenderID() == currentChat.getRecipient().getID()) Platform.runLater(messageList::refresh); if (currentChat != null && message.getSenderID() == currentChat.getRecipient().getID()) Platform.runLater(messageList::refresh);
})); }));
eventBus.register(GroupMessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(groupMessage -> {
((GroupMessage) groupMessage).getMemberStatuses().replace(e.getMemberID(), e.get());
// Update UI if in current chat
if (currentChat != null && groupMessage.getRecipientID() == currentChat.getRecipient().getID()) Platform.runLater(messageList::refresh);
}));
// Listen to user status changes // Listen to user status changes
eventBus.register(UserStatusChange.class, eventBus.register(UserStatusChange.class,
e -> userList.getItems() e -> userList.getItems()
@ -152,7 +153,7 @@ public final class ChatScene implements Restorable {
switch (e.getOperationType()) { switch (e.getOperationType()) {
case ADD: case ADD:
localDB.getUsers().put(contact.getName(), contact); localDB.getUsers().put(contact.getName(), contact);
localDB.getChats().add(new Chat(contact)); localDB.getChats().add(contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact));
Platform.runLater(() -> userList.getItems().add(contact)); Platform.runLater(() -> userList.getItems().add(contact));
break; break;
case REMOVE: case REMOVE:
@ -354,8 +355,8 @@ public final class ChatScene implements Restorable {
} }
/** /**
* Sends a new message to the server based on the text entered in the * Sends a new {@link Message} or {@link GroupMessage} to the server based on
* messageTextArea. * the text entered in the {@code messageTextArea} and the given attachment.
* *
* @since Envoy Client v0.1-beta * @since Envoy Client v0.1-beta
*/ */
@ -371,15 +372,18 @@ public final class ChatScene implements Restorable {
} }
final var text = messageTextArea.getText().strip(); final var text = messageTextArea.getText().strip();
try { try {
// Create and send message // Creating the message and its metadata
final var builder = new MessageBuilder(localDB.getUser().getID(), currentChat.getRecipient().getID(), localDB.getIDGenerator()) final var builder = new MessageBuilder(localDB.getUser().getID(), currentChat.getRecipient().getID(), localDB.getIDGenerator())
.setText(text); .setText(text);
if (pendingAttachment != null) { // Setting an attachment, if present
if (pendingAttachment != null) {
builder.setAttachment(pendingAttachment); builder.setAttachment(pendingAttachment);
pendingAttachment = null; pendingAttachment = null;
attachmentView.setVisible(false); attachmentView.setVisible(false);
} }
final var message = builder.build(); // Building the final message
final var message = currentChat.getRecipient() instanceof Group ? builder.buildGroupMessage((Group) currentChat.getRecipient())
: builder.build();
// Send message // Send message
writeProxy.writeMessage(message); writeProxy.writeMessage(message);

View File

@ -16,13 +16,9 @@ import envoy.client.net.Client;
import envoy.client.ui.ClearableTextField; import envoy.client.ui.ClearableTextField;
import envoy.client.ui.SceneContext; import envoy.client.ui.SceneContext;
import envoy.client.ui.Startup; import envoy.client.ui.Startup;
import envoy.data.LoginCredentials; import envoy.data.*;
import envoy.data.Message;
import envoy.data.User;
import envoy.data.User.UserStatus; import envoy.data.User.UserStatus;
import envoy.event.EventBus; import envoy.event.*;
import envoy.event.HandshakeRejection;
import envoy.event.MessageStatusChange;
import envoy.exception.EnvoyException; import envoy.exception.EnvoyException;
import envoy.util.Bounds; import envoy.util.Bounds;
import envoy.util.EnvoyLog; import envoy.util.EnvoyLog;
@ -59,7 +55,9 @@ public final class LoginScene {
private Client client; private Client client;
private LocalDB localDB; private LocalDB localDB;
private Cache<Message> receivedMessageCache; private Cache<Message> receivedMessageCache;
private Cache<GroupMessage> receivedGroupMessageCache;
private Cache<MessageStatusChange> receivedMessageStatusChangeCache; private Cache<MessageStatusChange> receivedMessageStatusChangeCache;
private Cache<GroupMessageStatusChange> receivedGroupMessageStatusChangeCache;
private SceneContext sceneContext; private SceneContext sceneContext;
private static final Logger logger = EnvoyLog.getLogger(LoginScene.class); private static final Logger logger = EnvoyLog.getLogger(LoginScene.class);
@ -77,27 +75,40 @@ public final class LoginScene {
/** /**
* Loads the login dialog using the FXML file {@code LoginDialog.fxml}. * Loads the login dialog using the FXML file {@code LoginDialog.fxml}.
* *
* @param client the client used to perform the * @param client the client used to perform the
* handshake * handshake
* @param localDB the local database used for offline * @param localDB the local database used for
* login * offline
* @param receivedMessageCache the cache storing messages received * login
* during * @param receivedMessageCache the cache storing messages
* the handshake * received
* @param receivedMessageStatusChangeCache the cache storing * during
* messageStatusChangeEvents received * the handshake
* during handshake * @param receivedGroupMessageCache the cache storing groupMessages
* @param sceneContext the scene context used to initialize * received during the handshake
* the chat * @param receivedMessageStatusChangeCache the cache storing
* scene * messageStatusChangeEvents
* received
* during handshake
* @param receivedGroupMessageStatusChangeCache the cache storing
* groupMessageStatusChangeEvents
* received
* during handshake
* @param sceneContext the scene context used to
* initialize
* the chat
* scene
* @since Envoy Client v0.1-beta * @since Envoy Client v0.1-beta
*/ */
public void initializeData(Client client, LocalDB localDB, Cache<Message> receivedMessageCache, public void initializeData(Client client, LocalDB localDB, Cache<Message> receivedMessageCache, Cache<GroupMessage> receivedGroupMessageCache,
Cache<MessageStatusChange> receivedMessageStatusChangeCache, SceneContext sceneContext) { Cache<MessageStatusChange> receivedMessageStatusChangeCache, Cache<GroupMessageStatusChange> receivedGroupMessageStatusChangeCache,
SceneContext sceneContext) {
this.client = client; this.client = client;
this.localDB = localDB; this.localDB = localDB;
this.receivedMessageCache = receivedMessageCache; this.receivedMessageCache = receivedMessageCache;
this.receivedGroupMessageCache = receivedGroupMessageCache;
this.receivedMessageStatusChangeCache = receivedMessageStatusChangeCache; this.receivedMessageStatusChangeCache = receivedMessageStatusChangeCache;
this.receivedGroupMessageStatusChangeCache = receivedGroupMessageStatusChangeCache;
this.sceneContext = sceneContext; this.sceneContext = sceneContext;
// Prepare handshake // Prepare handshake
@ -146,9 +157,17 @@ public final class LoginScene {
private void performHandshake(LoginCredentials credentials) { private void performHandshake(LoginCredentials credentials) {
try { try {
client.performHandshake(credentials, receivedMessageCache, receivedMessageStatusChangeCache); client.performHandshake(credentials,
receivedMessageCache,
receivedGroupMessageCache,
receivedMessageStatusChangeCache,
receivedGroupMessageStatusChangeCache);
if (client.isOnline()) { if (client.isOnline()) {
client.initReceiver(localDB, receivedMessageCache, receivedMessageStatusChangeCache); client.initReceiver(localDB,
receivedMessageCache,
receivedGroupMessageCache,
receivedMessageStatusChangeCache,
receivedGroupMessageStatusChangeCache);
loadChatScene(); loadChatScene();
} }
} catch (IOException | InterruptedException | TimeoutException e) { } catch (IOException | InterruptedException | TimeoutException e) {
@ -212,6 +231,8 @@ public final class LoginScene {
// Relay unread messages from cache // Relay unread messages from cache
if (receivedMessageCache != null && client.isOnline()) receivedMessageCache.relay(); if (receivedMessageCache != null && client.isOnline()) receivedMessageCache.relay();
if (receivedGroupMessageCache != null && client.isOnline()) receivedGroupMessageCache.relay();
if (receivedMessageStatusChangeCache != null && client.isOnline()) receivedMessageStatusChangeCache.relay(); if (receivedMessageStatusChangeCache != null && client.isOnline()) receivedMessageStatusChangeCache.relay();
if (receivedGroupMessageStatusChangeCache != null && client.isOnline()) receivedGroupMessageStatusChangeCache.relay();
} }
} }

View File

@ -57,12 +57,14 @@ public class MessageControl extends VBox {
textLabel.setWrapText(true); textLabel.setWrapText(true);
getChildren().add(textLabel); getChildren().add(textLabel);
// Setting the message status icon and background color // Setting the message status icon and background color
if (message.getRecipientID() != client.getID()) { if (message.getSenderID() == client.getID()) {
final var statusIcon = new ImageView(statusImages.get(message.getStatus())); final var statusIcon = new ImageView(statusImages.get(message.getStatus()));
statusIcon.setPreserveRatio(true); statusIcon.setPreserveRatio(true);
getChildren().add(statusIcon); getChildren().add(statusIcon);
getStyleClass().add("own-message"); getStyleClass().add("own-message");
} else getStyleClass().add("received-message"); } else {
getStyleClass().add("received-message");
}
// Adjusting height and weight of the cell to the corresponding ListView // Adjusting height and weight of the cell to the corresponding ListView
paddingProperty().setValue(new Insets(5, 20, 5, 20)); paddingProperty().setValue(new Insets(5, 20, 5, 20));
} }