Added IsWriting event on common, server and partially on client side
additionally fixed NullPointerException in ContactSearchScene and typo in Javadoc PS: this is the 1000th commit in Envoy! 🥳 🎉
This commit is contained in:
parent
72d1e074f4
commit
6f8859c3fd
@ -9,6 +9,7 @@ import java.util.Objects;
|
|||||||
import envoy.client.net.WriteProxy;
|
import envoy.client.net.WriteProxy;
|
||||||
import envoy.data.*;
|
import envoy.data.*;
|
||||||
import envoy.data.Message.MessageStatus;
|
import envoy.data.Message.MessageStatus;
|
||||||
|
import envoy.event.IsWriting;
|
||||||
import envoy.event.MessageStatusChange;
|
import envoy.event.MessageStatusChange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,6 +32,12 @@ public class Chat implements Serializable {
|
|||||||
|
|
||||||
protected int unreadAmount;
|
protected int unreadAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the milliseconds until another {@link IsWriting} event will be sent if
|
||||||
|
* something is typed.
|
||||||
|
*/
|
||||||
|
protected transient long lastWritingEvent;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,16 +48,14 @@ public 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) {
|
public Chat(Contact recipient) { this.recipient = 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()); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a hash code based on the recipient.
|
* Generates a hash code based on the recipient.
|
||||||
*
|
*
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -58,14 +63,14 @@ public class Chat implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests equality to another object based on the recipient.
|
* Tests equality to another object based on the recipient.
|
||||||
*
|
*
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) return true;
|
if (this == obj) return true;
|
||||||
if (!(obj instanceof Chat)) return false;
|
if (!(obj instanceof Chat)) return false;
|
||||||
Chat other = (Chat) obj;
|
final Chat other = (Chat) obj;
|
||||||
return Objects.equals(recipient, other.recipient);
|
return Objects.equals(recipient, other.recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +106,7 @@ public class Chat implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a message at the correct place according to its creation date.
|
* Inserts a message at the correct place according to its creation date.
|
||||||
*
|
*
|
||||||
* @param message the message to insert
|
* @param message the message to insert
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
@ -116,13 +121,13 @@ public class Chat implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments the amount of unread messages.
|
* Increments the amount of unread messages.
|
||||||
*
|
*
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
public void incrementUnreadAmount() { unreadAmount++; }
|
public void incrementUnreadAmount() { unreadAmount++; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the amount of unread mesages in this chat
|
* @return the amount of unread messages in this chat
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
public int getUnreadAmount() { return unreadAmount; }
|
public int getUnreadAmount() { return unreadAmount; }
|
||||||
@ -150,4 +155,17 @@ public class Chat implements Serializable {
|
|||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
public boolean isGroupChat() { return recipient instanceof Group; }
|
public boolean isGroupChat() { return recipient instanceof Group; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the last known time a {@link IsWriting} event has been sent
|
||||||
|
* @since Envoy Client v0.2-beta
|
||||||
|
*/
|
||||||
|
public long getLastWritingEvent() { return lastWritingEvent; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@code lastWritingEvent} to {@code System#currentTimeMillis()}.
|
||||||
|
*
|
||||||
|
* @since Envoy Client v0.2-beta
|
||||||
|
*/
|
||||||
|
public void lastWritingEventWasNow() { lastWritingEvent = System.currentTimeMillis(); }
|
||||||
}
|
}
|
||||||
|
@ -155,6 +155,9 @@ public class Client implements Closeable {
|
|||||||
// Process group size changes
|
// Process group size changes
|
||||||
receiver.registerProcessor(GroupResize.class, evt -> { localDB.updateGroup(evt); eventBus.dispatch(evt); });
|
receiver.registerProcessor(GroupResize.class, evt -> { localDB.updateGroup(evt); eventBus.dispatch(evt); });
|
||||||
|
|
||||||
|
// Process IsWriting events
|
||||||
|
receiver.registerProcessor(IsWriting.class, eventBus::dispatch);
|
||||||
|
|
||||||
// Send event
|
// Send event
|
||||||
eventBus.register(SendEvent.class, evt -> {
|
eventBus.register(SendEvent.class, evt -> {
|
||||||
try {
|
try {
|
||||||
|
@ -33,6 +33,7 @@ import envoy.client.data.audio.AudioRecorder;
|
|||||||
import envoy.client.data.commands.SystemCommandBuilder;
|
import envoy.client.data.commands.SystemCommandBuilder;
|
||||||
import envoy.client.data.commands.SystemCommandsMap;
|
import envoy.client.data.commands.SystemCommandsMap;
|
||||||
import envoy.client.event.MessageCreationEvent;
|
import envoy.client.event.MessageCreationEvent;
|
||||||
|
import envoy.client.event.SendEvent;
|
||||||
import envoy.client.net.Client;
|
import envoy.client.net.Client;
|
||||||
import envoy.client.net.WriteProxy;
|
import envoy.client.net.WriteProxy;
|
||||||
import envoy.client.ui.*;
|
import envoy.client.ui.*;
|
||||||
@ -444,10 +445,28 @@ public final class ChatScene implements Restorable {
|
|||||||
private void checkKeyCombination(KeyEvent e) {
|
private void checkKeyCombination(KeyEvent e) {
|
||||||
// Checks whether the text is too long
|
// Checks whether the text is too long
|
||||||
messageTextUpdated();
|
messageTextUpdated();
|
||||||
|
// Sending an IsWriting event if none has been sent for
|
||||||
|
// IsWriting#millisecondsActive
|
||||||
|
if (client.isOnline() && currentChat.getLastWritingEvent() + IsWriting.millisecondsActive <= System.currentTimeMillis()) {
|
||||||
|
eventBus.dispatch(new SendEvent(new IsWriting(getChatID(), currentChat.getRecipient().getID(), client.getSender().getName())));
|
||||||
|
currentChat.lastWritingEventWasNow();
|
||||||
|
}
|
||||||
// Automatic sending of messages via (ctrl +) enter
|
// Automatic sending of messages via (ctrl +) enter
|
||||||
checkPostConditions(e);
|
checkPostConditions(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the id that should be used to send things to the server:
|
||||||
|
* the id of 'our' {@link User} if the recipient of that object is another User,
|
||||||
|
* else the id of the {@link Group} 'our' user is sending to.
|
||||||
|
*
|
||||||
|
* @return an id that can be sent to the server
|
||||||
|
* @since Envoy Client v0.2-beta
|
||||||
|
*/
|
||||||
|
private long getChatID() {
|
||||||
|
return currentChat.getRecipient() instanceof User ? client.getSender().getID() : currentChat.getRecipient().getID();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param e the keys that have been pressed
|
* @param e the keys that have been pressed
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
@ -515,7 +534,7 @@ public final class ChatScene implements Restorable {
|
|||||||
updateInfoLabel("You need to go online to send more messages", "infoLabel-error");
|
updateInfoLabel("You need to go online to send more messages", "infoLabel-error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final var text = messageTextArea.getText().strip();
|
final var text = messageTextArea.getText().strip();
|
||||||
if (!messageTextAreaCommands.executeIfAnyPresent(text)) try {
|
if (!messageTextAreaCommands.executeIfAnyPresent(text)) try {
|
||||||
// Creating the message and its metadata
|
// 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())
|
||||||
|
@ -60,8 +60,10 @@ public class ContactSearchScene {
|
|||||||
|
|
||||||
private final Consumer<ContactOperation> handler = e -> {
|
private final Consumer<ContactOperation> handler = e -> {
|
||||||
final var contact = e.get();
|
final var contact = e.get();
|
||||||
if (e.getOperationType() == ElementOperation.ADD) Platform
|
if (e.getOperationType() == ElementOperation.ADD) Platform.runLater(() -> {
|
||||||
.runLater(() -> { userList.getItems().remove(contact); if (currentlySelectedUser.equals(contact) && alert.isShowing()) alert.close(); });
|
userList.getItems().remove(contact);
|
||||||
|
if (currentlySelectedUser != null && currentlySelectedUser.equals(contact) && alert.isShowing()) alert.close();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final EventBus eventBus = EventBus.getInstance();
|
private static final EventBus eventBus = EventBus.getInstance();
|
||||||
|
@ -138,7 +138,7 @@ public final class LoginScene {
|
|||||||
localDB.setUser(localDB.getUsers().get(identifier));
|
localDB.setUser(localDB.getUsers().get(identifier));
|
||||||
localDB.initializeUserStorage();
|
localDB.initializeUserStorage();
|
||||||
localDB.loadUserData();
|
localDB.loadUserData();
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
// User storage empty, wrong user name etc. -> default lastSync
|
// User storage empty, wrong user name etc. -> default lastSync
|
||||||
}
|
}
|
||||||
return localDB.getLastSync();
|
return localDB.getLastSync();
|
||||||
@ -161,7 +161,7 @@ public final class LoginScene {
|
|||||||
try {
|
try {
|
||||||
// Try entering offline mode
|
// Try entering offline mode
|
||||||
localDB.loadUsers();
|
localDB.loadUsers();
|
||||||
final User clientUser = (User) localDB.getUsers().get(credentials.getIdentifier());
|
final User clientUser = localDB.getUsers().get(credentials.getIdentifier());
|
||||||
if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown");
|
if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown");
|
||||||
client.setSender(clientUser);
|
client.setSender(clientUser);
|
||||||
loadChatScene();
|
loadChatScene();
|
||||||
@ -223,7 +223,7 @@ public final class LoginScene {
|
|||||||
// Initialize status tray icon
|
// Initialize status tray icon
|
||||||
final var trayIcon = new StatusTrayIcon(sceneContext.getStage());
|
final var trayIcon = new StatusTrayIcon(sceneContext.getStage());
|
||||||
settings.getItems().get("hideOnClose").setChangeHandler(c -> {
|
settings.getItems().get("hideOnClose").setChangeHandler(c -> {
|
||||||
if (((Boolean) c)) trayIcon.show();
|
if ((Boolean) c) trayIcon.show();
|
||||||
else trayIcon.hide();
|
else trayIcon.hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -31,12 +31,12 @@ public class ChatControl extends HBox {
|
|||||||
|
|
||||||
// Unread messages
|
// Unread messages
|
||||||
if (chat.getUnreadAmount() != 0) {
|
if (chat.getUnreadAmount() != 0) {
|
||||||
Region spacing = new Region();
|
final Region spacing = new Region();
|
||||||
setHgrow(spacing, Priority.ALWAYS);
|
setHgrow(spacing, Priority.ALWAYS);
|
||||||
getChildren().add(spacing);
|
getChildren().add(spacing);
|
||||||
final var unreadMessagesLabel = new Label(Integer.toString(chat.getUnreadAmount()));
|
final var unreadMessagesLabel = new Label(Integer.toString(chat.getUnreadAmount()));
|
||||||
unreadMessagesLabel.setMinSize(15, 15);
|
unreadMessagesLabel.setMinSize(15, 15);
|
||||||
var vBox2 = new VBox();
|
final var vBox2 = new VBox();
|
||||||
vBox2.setAlignment(Pos.CENTER_RIGHT);
|
vBox2.setAlignment(Pos.CENTER_RIGHT);
|
||||||
unreadMessagesLabel.setAlignment(Pos.CENTER);
|
unreadMessagesLabel.setAlignment(Pos.CENTER);
|
||||||
unreadMessagesLabel.getStyleClass().add("unreadMessagesAmount");
|
unreadMessagesLabel.getStyleClass().add("unreadMessagesAmount");
|
||||||
|
53
common/src/main/java/envoy/event/IsWriting.java
Normal file
53
common/src/main/java/envoy/event/IsWriting.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package envoy.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event should be sent when a user wrote anything in a chat.
|
||||||
|
* <p>
|
||||||
|
* Project: <strong>envoy-client</strong><br>
|
||||||
|
* File: <strong>IsWriting.java</strong><br>
|
||||||
|
* Created: <strong>24.07.2020</strong><br>
|
||||||
|
*
|
||||||
|
* @author Leon Hofmeister
|
||||||
|
* @since Envoy Client v0.2-beta
|
||||||
|
*/
|
||||||
|
public class IsWriting extends Event<Long> {
|
||||||
|
|
||||||
|
private final long destinationID;
|
||||||
|
|
||||||
|
private final String displayName;
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of milliseconds that this event will be active.<br>
|
||||||
|
* Currently set to 3.5 seconds.
|
||||||
|
*/
|
||||||
|
public static final int millisecondsActive = 3500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@code IsWriting} with originator and recipient.
|
||||||
|
*
|
||||||
|
* @param sourceID the id of the originator
|
||||||
|
* @param displayName the name of the originator
|
||||||
|
* @param destinationID the id of the contact the user wrote to
|
||||||
|
* @since Envoy Client v0.2-beta
|
||||||
|
*/
|
||||||
|
public IsWriting(Long sourceID, long destinationID, String displayName) {
|
||||||
|
super(sourceID);
|
||||||
|
this.destinationID = destinationID;
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id of the contact in whose chat the user wrote something
|
||||||
|
* @since Envoy Client v0.2-beta
|
||||||
|
*/
|
||||||
|
public long getDestinationID() { return destinationID; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of the originator to display
|
||||||
|
* @since Envoy Common v0.2-beta
|
||||||
|
*/
|
||||||
|
public String getDisplayName() { return displayName; }
|
||||||
|
|
||||||
|
}
|
@ -69,7 +69,8 @@ public class Startup {
|
|||||||
new UserStatusChangeProcessor(),
|
new UserStatusChangeProcessor(),
|
||||||
new IDGeneratorRequestProcessor(),
|
new IDGeneratorRequestProcessor(),
|
||||||
new UserSearchProcessor(),
|
new UserSearchProcessor(),
|
||||||
new ContactOperationProcessor())));
|
new ContactOperationProcessor(),
|
||||||
|
new IsWritingProcessor())));
|
||||||
|
|
||||||
// Initialize the current message ID
|
// Initialize the current message ID
|
||||||
final PersistenceManager persistenceManager = PersistenceManager.getInstance();
|
final PersistenceManager persistenceManager = PersistenceManager.getInstance();
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package envoy.server.processors;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import envoy.event.IsWriting;
|
||||||
|
import envoy.server.data.PersistenceManager;
|
||||||
|
import envoy.server.data.User;
|
||||||
|
import envoy.server.net.ConnectionManager;
|
||||||
|
import envoy.server.net.ObjectWriteProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This processor handles incoming {@link IsWriting}s.
|
||||||
|
* <p>
|
||||||
|
* Project: <strong>envoy-server-standalone</strong><br>
|
||||||
|
* File: <strong>IsWritingProcessor.java</strong><br>
|
||||||
|
* Created: <strong>24.07.2020</strong><br>
|
||||||
|
*
|
||||||
|
* @author Leon Hofmeister
|
||||||
|
* @since Envoy Server v0.2-beta
|
||||||
|
*/
|
||||||
|
public class IsWritingProcessor implements ObjectProcessor<IsWriting> {
|
||||||
|
|
||||||
|
private static final ConnectionManager connectionManager = ConnectionManager.getInstance();
|
||||||
|
private static final PersistenceManager persistenceManager = PersistenceManager.getInstance();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<IsWriting> getInputClass() { return IsWriting.class; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(IsWriting input, long socketID, ObjectWriteProxy writeProxy) throws IOException {
|
||||||
|
final var contact = persistenceManager.getContactByID(input.get());
|
||||||
|
if (contact instanceof User) {
|
||||||
|
final var destinationID = input.getDestinationID();
|
||||||
|
if (connectionManager.isOnline(destinationID)) writeProxy.write(connectionManager.getSocketID(destinationID), input);
|
||||||
|
} else writeProxy.writeToOnlineContacts(contact.getContacts(), input);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user