Feat: Add whisper chat functionality
Introduce recording of users connected to server, to show usernames as options for whisper chat.
This commit is contained in:
@@ -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.ChatClient;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService;
|
import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
|
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Timer;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
|
||||||
import java.util.TimerTask;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,10 +39,14 @@ public class ChatController {
|
|||||||
return chatModelMap;
|
return chatModelMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<ChatKey, ChatModel> chatModelMap;
|
private final Map<ChatKey, ChatModel> chatModelMap;
|
||||||
|
|
||||||
private static final long REFRESH_TIME = 1000;
|
private static final long REFRESH_TIME = 1000;
|
||||||
|
|
||||||
|
private List<String> localUserList;
|
||||||
|
|
||||||
|
private Logger logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor, adds TimerTask to be sent to the server regularly
|
* Constructor, adds TimerTask to be sent to the server regularly
|
||||||
*
|
*
|
||||||
@@ -52,13 +57,16 @@ public class ChatController {
|
|||||||
this.username = username;
|
this.username = username;
|
||||||
chatClient = new ChatClient(clientService);
|
chatClient = new ChatClient(clientService);
|
||||||
chatModelMap = new LinkedHashMap<>();
|
chatModelMap = new LinkedHashMap<>();
|
||||||
|
localUserList = new ArrayList<>();
|
||||||
this.chatBoxController = new ChatBoxController(username, this);
|
this.chatBoxController = new ChatBoxController(username, this);
|
||||||
|
this.logger = LogManager.getLogger(ChatController.class);
|
||||||
this.timer = new Timer();
|
this.timer = new Timer();
|
||||||
timer.schedule(
|
timer.schedule(
|
||||||
new TimerTask() {
|
new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
receiveMessage();
|
receiveMessage();
|
||||||
|
checkWhisperUsers();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
@@ -102,14 +110,21 @@ public class ChatController {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ChatType.WHISPER:
|
case ChatType.WHISPER:
|
||||||
if (msg.target.equals(username)) {
|
if (msg.target.equals(username) || msg.sender.equals(username)) {
|
||||||
if (chatModelMap.containsKey(
|
ChatKey key;
|
||||||
new ChatKey(ChatType.WHISPER, msg.sender))) {
|
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
|
chatModelMap
|
||||||
.get(new ChatKey(ChatType.WHISPER, msg.sender))
|
.get(key)
|
||||||
.addMessage(msg);
|
.addMessage(msg);
|
||||||
} else {
|
} else {
|
||||||
chatBoxController.addWhisperChat(msg.sender);
|
ChatModel chatModel = new ChatModel(ChatType.WHISPER, username, lobbyId, key.targetUser());
|
||||||
|
chatBoxController.addWhisperChat(key.targetUser(), chatModel);
|
||||||
|
chatModel.addMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -118,6 +133,22 @@ public class ChatController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void checkWhisperUsers() {
|
||||||
|
List<String> 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
|
* method to send a message to the server
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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.client.chat.Message;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
|
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.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
@@ -69,4 +70,27 @@ public class ChatClient {
|
|||||||
}
|
}
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getUsers() {
|
||||||
|
logger.info("Asking server for list of users");
|
||||||
|
List<String> users = clientService.processCommand("LIST_USERS");
|
||||||
|
List<String> parameters = new ArrayList<String>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-10
@@ -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 ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatType;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
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.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.MenuButton;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.control.Tab;
|
|
||||||
import javafx.scene.control.TabPane;
|
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
@@ -28,15 +34,21 @@ public class ChatBoxController {
|
|||||||
|
|
||||||
@FXML private MenuButton addWhisperChatButton;
|
@FXML private MenuButton addWhisperChatButton;
|
||||||
|
|
||||||
|
@FXML private HBox menuBox;
|
||||||
|
|
||||||
private FXMLLoader fxmlLoader;
|
private FXMLLoader fxmlLoader;
|
||||||
|
|
||||||
@FXML private List<MenuItem> whisperUsers;
|
private final List<String> activeWhisperChats;
|
||||||
|
|
||||||
|
@FXML private final Map<String, Tab> usernameTabMap;
|
||||||
|
|
||||||
private String ressource = "/ui-structure/components/chatui/chattab.fxml";
|
private String ressource = "/ui-structure/components/chatui/chattab.fxml";
|
||||||
|
|
||||||
public ChatBoxController(String username, ChatController chatController) {
|
public ChatBoxController(String username, ChatController chatController) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.chatController = chatController;
|
this.chatController = chatController;
|
||||||
|
activeWhisperChats = new ArrayList<>();
|
||||||
|
usernameTabMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,7 +63,7 @@ public class ChatBoxController {
|
|||||||
.getChatModelMap()
|
.getChatModelMap()
|
||||||
.put(new ChatController.ChatKey(ChatType.GLOBAL), globalChatModel);
|
.put(new ChatController.ChatKey(ChatType.GLOBAL), globalChatModel);
|
||||||
addChatTab("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.
|
* @param targetUserName The username of the person to be added to the whisper list.
|
||||||
*/
|
*/
|
||||||
public void addWhisperUser(String targetUserName) {
|
public void addWhisperUser(String targetUserName) {
|
||||||
|
Platform.runLater(
|
||||||
|
() -> {
|
||||||
MenuItem menuItem = new MenuItem(targetUserName);
|
MenuItem menuItem = new MenuItem(targetUserName);
|
||||||
whisperUsers.add(menuItem);
|
|
||||||
addWhisperChatButton.getItems().add(menuItem);
|
addWhisperChatButton.getItems().add(menuItem);
|
||||||
menuItem.setOnAction(event -> addWhisperChat(targetUserName));
|
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.
|
* @param target The username of the recipient for the private messages.
|
||||||
*/
|
*/
|
||||||
public void addWhisperChat(String target) {
|
public void addWhisperChat(String target, ChatModel chatModel) {
|
||||||
ChatModel chatModel = new ChatModel(ChatType.WHISPER, username, -1, target);
|
if (!activeWhisperChats.contains(target)) {
|
||||||
|
activeWhisperChats.add(target);
|
||||||
chatController
|
chatController
|
||||||
.getChatModelMap()
|
.getChatModelMap()
|
||||||
.put(new ChatController.ChatKey(ChatType.WHISPER, target), chatModel);
|
.put(new ChatController.ChatKey(ChatType.WHISPER, target), chatModel);
|
||||||
addChatTab(target, chatModel);
|
addChatTab(target, chatModel);
|
||||||
|
} else {
|
||||||
|
chatTabPane.getSelectionModel().select(usernameTabMap.get(target));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,6 +111,7 @@ public class ChatBoxController {
|
|||||||
public void addChatTab(String title, ChatModel chatModel) {
|
public void addChatTab(String title, ChatModel chatModel) {
|
||||||
URL resource = getClass().getResource(ressource);
|
URL resource = getClass().getResource(ressource);
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
||||||
|
runOnPlatformSynchronized(()-> {
|
||||||
try {
|
try {
|
||||||
ChatViewController chatViewController =
|
ChatViewController chatViewController =
|
||||||
new ChatViewController(this.chatController, chatModel, this.username);
|
new ChatViewController(this.chatController, chatModel, this.username);
|
||||||
@@ -104,9 +123,38 @@ public class ChatBoxController {
|
|||||||
vbox.getChildren().add(load);
|
vbox.getChildren().add(load);
|
||||||
chatModel.addListener((msg) -> chatViewController.showMessage(msg));
|
chatModel.addListener((msg) -> chatViewController.showMessage(msg));
|
||||||
Tab newChat = new Tab(title, vbox);
|
Tab newChat = new Tab(title, vbox);
|
||||||
|
usernameTabMap.put(title, newChat);
|
||||||
this.chatTabPane.getTabs().add(newChat);
|
this.chatTabPane.getTabs().add(newChat);
|
||||||
|
this.chatTabPane.getSelectionModel().select(newChat);
|
||||||
|
return newChat;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T runOnPlatformSynchronized(Callable<T> code) {
|
||||||
|
if(Platform.isFxApplicationThread()) {
|
||||||
|
try {
|
||||||
|
return code.call();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CompletableFuture<T> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import javafx.application.Application;
|
|||||||
|
|
||||||
public class Chat {
|
public class Chat {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Application.launch(ChatApplication.class);
|
Application.launch(ChatApplication.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.network.CoreClient;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
|
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
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_WIDTH = 1200;
|
||||||
private static final int SCENE_HEIGHT = 800;
|
private static final int SCENE_HEIGHT = 800;
|
||||||
String ip = "localhost";
|
|
||||||
String username = "mathis";
|
|
||||||
final int port = 5000;
|
|
||||||
|
|
||||||
public ChatApplication() {}
|
public ChatApplication() {}
|
||||||
|
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
|
List<String> params = getParameters().getRaw();
|
||||||
|
String ip = params.get(0);
|
||||||
|
int port = Integer.parseInt(params.get(1));
|
||||||
|
String username = params.get(2);
|
||||||
FXMLLoader fxmlLoader =
|
FXMLLoader fxmlLoader =
|
||||||
new FXMLLoader(
|
new FXMLLoader(
|
||||||
getClass().getResource("/ui-structure/components/chatui/chatbox.fxml"));
|
getClass().getResource("/ui-structure/components/chatui/chatbox.fxml"));
|
||||||
@@ -27,10 +33,10 @@ public class ChatApplication extends Application {
|
|||||||
CoreClient coreClient = new CoreClient(clientService);
|
CoreClient coreClient = new CoreClient(clientService);
|
||||||
coreClient.login(username);
|
coreClient.login(username);
|
||||||
ChatController chatController = new ChatController(username, clientService);
|
ChatController chatController = new ChatController(username, clientService);
|
||||||
ChatBoxController chatBoxController = new ChatBoxController(username, chatController);
|
ChatBoxController chatBoxController = chatController.getChatBoxController();
|
||||||
fxmlLoader.setController(chatBoxController);
|
fxmlLoader.setController(chatBoxController);
|
||||||
|
Parent node = fxmlLoader.load();
|
||||||
Scene scene = new Scene(fxmlLoader.load(), SCENE_WIDTH, SCENE_HEIGHT);
|
Scene scene = new Scene(node, SCENE_WIDTH, SCENE_HEIGHT);
|
||||||
stage.setTitle("Chat");
|
stage.setTitle("Chat");
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.show();
|
stage.show();
|
||||||
|
|||||||
Reference in New Issue
Block a user