|
|
@@ -0,0 +1,259 @@
|
|
|
+package space.anyi.chatClient.ui.controller;
|
|
|
+
|
|
|
+import javafx.application.Platform;
|
|
|
+import javafx.collections.FXCollections;
|
|
|
+import javafx.collections.ObservableList;
|
|
|
+import javafx.event.ActionEvent;
|
|
|
+import javafx.fxml.FXML;
|
|
|
+import javafx.fxml.FXMLLoader;
|
|
|
+import javafx.fxml.Initializable;
|
|
|
+import javafx.geometry.Pos;
|
|
|
+import javafx.scene.Node;
|
|
|
+import javafx.scene.Scene;
|
|
|
+import javafx.scene.control.*;
|
|
|
+import javafx.scene.layout.HBox;
|
|
|
+import javafx.scene.layout.VBox;
|
|
|
+import javafx.scene.paint.Color;
|
|
|
+import javafx.stage.Modality;
|
|
|
+import javafx.stage.Stage;
|
|
|
+import lombok.Data;
|
|
|
+import space.anyi.chatClient.core.Client;
|
|
|
+import space.anyi.chatClient.ui.ClientApplication;
|
|
|
+import space.anyi.chatCommom.Message;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.net.URL;
|
|
|
+import java.time.Instant;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.ResourceBundle;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @ProjectName: chat-gwng
|
|
|
+ * @FileName: ClientController
|
|
|
+ * @Author: 杨逸
|
|
|
+ * @Data:2025/9/26 20:09
|
|
|
+ * @Description:
|
|
|
+ */
|
|
|
+@Data
|
|
|
+public class ClientController implements Initializable {
|
|
|
+ private Stage stage;
|
|
|
+ private Client clientServer;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void initialize(URL url, ResourceBundle resourceBundle) {
|
|
|
+
|
|
|
+ }
|
|
|
+ @FXML
|
|
|
+ private Button bu;
|
|
|
+
|
|
|
+ @FXML
|
|
|
+ private TextArea inputMessage;
|
|
|
+
|
|
|
+ @FXML
|
|
|
+ private ScrollPane messagePane;
|
|
|
+
|
|
|
+ @FXML
|
|
|
+ private Label onlineLabel;
|
|
|
+
|
|
|
+ @FXML
|
|
|
+ private VBox userList;
|
|
|
+
|
|
|
+ @FXML
|
|
|
+ void sendMessage(ActionEvent event) {
|
|
|
+ bu.setDisable(true);
|
|
|
+ String content = inputMessage.getText();
|
|
|
+ inputMessage.clear();
|
|
|
+ if (Objects.nonNull(content) && !"".equals(content)) {
|
|
|
+ Message message = new Message(content);
|
|
|
+ message.setType(Message.MessageType.USER);
|
|
|
+ message.setTarget(Message.MessageTarget.GROUP);
|
|
|
+ //message.setSource(name);
|
|
|
+ clientServer.sendMessageWithGroup(message);
|
|
|
+ addMessage(message);
|
|
|
+ }
|
|
|
+ bu.setDisable(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setStage(Stage stage) {
|
|
|
+ this.stage = stage;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setClientServer(Client clientServer) {
|
|
|
+ this.clientServer = clientServer;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void addMessage(Message message) {
|
|
|
+ VBox messageUI = createMessageUI(message);
|
|
|
+ VBox content = (VBox) messagePane.getContent();
|
|
|
+ Platform.runLater(()->{
|
|
|
+ content.getChildren().add(messageUI);
|
|
|
+ });
|
|
|
+
|
|
|
+ //右键菜单
|
|
|
+ if (message.getType() == Message.MessageType.USER) {
|
|
|
+ messageUI.setOnContextMenuRequested(event->{
|
|
|
+ ContextMenu contextMenu = new ContextMenu();
|
|
|
+ //自己的可以触发撤回
|
|
|
+ //别人的可以私聊
|
|
|
+ MenuItem item = null;
|
|
|
+ if (message.getSource().equals(Client.name)) {
|
|
|
+ item = new MenuItem("撤回");
|
|
|
+ item.setOnAction(e->{
|
|
|
+ Alert alert = new Alert(Alert.AlertType.WARNING);
|
|
|
+ alert.setTitle("警告");
|
|
|
+ alert.setHeaderText("撤回消息");
|
|
|
+ alert.setContentText("确定撤回?");
|
|
|
+ alert.showAndWait().ifPresent(buttonType -> {
|
|
|
+ removeMessageUI(messageUI);
|
|
|
+ message.setType(Message.MessageType.SYSTEM);
|
|
|
+ message.setOperate(Message.OperateType.REVOKE);
|
|
|
+ clientServer.revokeMessage(message);
|
|
|
+ });
|
|
|
+
|
|
|
+ });
|
|
|
+ }else{
|
|
|
+ item = new MenuItem("私聊");
|
|
|
+ item.setOnAction(actionEvent->{
|
|
|
+ //创建私聊场景
|
|
|
+ FXMLLoader fxmlLoader = new FXMLLoader();
|
|
|
+ fxmlLoader.setLocation(getClass().getResource("/fxml/privateChatScene.fxml"));
|
|
|
+ try {
|
|
|
+ VBox privateChatPane = fxmlLoader.load();
|
|
|
+ PrivateChatController controller = fxmlLoader.getController();
|
|
|
+ controller.setWriterHandler(clientServer.getWriterHandler());
|
|
|
+ List<Message> list = Client.messageListMap.getOrDefault(message.getSource(), new ArrayList<>());
|
|
|
+ Client.messageListMap.put(message.getSource(),list);
|
|
|
+ controller.setMessageList(list);
|
|
|
+ controller.setName(message.getSource());
|
|
|
+ controller.runTask();
|
|
|
+ Scene scene = new Scene(privateChatPane);
|
|
|
+ Stage stage = new Stage();
|
|
|
+ stage.setTitle("私聊");
|
|
|
+ stage.setScene(scene);
|
|
|
+ stage.setResizable(false);
|
|
|
+ stage.initOwner(ClientApplication.primaryStage);
|
|
|
+ stage.initModality(Modality.WINDOW_MODAL);
|
|
|
+ stage.show();
|
|
|
+ stage.setOnCloseRequest(windowEvent -> {
|
|
|
+ //取消私聊消息列表的更新任务
|
|
|
+ controller.setFlag(false);
|
|
|
+ });
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ contextMenu.getItems().add(item);
|
|
|
+ contextMenu.show(messageUI,event.getScreenX(),event.getScreenY());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private VBox createMessageUI(Message message) {
|
|
|
+ VBox result = new VBox();
|
|
|
+ HBox head = new HBox();
|
|
|
+ Label name = new Label(message.getSource());
|
|
|
+ Label content = new Label(message.getContent());
|
|
|
+ String format = Instant.ofEpochMilli(message.getTimeStamp()).atZone(ZoneId.systemDefault()).toLocalDateTime().format(DateTimeFormatter.ISO_DATE_TIME);
|
|
|
+ Label time = new Label(format);
|
|
|
+ //样式
|
|
|
+ double width = 450;
|
|
|
+ double height = 50;
|
|
|
+ result.setPrefWidth(width);
|
|
|
+ result.setPrefHeight(height);
|
|
|
+ //用背景颜色区分自己的消息
|
|
|
+ if (Client.name.equals(message.getSource())){
|
|
|
+ //自己的
|
|
|
+ result.setStyle("-fx-background-radius: 100;-fx-background-color: #3EB575");
|
|
|
+ }else{
|
|
|
+ //别人的
|
|
|
+ result.setStyle("-fx-background-radius: 100;-fx-background-color: #2E2E2E");
|
|
|
+ }
|
|
|
+ head.setPrefWidth(width);
|
|
|
+ head.setPrefHeight(height-15);
|
|
|
+
|
|
|
+ name.setPrefWidth(100);
|
|
|
+ name.setPrefHeight(height - 15);
|
|
|
+ name.setTextFill(Color.WHITE);
|
|
|
+ name.setAlignment(Pos.CENTER);
|
|
|
+
|
|
|
+ content.setPrefWidth(width - 100);
|
|
|
+ content.setPrefHeight(height - 15);
|
|
|
+ content.setTextFill(Color.WHITE);
|
|
|
+
|
|
|
+ time.setPrefWidth(width);
|
|
|
+ time.setPrefHeight(15);
|
|
|
+ time.setTextFill(Color.GRAY);
|
|
|
+ time.setAlignment(Pos.CENTER);
|
|
|
+
|
|
|
+
|
|
|
+ //组装
|
|
|
+ head.getChildren().addAll(name, content);
|
|
|
+ result.getChildren().addAll(head,time);
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void removeMessageUI(VBox messageUI) {
|
|
|
+ VBox content = (VBox) messagePane.getContent();
|
|
|
+ ObservableList<Node> children = content.getChildren();
|
|
|
+ for (Node child : children) {
|
|
|
+ if (child.equals(messageUI)){
|
|
|
+ children.remove(child);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void updateUserList(String[] userArray) {
|
|
|
+ int size = userArray.length;
|
|
|
+ Platform.runLater(()->{
|
|
|
+ onlineLabel.setText("在线人数:"+size);
|
|
|
+ userList.getChildren().clear();
|
|
|
+ for (int i = 0; i < userArray.length; i++) {
|
|
|
+ userList.getChildren().add(createUserUI(userArray[i]));
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private Label createUserUI(String username) {
|
|
|
+ Label label = new Label(username);
|
|
|
+ label.prefWidth(150);
|
|
|
+ label.setMinWidth(150);
|
|
|
+ label.setMinHeight(30);
|
|
|
+ label.prefHeight(30);
|
|
|
+ label.setAlignment(Pos.CENTER);
|
|
|
+ label.setStyle("-fx-background-color: #363636; -fx-background-radius: 50;");
|
|
|
+ label.setTextFill(Color.WHITE);
|
|
|
+ return label;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void removeMessage(Message message) {
|
|
|
+ VBox content = (VBox) messagePane.getContent();
|
|
|
+ ObservableList<Node> children = content.getChildren();
|
|
|
+ for (Node child : children) {
|
|
|
+ VBox messageUI = (VBox) child;
|
|
|
+ HBox head = (HBox) messageUI.getChildren().get(0);
|
|
|
+ Label nameLabel = (Label) head.getChildren().get(0);
|
|
|
+ Label contentLabel = (Label) head.getChildren().get(1);
|
|
|
+ Label timeLabel = (Label) messageUI.getChildren().get(1);
|
|
|
+ String name1 = nameLabel.getText();
|
|
|
+ String content1 = contentLabel.getText();
|
|
|
+ String time1 = timeLabel.getText();
|
|
|
+ String name2 = message.getSource();
|
|
|
+ String content2 = message.getContent();
|
|
|
+ String time2 = Instant.ofEpochMilli(message.getTimeStamp()).atZone(ZoneId.systemDefault()).toLocalDateTime().format(DateTimeFormatter.ISO_DATE_TIME);
|
|
|
+ if (name1.equals(name2) && content1.equals(content2) && time1.equals(time2)){
|
|
|
+ Platform.runLater(()->{
|
|
|
+ children.remove(child);
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|