diff --git a/build.gradle b/build.gradle index 4360c82..6f82563 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ dependencies { // Source: https://mvnrepository.com/artifact/org.apache.logging.log4j implementation("org.apache.logging.log4j:log4j-api:2.25.3") runtimeOnly("org.apache.logging.log4j:log4j-core:2.25.3") - + implementation("org.jspecify:jspecify:1.0.0") // Source: https://mvnrepository.com/artifact/org.fusesource.jansi/jansi runtimeOnly("org.fusesource.jansi:jansi:2.4.2") 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 c3a809f..a3861a5 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 @@ -2,8 +2,15 @@ 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 java.util.ArrayList; +import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController; +import org.jspecify.annotations.Nullable; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.Map; import java.util.List; +import java.util.LinkedHashMap; + /** * responsible for the transferring of messages from the server to the ChatModel or from the @@ -12,49 +19,84 @@ import java.util.List; public class ChatController { private final String username; - private final ClientService clientService; - private final ArrayList chatModelArrayList; private final ChatClient chatClient; + public ChatBoxController getChatBoxController() { + return chatBoxController; + } + + private final ChatBoxController chatBoxController; + private int lobbyId = -1; + private final Timer timer; + + + public record ChatKey(ChatType type, @Nullable String targetUser){ + public ChatKey(ChatType type){ + this(type, null); + } + } + + public Map getChatModelMap() { + return chatModelMap; + } + + private Map chatModelMap; + + private static final long REFRESH_TIME = 1000; + public ChatController(String username, ClientService clientService) { this.username = username; - this.clientService = clientService; - chatModelArrayList = new ArrayList<>(); - chatModelArrayList.add(new ChatModel(ChatType.GLOBAL, username)); chatClient = new ChatClient(clientService); + chatModelMap = new LinkedHashMap<>(); + this.chatBoxController = new ChatBoxController(username, this); + this.timer = new Timer(); + timer.schedule( + new TimerTask() { + @Override + public void run() { + clientService.ping(); + receiveMessage(); + } + }, + 0, + REFRESH_TIME); } - public ChatModel getChatModel(int index) { - return chatModelArrayList.get(index); - } - - public void createLobbyChat(int lobbyId, ChatType chatType) { - ChatModel chatModel = new ChatModel(chatType, username, lobbyId); - chatModelArrayList.add(chatModel); + public void setLobbyChat(int lobbyId) { + this.lobbyId = lobbyId; + ChatModel lobbyChatModel = new ChatModel(ChatType.LOBBY, username, lobbyId, null); + chatModelMap.put(new ChatKey(ChatType.LOBBY), lobbyChatModel); } /** method to get all messages from the server */ - public Boolean receiveMessage() { + public void receiveMessage() { List newMessages = chatClient.getMessages(); if (!newMessages.isEmpty()) { for (Message msg : newMessages) { switch (msg.getMessageType()) { case ChatType.GLOBAL: - chatModelArrayList.get(0).addMessage(msg); + chatModelMap.get(new ChatKey(ChatType.GLOBAL)).addMessage(msg); case ChatType.LOBBY: - ChatModel chatModel = chatModelArrayList.get(1); - if (chatModel != null && chatModel.lobbyId == msg.lobbyId) { - chatModel.addMessage(msg); + if (msg.lobbyId == lobbyId) { + chatModelMap.computeIfAbsent(new ChatKey(ChatType.LOBBY), + (_key) -> new ChatModel(ChatType.LOBBY, username, msg.lobbyId, null)).addMessage(msg); } case ChatType.WHISPER: // TODO: Check, if target person is user and if yes, iterate through all - // whisper chats. + if (msg.target.equals(username)) { + if (chatModelMap.containsKey(new ChatKey(ChatType.WHISPER, msg.sender))) { + chatModelMap.get(new ChatKey(ChatType.WHISPER, msg.sender)).addMessage(msg); + } else { + ChatModel value = new ChatModel(ChatType.WHISPER, username, -1, msg.sender); + chatModelMap.put(new ChatKey(ChatType.WHISPER, msg.sender), value); + chatBoxController.addWhisperChat(msg.sender, value); + } + } + + } } - return true; - } else { - return false; } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatModel.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatModel.java index 6fd4177..894d957 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatModel.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/ChatModel.java @@ -1,5 +1,9 @@ package ch.unibas.dmi.dbis.cs108.casono.client.chat; +import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatViewController; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; + import java.util.ArrayList; /** @@ -11,33 +15,30 @@ public class ChatModel { public ArrayList messages; - private ChatType chattype; + private final ChatType chattype; - public String username; + /** + * The person currently using this client + */ + public final String username; - public int count; + /** + * The person to send the message to + * If the chat is a whisper chat + */ + private final String target; + + private final IntegerProperty count; public int lobbyId; - /** - * Creates a new ChatModel, given a username of the client - * - * @param chattype - * @param username - */ - public ChatModel(ChatType chattype, String username) { + public ChatModel(ChatType chattype, String username, int lobbyId, String target) { this.messages = new ArrayList(); this.chattype = chattype; this.username = username; - this.count = 0; - } - - public ChatModel(ChatType chattype, String username, int lobbyId) { - this.messages = new ArrayList(); - this.chattype = chattype; - this.username = username; - this.count = 0; + this.count = new SimpleIntegerProperty(0); this.lobbyId = lobbyId; + this.target = target; } public ChatType getChattype() { @@ -49,9 +50,9 @@ public class ChatModel { * ChatModel */ public synchronized String viewNextMessage() { - count--; + count.subtract(1); Message msg = messages.getLast(); - return String.format("[%s] %s: %s", msg.timestamp, msg.user, msg.getMessage()); + return String.format("[%s] %s: %s", msg.timestamp, msg.sender, msg.getMessage()); } /** @@ -61,13 +62,21 @@ public class ChatModel { */ public synchronized void addMessage(Message msg) { messages.add(msg); - count++; + count.add(1); } - /** method to send all current messages to the ChatViewController, if needed */ - public void addCompleteChat() { - for (int i = 0; i < this.messages.size(); i++) { - Message msg = this.messages.get(i); - } + + public void addListener(ChatViewController chatViewController) { + count.addListener( + (_count, _p, n) -> + { + if(n.intValue() > 0) { + chatViewController.showMessage(); + } + }); + } + + public String getTarget() { + return target; } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/Message.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/Message.java index 60cb568..7869271 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/Message.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/chat/Message.java @@ -1,7 +1,11 @@ package ch.unibas.dmi.dbis.cs108.casono.client.chat; +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter; +import org.jspecify.annotations.NonNull; + import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -12,7 +16,7 @@ import java.util.regex.Pattern; public class Message { private final ChatType type; private final String message; - public String user; + public String sender; public String timestamp; public int lobbyId = 0; public String target = null; @@ -22,20 +26,20 @@ public class Message { * * @param type - Either global, local or whisper * @param lobbyId - lobby id, or null, if the typChatType - * @param user - username + * @param sender - username * @param target - username of the target user, for whisper chat * @param message */ public Message( ChatType type, int lobbyId, - String user, + String sender, String target, String timestamp, String message) { this.type = type; this.lobbyId = lobbyId; - this.user = user; + this.sender = sender; this.target = target; this.timestamp = timestamp; this.message = message; @@ -47,14 +51,14 @@ public class Message { * * @param type - Either global, local or whisper * @param lobbyId - lobby id, or null, if the type is global - * @param user - username + * @param sender - username * @param target - username of the target user, for whisper chat * @param message */ - public Message(ChatType type, int lobbyId, String user, String target, String message) { + public Message(ChatType type, int lobbyId, String sender, String target, String message) { this.type = type; this.lobbyId = lobbyId; - this.user = user; + this.sender = sender; this.target = target; this.message = message; LocalDateTime now = LocalDateTime.now(); @@ -77,10 +81,10 @@ public class Message { */ public String toArgsString() { return String.format( - "TYPE=%s GAME=%d USER=%s TARGET=%s TIME=%s TEXT=%s", + "TYPE=%s GAME=%d USER=%s TARGET=%s TIME=%s TEXT='%s'", this.type.toString(), this.lobbyId, - this.user, + this.sender, this.target, this.timestamp, this.message); @@ -91,7 +95,7 @@ public class Message { Pattern.compile( "TYPE=(?\\w+) " + "GAME=(?\\w+) " + "USER=(?\\w+) " + "TARGET=(?\\w+) " + - "TIME=(?