From b2adeb7a5604439133b23c86d18ab4519c64d4b0 Mon Sep 17 00:00:00 2001 From: Mathis Ginkel Date: Sun, 12 Apr 2026 00:19:34 +0200 Subject: [PATCH 1/2] Feat: Add whisper chat functionality Introduce recording of users connected to server, to show usernames as options for whisper chat. --- .../casono/client/chat/ChatController.java | 53 +++++++-- .../casono/client/network/ChatClient.java | 28 ++++- .../client/ui/chatui/ChatBoxController.java | 108 +++++++++++++----- .../dbis/cs108/casono/client/chat/Chat.java | 2 +- .../casono/client/chat/ChatApplication.java | 18 ++- 5 files changed, 159 insertions(+), 50 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatController.java index 161397a..5c8b50a 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatController.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatController.java @@ -3,11 +3,12 @@ package ch.unibas.dmi.dbis.cs108.casono.client.chat; import ch.unibas.dmi.dbis.cs108.casono.client.network.ChatClient; import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService; import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; + +import java.util.*; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jspecify.annotations.Nullable; /** @@ -38,10 +39,14 @@ public class ChatController { return chatModelMap; } - private Map chatModelMap; + private final Map chatModelMap; private static final long REFRESH_TIME = 1000; + private List localUserList; + + private Logger logger; + /** * Constructor, adds TimerTask to be sent to the server regularly * @@ -52,13 +57,16 @@ public class ChatController { this.username = username; chatClient = new ChatClient(clientService); chatModelMap = new LinkedHashMap<>(); + localUserList = new ArrayList<>(); this.chatBoxController = new ChatBoxController(username, this); + this.logger = LogManager.getLogger(ChatController.class); this.timer = new Timer(); timer.schedule( new TimerTask() { @Override public void run() { receiveMessage(); + checkWhisperUsers(); } }, 0, @@ -102,14 +110,21 @@ public class ChatController { } break; case ChatType.WHISPER: - if (msg.target.equals(username)) { - if (chatModelMap.containsKey( - new ChatKey(ChatType.WHISPER, msg.sender))) { + if (msg.target.equals(username) || msg.sender.equals(username)) { + ChatKey key; + if(msg.target.equals(username)) { + key = new ChatKey(ChatType.WHISPER, msg.sender); + } else { + key = new ChatKey(ChatType.WHISPER, msg.target); + } + if (chatModelMap.containsKey(key)) { chatModelMap - .get(new ChatKey(ChatType.WHISPER, msg.sender)) + .get(key) .addMessage(msg); } else { - chatBoxController.addWhisperChat(msg.sender); + ChatModel chatModel = new ChatModel(ChatType.WHISPER, username, lobbyId, key.targetUser()); + chatBoxController.addWhisperChat(key.targetUser(), chatModel); + chatModel.addMessage(msg); } } break; @@ -118,6 +133,22 @@ public class ChatController { } } + public synchronized void checkWhisperUsers() { + List users = chatClient.getUsers(); + logger.info(users); + if (!users.isEmpty()) { + for (String user : users) { + String value = user.split("\\=")[1]; + logger.info(value); + if (!(localUserList.contains(value) || value.equals(username))) { + localUserList.add(value); + logger.info("adding new whisper user"); + chatBoxController.addWhisperUser(value); + } + } + } + } + /** * method to send a message to the server * diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java index f47ea87..e6fe86e 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java @@ -2,8 +2,9 @@ package ch.unibas.dmi.dbis.cs108.casono.client.network; import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message; import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter; -import java.util.ArrayList; -import java.util.List; + +import java.util.*; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -69,4 +70,27 @@ public class ChatClient { } return messages; } + + public List getUsers() { + logger.info("Asking server for list of users"); + List users = clientService.processCommand("LIST_USERS"); + List parameters = new ArrayList(); + for (int i = 0; i < users.size(); i++) { + String line = users.get(i); + if (line.equals("USERS")) { + continue; + } else if (line.equals("END")) { + break; + } + line = line.replaceFirst("^\t", ""); + + if (line.equals("USER")) { + String username = users.get(i + 1); + username = username.replaceFirst("^\t", ""); + username = username.replaceFirst("^\t", ""); + parameters.add(username); + } + } + return parameters; + } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatBoxController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatBoxController.java index 618d309..3e5c518 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatBoxController.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatBoxController.java @@ -5,14 +5,20 @@ import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel; import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatType; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import javafx.application.Platform; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Node; -import javafx.scene.control.MenuButton; -import javafx.scene.control.MenuItem; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; @@ -28,15 +34,21 @@ public class ChatBoxController { @FXML private MenuButton addWhisperChatButton; + @FXML private HBox menuBox; + private FXMLLoader fxmlLoader; - @FXML private List whisperUsers; + private final List activeWhisperChats; + + @FXML private final Map usernameTabMap; private String ressource = "/ui-structure/components/chatui/chattab.fxml"; public ChatBoxController(String username, ChatController chatController) { this.username = username; this.chatController = chatController; + activeWhisperChats = new ArrayList<>(); + usernameTabMap = new HashMap<>(); } /** @@ -51,7 +63,7 @@ public class ChatBoxController { .getChatModelMap() .put(new ChatController.ChatKey(ChatType.GLOBAL), globalChatModel); addChatTab("GLOBAL", globalChatModel); - // TODO: Button to add new Whisper Chat + addWhisperChatButton.setOnAction(event -> addWhisperChatButton.show()); } /** @@ -61,10 +73,12 @@ public class ChatBoxController { * @param targetUserName The username of the person to be added to the whisper list. */ public void addWhisperUser(String targetUserName) { - MenuItem menuItem = new MenuItem(targetUserName); - whisperUsers.add(menuItem); - addWhisperChatButton.getItems().add(menuItem); - menuItem.setOnAction(event -> addWhisperChat(targetUserName)); + Platform.runLater( + () -> { + MenuItem menuItem = new MenuItem(targetUserName); + addWhisperChatButton.getItems().add(menuItem); + menuItem.setOnAction(event -> addWhisperChat(targetUserName, new ChatModel(ChatType.WHISPER, username, -1, targetUserName))); + }); } /** @@ -73,12 +87,16 @@ public class ChatBoxController { * * @param target The username of the recipient for the private messages. */ - public void addWhisperChat(String target) { - ChatModel chatModel = new ChatModel(ChatType.WHISPER, username, -1, target); - chatController - .getChatModelMap() - .put(new ChatController.ChatKey(ChatType.WHISPER, target), chatModel); - addChatTab(target, chatModel); + public void addWhisperChat(String target, ChatModel chatModel) { + if (!activeWhisperChats.contains(target)) { + activeWhisperChats.add(target); + chatController + .getChatModelMap() + .put(new ChatController.ChatKey(ChatType.WHISPER, target), chatModel); + addChatTab(target, chatModel); + } else { + chatTabPane.getSelectionModel().select(usernameTabMap.get(target)); + } } /** @@ -93,20 +111,50 @@ public class ChatBoxController { public void addChatTab(String title, ChatModel chatModel) { URL resource = getClass().getResource(ressource); FXMLLoader fxmlLoader = new FXMLLoader(resource); - try { - ChatViewController chatViewController = - new ChatViewController(this.chatController, chatModel, this.username); - fxmlLoader.setController(chatViewController); - Node load = fxmlLoader.load(); - VBox.setVgrow(load, Priority.ALWAYS); - VBox vbox = new VBox(); - VBox.setVgrow(vbox, Priority.ALWAYS); - vbox.getChildren().add(load); - chatModel.addListener((msg) -> chatViewController.showMessage(msg)); - Tab newChat = new Tab(title, vbox); - this.chatTabPane.getTabs().add(newChat); - } catch (IOException e) { - throw new RuntimeException(e); + runOnPlatformSynchronized(()-> { + try { + ChatViewController chatViewController = + new ChatViewController(this.chatController, chatModel, this.username); + fxmlLoader.setController(chatViewController); + Node load = fxmlLoader.load(); + VBox.setVgrow(load, Priority.ALWAYS); + VBox vbox = new VBox(); + VBox.setVgrow(vbox, Priority.ALWAYS); + vbox.getChildren().add(load); + chatModel.addListener((msg) -> chatViewController.showMessage(msg)); + Tab newChat = new Tab(title, vbox); + usernameTabMap.put(title, newChat); + this.chatTabPane.getTabs().add(newChat); + this.chatTabPane.getSelectionModel().select(newChat); + return newChat; + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + public static T runOnPlatformSynchronized(Callable code) { + if(Platform.isFxApplicationThread()) { + try { + return code.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + CompletableFuture futureLock = new CompletableFuture<>(); + Platform.runLater(() -> { + try { + futureLock.complete(code.call()); + } catch (Exception e) { + futureLock.completeExceptionally(e); + } + }); + try { + return futureLock.get(); + } catch (Throwable e) { + throw new RuntimeException(e); + } } } + } diff --git a/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/Chat.java b/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/Chat.java index 6088f22..5f533fd 100644 --- a/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/Chat.java +++ b/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/Chat.java @@ -4,6 +4,6 @@ import javafx.application.Application; public class Chat { public static void main(String[] args) { - Application.launch(ChatApplication.class); + Application.launch(ChatApplication.class, args); } } diff --git a/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatApplication.java b/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatApplication.java index 0eff249..722b859 100644 --- a/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatApplication.java +++ b/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatApplication.java @@ -4,8 +4,13 @@ import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService; import ch.unibas.dmi.dbis.cs108.casono.client.network.CoreClient; import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + import javafx.application.Application; import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; @@ -13,13 +18,14 @@ public class ChatApplication extends Application { private static final int SCENE_WIDTH = 1200; private static final int SCENE_HEIGHT = 800; - String ip = "localhost"; - String username = "mathis"; - final int port = 5000; public ChatApplication() {} public void start(Stage stage) throws IOException { + List params = getParameters().getRaw(); + String ip = params.get(0); + int port = Integer.parseInt(params.get(1)); + String username = params.get(2); FXMLLoader fxmlLoader = new FXMLLoader( getClass().getResource("/ui-structure/components/chatui/chatbox.fxml")); @@ -27,10 +33,10 @@ public class ChatApplication extends Application { CoreClient coreClient = new CoreClient(clientService); coreClient.login(username); ChatController chatController = new ChatController(username, clientService); - ChatBoxController chatBoxController = new ChatBoxController(username, chatController); + ChatBoxController chatBoxController = chatController.getChatBoxController(); fxmlLoader.setController(chatBoxController); - - Scene scene = new Scene(fxmlLoader.load(), SCENE_WIDTH, SCENE_HEIGHT); + Parent node = fxmlLoader.load(); + Scene scene = new Scene(node, SCENE_WIDTH, SCENE_HEIGHT); stage.setTitle("Chat"); stage.setScene(scene); stage.show(); -- 2.52.0 From e08b75dc7a21d1a06f4852cd8601b4772c396152 Mon Sep 17 00:00:00 2001 From: Mathis Ginkel Date: Sun, 12 Apr 2026 15:31:59 +0200 Subject: [PATCH 2/2] Style: Apply Spotless --- .../casono/client/chat/ChatController.java | 58 ++++++++----- .../casono/client/network/ChatClient.java | 11 ++- .../client/ui/chatui/ChatBoxController.java | 81 +++++++++++-------- .../casono/client/chat/ChatApplication.java | 3 - 4 files changed, 96 insertions(+), 57 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatController.java index 5c8b50a..3a69a45 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatController.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatController.java @@ -3,10 +3,12 @@ package ch.unibas.dmi.dbis.cs108.casono.client.chat; import ch.unibas.dmi.dbis.cs108.casono.client.network.ChatClient; import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService; import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController; - -import java.util.*; - -import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.Nullable; @@ -43,9 +45,10 @@ public class ChatController { private static final long REFRESH_TIME = 1000; - private List localUserList; + /** List of all users connected to the server, to safe them locally on the client */ + private final List localUserList; - private Logger logger; + private final Logger logger; /** * Constructor, adds TimerTask to be sent to the server regularly @@ -74,7 +77,7 @@ public class ChatController { } /** - * Method to be activated, if a lobby has be chosen. It will update the UI and add a new + * Method to be activated, if a lobby has been chosen. It will update the UI and add a new * ChatModel to hold the Data for the Lobby Chat * * @param lobbyId @@ -86,7 +89,15 @@ public class ChatController { this.chatBoxController.addChatTab("Lobby", lobbyChatModel); } - /** method to get all messages from the server */ + /** + * Method to process the Messages that got polled by the {@link ChatClient}. + * + *

Case distinction for every message: - Messages identified with ChatType.LOBBY -> check if + * they belong to the users lobby. - Messages identified with ChatType.GLOBAL -> check if the + * target user of that Message is the user, or the message got sent by the user. + * + *

All Messages get added to a particular {@link ChatModel}, if the checks passed. + */ public void receiveMessage() { List newMessages = chatClient.getMessages(); if (!newMessages.isEmpty()) { @@ -112,17 +123,20 @@ public class ChatController { case ChatType.WHISPER: if (msg.target.equals(username) || msg.sender.equals(username)) { ChatKey key; - if(msg.target.equals(username)) { - key = new ChatKey(ChatType.WHISPER, msg.sender); - } else { - key = new ChatKey(ChatType.WHISPER, msg.target); - } - if (chatModelMap.containsKey(key)) { - chatModelMap - .get(key) - .addMessage(msg); + if (msg.target.equals(username)) { + key = new ChatKey(ChatType.WHISPER, msg.sender); } else { - ChatModel chatModel = new ChatModel(ChatType.WHISPER, username, lobbyId, key.targetUser()); + key = new ChatKey(ChatType.WHISPER, msg.target); + } + if (chatModelMap.containsKey(key)) { + chatModelMap.get(key).addMessage(msg); + } else { + ChatModel chatModel = + new ChatModel( + ChatType.WHISPER, + username, + lobbyId, + key.targetUser()); chatBoxController.addWhisperChat(key.targetUser(), chatModel); chatModel.addMessage(msg); } @@ -133,6 +147,14 @@ public class ChatController { } } + /** + * Method to process the usernames of other users connected to the server, after they got polled + * by the {@link ChatClient}. + * + *

Checks for every one of the usernames, if it is already in the list localUserList and if + * not adds them. For every new User added in the List, they get added as an option to start a + * Whisper Chat with. + */ public synchronized void checkWhisperUsers() { List users = chatClient.getUsers(); logger.info(users); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java index e6fe86e..6a88ed9 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java @@ -2,9 +2,8 @@ package ch.unibas.dmi.dbis.cs108.casono.client.network; import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message; import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter; - -import java.util.*; - +import java.util.ArrayList; +import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -71,6 +70,12 @@ public class ChatClient { return messages; } + /** + * Method to poll the usernames of all users currently connected to the server, by sending the + * "LIST_USERS" command. + * + * @return List of all usernames retrieved from the server. + */ public List getUsers() { logger.info("Asking server for list of users"); List users = clientService.processCommand("LIST_USERS"); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatBoxController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatBoxController.java index 3e5c518..e0a62e6 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatBoxController.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatBoxController.java @@ -11,13 +11,14 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - import javafx.application.Platform; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Node; -import javafx.scene.control.*; +import javafx.scene.control.MenuButton; +import javafx.scene.control.MenuItem; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; @@ -77,7 +78,15 @@ public class ChatBoxController { () -> { MenuItem menuItem = new MenuItem(targetUserName); addWhisperChatButton.getItems().add(menuItem); - menuItem.setOnAction(event -> addWhisperChat(targetUserName, new ChatModel(ChatType.WHISPER, username, -1, targetUserName))); + menuItem.setOnAction( + event -> + addWhisperChat( + targetUserName, + new ChatModel( + ChatType.WHISPER, + username, + -1, + targetUserName))); }); } @@ -111,30 +120,36 @@ public class ChatBoxController { public void addChatTab(String title, ChatModel chatModel) { URL resource = getClass().getResource(ressource); FXMLLoader fxmlLoader = new FXMLLoader(resource); - runOnPlatformSynchronized(()-> { - try { - ChatViewController chatViewController = - new ChatViewController(this.chatController, chatModel, this.username); - fxmlLoader.setController(chatViewController); - Node load = fxmlLoader.load(); - VBox.setVgrow(load, Priority.ALWAYS); - VBox vbox = new VBox(); - VBox.setVgrow(vbox, Priority.ALWAYS); - vbox.getChildren().add(load); - chatModel.addListener((msg) -> chatViewController.showMessage(msg)); - Tab newChat = new Tab(title, vbox); - usernameTabMap.put(title, newChat); - this.chatTabPane.getTabs().add(newChat); - this.chatTabPane.getSelectionModel().select(newChat); - return newChat; - } catch (IOException e) { - throw new RuntimeException(e); - } - }); + runOnPlatformSynchronized( + () -> { + try { + ChatViewController chatViewController = + new ChatViewController( + this.chatController, chatModel, this.username); + fxmlLoader.setController(chatViewController); + Node load = fxmlLoader.load(); + VBox.setVgrow(load, Priority.ALWAYS); + VBox vbox = new VBox(); + VBox.setVgrow(vbox, Priority.ALWAYS); + vbox.getChildren().add(load); + chatModel.addListener((msg) -> chatViewController.showMessage(msg)); + Tab newChat = new Tab(title, vbox); + usernameTabMap.put(title, newChat); + this.chatTabPane.getTabs().add(newChat); + this.chatTabPane.getSelectionModel().select(newChat); + return newChat; + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } + /** + * Helper Function to cope with a Threads problem occurring when the main JavaFX Thread performs + * the task to add a new whisper Chat tab, and the task is specified to runLater. + */ public static T runOnPlatformSynchronized(Callable code) { - if(Platform.isFxApplicationThread()) { + if (Platform.isFxApplicationThread()) { try { return code.call(); } catch (Exception e) { @@ -142,13 +157,14 @@ public class ChatBoxController { } } else { CompletableFuture futureLock = new CompletableFuture<>(); - Platform.runLater(() -> { - try { - futureLock.complete(code.call()); - } catch (Exception e) { - futureLock.completeExceptionally(e); - } - }); + Platform.runLater( + () -> { + try { + futureLock.complete(code.call()); + } catch (Exception e) { + futureLock.completeExceptionally(e); + } + }); try { return futureLock.get(); } catch (Throwable e) { @@ -156,5 +172,4 @@ public class ChatBoxController { } } } - } diff --git a/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatApplication.java b/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatApplication.java index 722b859..9c81ee7 100644 --- a/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatApplication.java +++ b/src/test/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatApplication.java @@ -4,12 +4,9 @@ import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService; import ch.unibas.dmi.dbis.cs108.casono.client.network.CoreClient; import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController; import java.io.IOException; -import java.util.ArrayList; import java.util.List; - import javafx.application.Application; import javafx.fxml.FXMLLoader; -import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; -- 2.52.0