diff --git a/pom.xml b/pom.xml index 59bb365..d036d0d 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - f~groups-SNAPSHOT + develop-SNAPSHOT org.openjfx diff --git a/src/main/java/envoy/client/data/LocalDB.java b/src/main/java/envoy/client/data/LocalDB.java index 60bf7c0..38aeea4 100644 --- a/src/main/java/envoy/client/data/LocalDB.java +++ b/src/main/java/envoy/client/data/LocalDB.java @@ -200,4 +200,13 @@ public abstract class LocalDB { } }); } + + /** + * Creates a new {@link Chat} for all {@link Contact}s that do not have a chat. + * + * @since Envoy Client v0.1-beta + */ + public void createMissingChats() { + users.values().stream().filter(u -> !u.equals(user) && getChat(u.getID()).isEmpty()).map(Chat::new).forEach(chats::add); + } } diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 7aaf28b..9f9dad7 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -60,13 +60,15 @@ public class Client implements Closeable { * @param receivedMessageCache a message cache containing all unread messages * from the server that can be relayed after * initialization + * @param receivedMessageStatusChangeEventCache an event cache containing all received messageStatusChangeEvents from the server that can be relayed after initialization * @throws TimeoutException if the server could not be reached * @throws IOException if the login credentials could not be * written * @throws InterruptedException if the current thread is interrupted while * waiting for the handshake response */ - public void performHandshake(LoginCredentials credentials, Cache receivedMessageCache) + public void performHandshake(LoginCredentials credentials, Cache receivedMessageCache, + Cache receivedMessageStatusChangeEventCache) throws TimeoutException, IOException, InterruptedException { if (online) throw new IllegalStateException("Handshake has already been performed successfully"); // Establish TCP connection @@ -80,6 +82,7 @@ public class Client implements Closeable { // Register user creation processor, contact list processor and message cache receiver.registerProcessor(User.class, sender -> { this.sender = sender; contacts = sender.getContacts(); }); receiver.registerProcessor(Message.class, receivedMessageCache); + receiver.registerProcessor(MessageStatusChangeEvent.class, receivedMessageStatusChangeEventCache); receiver.registerProcessor(HandshakeRejectionEvent.class, evt -> { rejected = true; eventBus.dispatch(evt); }); rejected = false; @@ -123,22 +126,27 @@ public class Client implements Closeable { * @param receivedMessageCache a message cache containing all unread messages * from the server that can be relayed after * initialization + * @param receivedMessageStatusChangeEventCache an event cache containing all received messageStatusChangeEvents from the server that can be relayed after initialization * @throws IOException if no {@link IDGenerator} is present and none could be * requested from the server * @since Envoy Client v0.2-alpha */ - public void initReceiver(LocalDB localDB, Cache receivedMessageCache) throws IOException { + public void initReceiver(LocalDB localDB, Cache receivedMessageCache, + Cache receivedMessageStatusChangeEventCache) throws IOException { checkOnline(); // Process incoming messages final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor(); + final MessageStatusChangeEventProcessor messageStatusChangeEventProcessor = new MessageStatusChangeEventProcessor(); + receiver.registerProcessor(Message.class, receivedMessageProcessor); // Relay cached unread messages receivedMessageCache.setProcessor(receivedMessageProcessor); // Process message status changes - receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor()); + receiver.registerProcessor(MessageStatusChangeEvent.class, messageStatusChangeEventProcessor); + receivedMessageStatusChangeEventCache.setProcessor(messageStatusChangeEventProcessor); // Process user status changes receiver.registerProcessor(UserStatusChangeEvent.class, eventBus::dispatch); diff --git a/src/main/java/envoy/client/ui/SceneContext.java b/src/main/java/envoy/client/ui/SceneContext.java index c191d8e..ea3b4b2 100644 --- a/src/main/java/envoy/client/ui/SceneContext.java +++ b/src/main/java/envoy/client/ui/SceneContext.java @@ -58,6 +58,13 @@ public final class SceneContext { */ CONTACT_SEARCH_SCENE("/fxml/ContactSearchScene.fxml"), + /** + * The scene in which the group creation screen is displayed. + * + * @since Envoy Client v0.1-beta + */ + GROUP_CREATION_SCENE("/fxml/GroupCreationScene.fxml"), + /** * The scene in which the login screen is displayed. * diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index aff8801..dbadfc3 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -16,6 +16,7 @@ import envoy.client.net.Client; import envoy.client.ui.SceneContext.SceneInfo; import envoy.client.ui.controller.LoginScene; import envoy.data.Message; +import envoy.event.MessageStatusChangeEvent; import envoy.exception.EnvoyException; import envoy.util.EnvoyLog; @@ -27,13 +28,15 @@ import envoy.util.EnvoyLog; * Created: 26.03.2020
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy Client v0.1-beta */ public final class Startup extends Application { private LocalDB localDB; private Client client; - private Cache cache; + private Cache messageCache; + private Cache messageStatusCache; private static final ClientConfig config = ClientConfig.getInstance(); private static final Logger logger = EnvoyLog.getLogger(Startup.class); @@ -87,14 +90,15 @@ public final class Startup extends Application { // Initialize client and unread message cache client = new Client(); - cache = new Cache<>(); + messageCache = new Cache<>(); + messageStatusCache = new Cache<>(); stage.setTitle("Envoy"); stage.getIcons().add(IconUtil.load("/icons/envoy_logo.png")); final var sceneContext = new SceneContext(stage); sceneContext.load(SceneInfo.LOGIN_SCENE); - sceneContext.getController().initializeData(client, localDB, cache, sceneContext); + sceneContext.getController().initializeData(client, localDB, messageCache, messageStatusCache, sceneContext); } /** diff --git a/src/main/java/envoy/client/ui/controller/ChatScene.java b/src/main/java/envoy/client/ui/controller/ChatScene.java index d74b82f..8f7b487 100644 --- a/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -201,7 +201,7 @@ public final class ChatScene { @FXML private void addContactButtonClicked() { sceneContext.load(SceneContext.SceneInfo.CONTACT_SEARCH_SCENE); - sceneContext.getController().initializeData(sceneContext); + sceneContext.getController().initializeData(sceneContext, localDB); } /** diff --git a/src/main/java/envoy/client/ui/controller/ContactSearchScene.java b/src/main/java/envoy/client/ui/controller/ContactSearchScene.java index 9fc495d..f2976c9 100644 --- a/src/main/java/envoy/client/ui/controller/ContactSearchScene.java +++ b/src/main/java/envoy/client/ui/controller/ContactSearchScene.java @@ -8,9 +8,10 @@ import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.control.Alert.AlertType; +import envoy.client.data.LocalDB; import envoy.client.event.SendEvent; -import envoy.client.ui.SceneContext; import envoy.client.ui.ContactListCell; +import envoy.client.ui.SceneContext; import envoy.data.Contact; import envoy.event.ElementOperation; import envoy.event.EventBus; @@ -38,6 +39,9 @@ public class ContactSearchScene { @FXML private Button searchButton; + @FXML + private Button newGroupButton; + @FXML private TextField searchBar; @@ -46,6 +50,8 @@ public class ContactSearchScene { private SceneContext sceneContext; + private LocalDB localDB; + private static EventBus eventBus = EventBus.getInstance(); private static final Logger logger = EnvoyLog.getLogger(ChatScene.class); @@ -53,7 +59,10 @@ public class ContactSearchScene { * @param sceneContext enables the user to return to the chat scene * @since Envoy Client v0.1-beta */ - public void initializeData(SceneContext sceneContext) { this.sceneContext = sceneContext; } + public void initializeData(SceneContext sceneContext, LocalDB localDB) { + this.sceneContext = sceneContext; + this.localDB = localDB; + } @FXML private void initialize() { @@ -122,6 +131,12 @@ public class ContactSearchScene { } } + @FXML + private void newGroupButtonClicked() { + sceneContext.load(SceneContext.SceneInfo.GROUP_CREATION_SCENE); + sceneContext.getController().initializeData(sceneContext, localDB); + } + @FXML private void backButtonClicked() { sceneContext.pop(); } } diff --git a/src/main/java/envoy/client/ui/controller/GroupCreationScene.java b/src/main/java/envoy/client/ui/controller/GroupCreationScene.java new file mode 100644 index 0000000..af91d91 --- /dev/null +++ b/src/main/java/envoy/client/ui/controller/GroupCreationScene.java @@ -0,0 +1,77 @@ +package envoy.client.ui.controller; + +import java.util.stream.Collectors; + +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.scene.control.*; + +import envoy.client.data.LocalDB; +import envoy.client.event.SendEvent; +import envoy.client.ui.ContactListCell; +import envoy.client.ui.SceneContext; +import envoy.data.Contact; +import envoy.data.User; +import envoy.event.EventBus; +import envoy.event.GroupCreationEvent; + +/** + * Project: envoy-client
+ * File: ContactSearchSceneController.java
+ * Created: 07.06.2020
+ * + * @author Maximilian Käfer + * @since Envoy Client v0.1-beta + */ +public class GroupCreationScene { + + @FXML + private Button backButton; + + @FXML + private Button createButton; + + @FXML + private TextField groupNameBar; + + @FXML + private ListView contactList; + + private SceneContext sceneContext; + + private static EventBus eventBus = EventBus.getInstance(); + + @FXML + private void initialize() { + contactList.setCellFactory(e -> new ContactListCell()); + contactList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + } + + /** + * @param sceneContext enables the user to return to the chat scene + * @since Envoy Client v0.1-beta + */ + public void initializeData(SceneContext sceneContext, LocalDB localDB) { + this.sceneContext = sceneContext; + Platform.runLater(() -> contactList.getItems() + .addAll(localDB.getUsers() + .values() + .stream() + .filter(c -> c instanceof User && c.getID() != localDB.getUser().getID()) + .collect(Collectors.toList()))); + } + + /** + * Sends a {@link GroupCreationEvent} to the server. + * + * @since Envoy Client v0.1-beta + */ + @FXML + private void sendGroupObject() { + eventBus.dispatch(new SendEvent(new GroupCreationEvent(groupNameBar.getText(), + contactList.getSelectionModel().getSelectedItems().stream().map(Contact::getID).collect(Collectors.toSet())))); + } + + @FXML + private void backButtonClicked() { sceneContext.pop(); } +} diff --git a/src/main/java/envoy/client/ui/controller/LoginScene.java b/src/main/java/envoy/client/ui/controller/LoginScene.java index 5f6c5aa..f015b6e 100644 --- a/src/main/java/envoy/client/ui/controller/LoginScene.java +++ b/src/main/java/envoy/client/ui/controller/LoginScene.java @@ -21,6 +21,7 @@ import envoy.data.User; import envoy.data.User.UserStatus; import envoy.event.EventBus; import envoy.event.HandshakeRejectionEvent; +import envoy.event.MessageStatusChangeEvent; import envoy.exception.EnvoyException; import envoy.util.EnvoyLog; @@ -30,6 +31,7 @@ import envoy.util.EnvoyLog; * Created: 03.04.2020
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy Client v0.1-beta */ public final class LoginScene { @@ -55,6 +57,7 @@ public final class LoginScene { private Client client; private LocalDB localDB; private Cache receivedMessageCache; + private Cache receivedMessageStatusChangeEventCache; private SceneContext sceneContext; private static final Logger logger = EnvoyLog.getLogger(LoginScene.class); @@ -77,14 +80,17 @@ public final class LoginScene { * @param localDB the local database used for offline login * @param receivedMessageCache the cache storing messages received during * the handshake + * @param receivedMessageStatusChangeEventCache the cache storing messageStatusChangeEvents received during handshake * @param sceneContext the scene context used to initialize the chat * scene * @since Envoy Client v0.1-beta */ - public void initializeData(Client client, LocalDB localDB, Cache receivedMessageCache, SceneContext sceneContext) { + public void initializeData(Client client, LocalDB localDB, Cache receivedMessageCache, + Cache receivedMessageStatusChangeEventCache, SceneContext sceneContext) { this.client = client; this.localDB = localDB; this.receivedMessageCache = receivedMessageCache; + this.receivedMessageStatusChangeEventCache = receivedMessageStatusChangeEventCache; this.sceneContext = sceneContext; // Prepare handshake @@ -129,9 +135,9 @@ public final class LoginScene { private void performHandshake(LoginCredentials credentials) { try { - client.performHandshake(credentials, receivedMessageCache); + client.performHandshake(credentials, receivedMessageCache, receivedMessageStatusChangeEventCache); if (client.isOnline()) { - client.initReceiver(localDB, receivedMessageCache); + client.initReceiver(localDB, receivedMessageCache, receivedMessageStatusChangeEventCache); loadChatScene(); } } catch (IOException | InterruptedException | TimeoutException e) { @@ -179,6 +185,7 @@ public final class LoginScene { // Save all users to the local database and flush cache localDB.setUsers(client.getUsers()); + localDB.createMissingChats(); writeProxy.flushCache(); } else // Set all contacts to offline mode @@ -193,6 +200,7 @@ public final class LoginScene { // Relay unread messages from cache if (receivedMessageCache != null && client.isOnline()) receivedMessageCache.relay(); + if (receivedMessageStatusChangeEventCache != null && client.isOnline()) receivedMessageStatusChangeEventCache.relay(); } private void clearPasswordFields() { diff --git a/src/main/resources/fxml/ContactSearchScene.fxml b/src/main/resources/fxml/ContactSearchScene.fxml index c1fe70b..517b3e5 100644 --- a/src/main/resources/fxml/ContactSearchScene.fxml +++ b/src/main/resources/fxml/ContactSearchScene.fxml @@ -6,10 +6,8 @@ - - @@ -30,15 +28,7 @@ - - - - - - - - - + diff --git a/src/main/resources/fxml/GroupCreationScene.fxml b/src/main/resources/fxml/GroupCreationScene.fxml new file mode 100644 index 0000000..53900d5 --- /dev/null +++ b/src/main/resources/fxml/GroupCreationScene.fxml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +