Merge pull request #143 from informatik-ag-ngl/f/groups
Group Creation and working MessageStatus delivery (NO READ)
This commit is contained in:
commit
2d92a3afcb
2
pom.xml
2
pom.xml
@ -28,7 +28,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.informatik-ag-ngl</groupId>
|
||||
<artifactId>envoy-common</artifactId>
|
||||
<version>f~groups-SNAPSHOT</version>
|
||||
<version>develop-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<Message> receivedMessageCache)
|
||||
public void performHandshake(LoginCredentials credentials, Cache<Message> receivedMessageCache,
|
||||
Cache<MessageStatusChangeEvent> 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<Message> receivedMessageCache) throws IOException {
|
||||
public void initReceiver(LocalDB localDB, Cache<Message> receivedMessageCache,
|
||||
Cache<MessageStatusChangeEvent> 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);
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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: <strong>26.03.2020</strong><br>
|
||||
*
|
||||
* @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<Message> cache;
|
||||
private Cache<Message> messageCache;
|
||||
private Cache<MessageStatusChangeEvent> 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.<LoginScene>getController().initializeData(client, localDB, cache, sceneContext);
|
||||
sceneContext.<LoginScene>getController().initializeData(client, localDB, messageCache, messageStatusCache, sceneContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,7 +201,7 @@ public final class ChatScene {
|
||||
@FXML
|
||||
private void addContactButtonClicked() {
|
||||
sceneContext.load(SceneContext.SceneInfo.CONTACT_SEARCH_SCENE);
|
||||
sceneContext.<ContactSearchScene>getController().initializeData(sceneContext);
|
||||
sceneContext.<ContactSearchScene>getController().initializeData(sceneContext, localDB);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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.<GroupCreationScene>getController().initializeData(sceneContext, localDB);
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void backButtonClicked() { sceneContext.pop(); }
|
||||
}
|
||||
|
@ -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: <strong>envoy-client</strong><br>
|
||||
* File: <strong>ContactSearchSceneController.java</strong><br>
|
||||
* Created: <strong>07.06.2020</strong><br>
|
||||
*
|
||||
* @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<Contact> 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(); }
|
||||
}
|
@ -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: <strong>03.04.2020</strong><br>
|
||||
*
|
||||
* @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<Message> receivedMessageCache;
|
||||
private Cache<MessageStatusChangeEvent> 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<Message> receivedMessageCache, SceneContext sceneContext) {
|
||||
public void initializeData(Client client, LocalDB localDB, Cache<Message> receivedMessageCache,
|
||||
Cache<MessageStatusChangeEvent> 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() {
|
||||
|
@ -6,10 +6,8 @@
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
|
||||
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="envoy.client.ui.controller.ContactSearchScene">
|
||||
<children>
|
||||
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
|
||||
@ -30,15 +28,7 @@
|
||||
<Tooltip autoHide="true" text="Clears the text to the left and the elements below" wrapText="true" />
|
||||
</tooltip>
|
||||
</Button>
|
||||
<Pane disable="true" maxWidth="20.0" prefWidth="20.0" visible="false">
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</Pane>
|
||||
<Button fx:id="searchButton" disable="true" defaultButton="true" mnemonicParsing="true" onAction="#suggestContacts" prefHeight="26.0" prefWidth="71.0" text="_Search" textOverrun="LEADING_WORD_ELLIPSIS">
|
||||
<Button fx:id="searchButton" defaultButton="true" disable="true" mnemonicParsing="true" onAction="#suggestContacts" prefHeight="26.0" prefWidth="71.0" text="_Search" textOverrun="LEADING_WORD_ELLIPSIS">
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
@ -49,6 +39,11 @@
|
||||
<Tooltip autoHide="true" text="Search for accounts with the name entered to the left" wrapText="true" />
|
||||
</tooltip>
|
||||
</Button>
|
||||
<Button mnemonicParsing="false" onAction="#newGroupButtonClicked" text="New Group">
|
||||
<HBox.margin>
|
||||
<Insets left="100.0" />
|
||||
</HBox.margin>
|
||||
</Button>
|
||||
</children>
|
||||
</HBox>
|
||||
<ListView fx:id="contactList" onMouseClicked="#contactListClicked" prefHeight="314.0" prefWidth="600.0" />
|
||||
|
49
src/main/resources/fxml/GroupCreationScene.fxml
Normal file
49
src/main/resources/fxml/GroupCreationScene.fxml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ListView?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="envoy.client.ui.controller.GroupCreationScene">
|
||||
<children>
|
||||
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
|
||||
<children>
|
||||
<TextField fx:id="groupNameBar" prefColumnCount="22" promptText="Enter Group Name">
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
<tooltip>
|
||||
<Tooltip text="Enter a name. If an account by that name exists, it will be displayed below." wrapText="true" />
|
||||
</tooltip>
|
||||
</TextField>
|
||||
</children>
|
||||
</HBox>
|
||||
<Label text="Choose Members:">
|
||||
<font>
|
||||
<Font size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<ListView fx:id="contactList" prefHeight="314.0" prefWidth="600.0" />
|
||||
<Button mnemonicParsing="false" onAction="#sendGroupObject" text="Create" />
|
||||
<Button fx:id="backButton" cancelButton="true" mnemonicParsing="true" onAction="#backButtonClicked" text="_Back">
|
||||
<VBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</VBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
<tooltip>
|
||||
<Tooltip autoHide="true" text="Takes you back to the screen where you can chat with others" wrapText="true" />
|
||||
</tooltip>
|
||||
</Button>
|
||||
</children>
|
||||
</VBox>
|
Reference in New Issue
Block a user