Merge branch 'feat/chat-visual-improvement' into 'main'
Feat/chat visual improvement Closes #107 See merge request cs108-fs26/Gruppe-13!159
This commit was merged in pull request #315.
This commit is contained in:
+44
-22
@@ -1,6 +1,7 @@
|
||||
package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui;
|
||||
|
||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatController;
|
||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatController.ChatKey;
|
||||
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.Message;
|
||||
@@ -20,7 +21,6 @@ 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;
|
||||
|
||||
@@ -30,16 +30,10 @@ public class ChatBoxController {
|
||||
|
||||
private final ChatController chatController;
|
||||
|
||||
@FXML private VBox chatBox;
|
||||
|
||||
@FXML private TabPane chatTabPane;
|
||||
|
||||
@FXML private MenuButton addWhisperChatButton;
|
||||
|
||||
@FXML private HBox menuBox;
|
||||
|
||||
private FXMLLoader fxmlLoader;
|
||||
|
||||
private final List<String> activeWhisperChats;
|
||||
|
||||
@FXML private final Map<String, Tab> usernameTabMap;
|
||||
@@ -76,7 +70,7 @@ public class ChatBoxController {
|
||||
ChatModel globalChatModel = new ChatModel(global, username, -1, null);
|
||||
chatController.getChatModelMap().put(new ChatController.ChatKey(global), globalChatModel);
|
||||
addChatTab("GLOBAL", globalChatModel, global);
|
||||
addWhisperChatButton.setOnAction(event -> addWhisperChatButton.show());
|
||||
addWhisperChatButton.setOnAction(_ -> addWhisperChatButton.show());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,7 +90,7 @@ public class ChatBoxController {
|
||||
MenuItem menuItem = new MenuItem(targetUserName);
|
||||
addWhisperChatButton.getItems().add(menuItem);
|
||||
menuItem.setOnAction(
|
||||
event ->
|
||||
_ ->
|
||||
addWhisperChat(
|
||||
targetUserName,
|
||||
new ChatModel(
|
||||
@@ -130,7 +124,7 @@ public class ChatBoxController {
|
||||
if (oldUsername.equals(item.getText())) {
|
||||
item.setText(newUsername);
|
||||
item.setOnAction(
|
||||
event ->
|
||||
_ ->
|
||||
addWhisperChat(
|
||||
newUsername,
|
||||
new ChatModel(
|
||||
@@ -165,11 +159,21 @@ public class ChatBoxController {
|
||||
if (!activeWhisperChats.contains(target)) {
|
||||
activeWhisperChats.add(target);
|
||||
ChatType whisper = ChatType.WHISPER;
|
||||
chatController
|
||||
.getChatModelMap()
|
||||
.put(new ChatController.ChatKey(whisper, target), chatModel);
|
||||
addChatTab(target, chatModel, whisper);
|
||||
chatController.getChatModelMap().put(new ChatKey(whisper, target), chatModel);
|
||||
ChatViewController chatViewController = addChatTab(target, chatModel, whisper);
|
||||
Tab chatTab = chatViewController.getChatTab();
|
||||
chatTab.setOnCloseRequest(
|
||||
_ -> {
|
||||
chatViewController.tabIsOpen = false;
|
||||
chatTabPane.getTabs().remove(chatTab);
|
||||
});
|
||||
} else {
|
||||
ChatViewController chatViewController =
|
||||
chatController.activeChatControllers.get(new ChatKey(ChatType.WHISPER, target));
|
||||
if (!chatViewController.tabIsOpen) {
|
||||
reopenChatTab(chatViewController.getChatTab());
|
||||
chatViewController.tabIsOpen = true;
|
||||
}
|
||||
chatTabPane.getSelectionModel().select(usernameTabMap.get(target));
|
||||
}
|
||||
}
|
||||
@@ -183,30 +187,40 @@ public class ChatBoxController {
|
||||
* @param chatModel The {@link ChatModel} containing the data and logic for this specific chat.
|
||||
* @throws RuntimeException If the FXML resource for the chat tab cannot be loaded.
|
||||
*/
|
||||
public void addChatTab(String title, ChatModel chatModel, ChatType chatType) {
|
||||
public ChatViewController addChatTab(String title, ChatModel chatModel, ChatType chatType) {
|
||||
String ressource = "/ui-structure/components/chatui/chattab.fxml";
|
||||
URL resource = getClass().getResource(ressource);
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
||||
runOnPlatformSynchronized(
|
||||
return runOnPlatformSynchronized(
|
||||
() -> {
|
||||
try {
|
||||
ChatViewController chatViewController =
|
||||
new ChatViewController(
|
||||
this.chatController, chatModel, this.username);
|
||||
chatController.activeChatControllers.put(
|
||||
new ChatController.ChatKey(chatType), chatViewController);
|
||||
this.chatController, chatModel, this);
|
||||
|
||||
ChatKey chatKey;
|
||||
if (chatType.equals(ChatType.WHISPER)) {
|
||||
chatKey = new ChatKey(chatType, title);
|
||||
} else {
|
||||
chatKey = new ChatKey(chatType);
|
||||
}
|
||||
chatController.activeChatControllers.put(chatKey, chatViewController);
|
||||
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));
|
||||
chatModel.addListener(chatViewController::showMessage);
|
||||
Tab newChat = new Tab(title, vbox);
|
||||
usernameTabMap.put(title, newChat);
|
||||
this.chatTabPane.getTabs().add(newChat);
|
||||
chatTabPane.getTabs().add(newChat);
|
||||
this.chatTabPane.getSelectionModel().select(newChat);
|
||||
return newChat;
|
||||
chatViewController.setChatTab(newChat);
|
||||
if (!chatType.equals(ChatType.WHISPER)) {
|
||||
newChat.setClosable(false);
|
||||
}
|
||||
return chatViewController;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -267,4 +281,12 @@ public class ChatBoxController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reopenChatTab(Tab chatTab) {
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
chatTabPane.getTabs().add(chatTab);
|
||||
chatTabPane.getSelectionModel().select(chatTab);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+26
-11
@@ -11,37 +11,48 @@ import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
/** Responsible for the presentation of the ChatModel to the Client */
|
||||
public class ChatViewController implements Initializable {
|
||||
|
||||
private final ChatBoxController chatBoxController;
|
||||
@FXML private Button sendButton;
|
||||
|
||||
@FXML private TextField inputField;
|
||||
|
||||
@FXML private VBox chatInterfaceVBox;
|
||||
|
||||
@FXML private HBox controlBar;
|
||||
|
||||
@FXML private ScrollPane scrollPane;
|
||||
|
||||
@FXML private VBox chat;
|
||||
|
||||
private final ChatModel chatModel;
|
||||
public Tab getChatTab() {
|
||||
return chatTab;
|
||||
}
|
||||
|
||||
private final String username;
|
||||
public void setChatTab(Tab chatTab) {
|
||||
this.chatTab = chatTab;
|
||||
}
|
||||
|
||||
@FXML private Tab chatTab;
|
||||
|
||||
public Boolean tabIsOpen;
|
||||
|
||||
private final ChatModel chatModel;
|
||||
|
||||
private final ChatController controller;
|
||||
|
||||
private static final int CHAT_PADDING = 20;
|
||||
|
||||
public ChatViewController(ChatController chatController, ChatModel chatModel, String username) {
|
||||
public ChatViewController(
|
||||
ChatController chatController,
|
||||
ChatModel chatModel,
|
||||
ChatBoxController chatBoxController) {
|
||||
this.controller = chatController;
|
||||
this.username = username;
|
||||
this.chatModel = chatModel;
|
||||
this.chatBoxController = chatBoxController;
|
||||
tabIsOpen = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,8 +65,8 @@ public class ChatViewController implements Initializable {
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resourceBundle) {
|
||||
inputField.setOnAction(event -> sendMessage());
|
||||
sendButton.setOnAction(event -> sendMessage());
|
||||
inputField.setOnAction(_ -> sendMessage());
|
||||
sendButton.setOnAction(_ -> sendMessage());
|
||||
scrollPane.vvalueProperty().bind(chat.heightProperty());
|
||||
}
|
||||
|
||||
@@ -88,6 +99,10 @@ public class ChatViewController implements Initializable {
|
||||
* @param msg The {@link Message} object containing the content and metadata to display.
|
||||
*/
|
||||
public void showMessage(Message msg) {
|
||||
if (!tabIsOpen) {
|
||||
tabIsOpen = true;
|
||||
chatBoxController.reopenChatTab(chatTab);
|
||||
}
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
String msgText =
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<?import javafx.scene.control.skin.TabPaneSkin.TabContentRegion?>
|
||||
<VBox xmlns="http://javafx.com/javafx/21"
|
||||
xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:id="chatBox"
|
||||
VBox.vgrow="ALWAYS"
|
||||
stylesheets="@chatui.css"
|
||||
styleClass="chat-box"
|
||||
spacing="10"
|
||||
spacing="20"
|
||||
maxWidth="Infinity">
|
||||
|
||||
<HBox spacing="10"
|
||||
@@ -17,14 +18,14 @@
|
||||
|
||||
<Label text="== CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
|
||||
<Region HBox.hgrow="ALWAYS"/>
|
||||
<MenuButton fx:id="addWhisperChatButton" styleClass="yellow-button" text="WHISPER CHAT"
|
||||
<MenuButton fx:id="addWhisperChatButton" styleClass="menu-button" text="WHISPER CHAT"
|
||||
alignment="CENTER_RIGHT">
|
||||
</MenuButton>
|
||||
</HBox>
|
||||
|
||||
<TabPane fx:id="chatTabPane"
|
||||
VBox.vgrow="ALWAYS"
|
||||
styleClass="tab-header-area">
|
||||
styleClass="tab-pane">
|
||||
|
||||
</TabPane>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<VBox fx:id="chatInterfaceVBox"
|
||||
maxWidth="Infinity"
|
||||
spacing="10"
|
||||
styleClass="chat-box"
|
||||
styleClass="tab-chat-box"
|
||||
stylesheets="@chatui.css"
|
||||
VBox.vgrow="ALWAYS"
|
||||
xmlns="http://javafx.com/javafx/17.0.12"
|
||||
|
||||
@@ -5,7 +5,17 @@
|
||||
-fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10;
|
||||
-fx-border-width: 12;
|
||||
-fx-padding: 20;
|
||||
/*-fx-effect: dropshadow(one-pass-box, rgba(0,0,0,1), 0, 0, 15, 15);*/
|
||||
-fx-effect: dropshadow(one-pass-box, rgba(0,0,0,1), 0, 0, 15, 15);
|
||||
}
|
||||
|
||||
.tab-chat-box {
|
||||
|
||||
-fx-background-color: #0d9e3b;
|
||||
-fx-background-radius: 58;
|
||||
-fx-border-radius: 50;
|
||||
-fx-border-color: #0d763b #0d623b #0d623b #0d763b;
|
||||
-fx-border-width: 12;
|
||||
-fx-padding: 20;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
@@ -163,25 +173,25 @@
|
||||
-fx-border-width: 5;
|
||||
-fx-padding: 10;
|
||||
-fx-effect: dropshadow(one-pass-box, rgba(0,0,0,1), 0, 0, 15, 15);
|
||||
-fx-max-height: 10;
|
||||
-fx-min-height: 10;
|
||||
}
|
||||
|
||||
.tab-pane .tab {
|
||||
-fx-background-color: #0d9e3b;
|
||||
-fx-background-radius: 18;
|
||||
-fx-background-color: #0d983b;
|
||||
-fx-background-radius: 28;
|
||||
-fx-border-radius: 10;
|
||||
-fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10;
|
||||
-fx-border-color: #0d873b #0d733b #0d733b #0d873b;
|
||||
-fx-border-width: 5;
|
||||
-fx-padding: 10;
|
||||
-fx-padding: 6 15;
|
||||
}
|
||||
|
||||
.tab-pane .tab:selected {
|
||||
-fx-background-color: #0d763b;
|
||||
-fx-background-color: #0d873b;
|
||||
-fx-background-radius: 18;
|
||||
-fx-border-radius: 10;
|
||||
-fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10;
|
||||
-fx-border-color: #0d763b #0d623b #0d623b #0d763b;
|
||||
-fx-border-width: 5;
|
||||
-fx-padding: 10;
|
||||
-fx-padding: 6 15;
|
||||
}
|
||||
|
||||
.tab-pane .tab .tab-close-button {
|
||||
@@ -192,7 +202,6 @@
|
||||
-fx-background-color: #0d9e3b;
|
||||
}
|
||||
|
||||
|
||||
.tab .tab-label {
|
||||
-fx-alignment: CENTER;
|
||||
-fx-text-fill: #ffffff;
|
||||
@@ -204,3 +213,36 @@
|
||||
-fx-alignment: CENTER;
|
||||
-fx-text-fill: #ffffff;
|
||||
}
|
||||
|
||||
.menu-button {
|
||||
-fx-background-color: #b8860b;
|
||||
-fx-border-color: #ffd700;
|
||||
-fx-text-fill: #ffffff;
|
||||
-fx-background-radius: 12;
|
||||
-fx-border-radius: 12;
|
||||
-fx-font-family: "Courier New";
|
||||
-fx-font-weight: bold;
|
||||
-fx-border-width: 2;
|
||||
-fx-padding: 6 15;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
.menu-button .context-menu {
|
||||
-fx-background-color: #b8860b;
|
||||
-fx-background-radius: 4;
|
||||
-fx-padding: 6 15;
|
||||
-fx-cursor: hand;
|
||||
|
||||
}
|
||||
|
||||
.menu-button:hover {
|
||||
-fx-translate-y: -3;
|
||||
-fx-effect: dropshadow(one-pass-box, rgba(0, 0, 0, 0.8), 0, 0, 3, 3);
|
||||
}
|
||||
|
||||
.menu-button .menu-item {
|
||||
-fx-background-color: #b8860b;
|
||||
-fx-border-color: #ffd700;
|
||||
-fx-text-fill: #ffffff
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user