From e04b780397d58e945dd1905360d7c245a96f1efc Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Sun, 3 Jan 2021 13:46:46 +0100 Subject: [PATCH] fix javafx thread errors and improve chat performance --- .../fr/insa/clavardator/chat/ChatHistory.java | 77 +++++++++---------- .../clavardator/ui/chat/ChatController.java | 37 ++++----- .../ui/chat/MessageListItemCell.java | 27 ++++--- .../ui/chat/MessageListItemController.java | 23 ++++-- .../ui/users/UserListItemCell.java | 36 +++++---- 5 files changed, 103 insertions(+), 97 deletions(-) diff --git a/src/main/java/fr/insa/clavardator/chat/ChatHistory.java b/src/main/java/fr/insa/clavardator/chat/ChatHistory.java index ade1d64..d868ba0 100644 --- a/src/main/java/fr/insa/clavardator/chat/ChatHistory.java +++ b/src/main/java/fr/insa/clavardator/chat/ChatHistory.java @@ -4,24 +4,36 @@ import fr.insa.clavardator.db.DatabaseController; import fr.insa.clavardator.users.CurrentUser; import fr.insa.clavardator.users.PeerUser; import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class ChatHistory { private final DatabaseController db; private final PeerUser user; + private final ObservableList history; private final ArrayList historyListener; - private final ArrayList messageListener; - private ArrayList history; + private final ArrayList fakeHistory; + public ChatHistory(PeerUser user) { this.user = user; db = new DatabaseController(); - this.historyListener = new ArrayList<>(); - this.messageListener = new ArrayList<>(); + history = FXCollections.observableArrayList(); + historyListener = new ArrayList<>(); + fakeHistory = new ArrayList<>(); + CurrentUser currentUser = CurrentUser.getInstance(); + try { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + fakeHistory.add(new Message(user, currentUser, format.parse("2021-01-01 10:00:00"), "Coucou toi")); + } catch (ParseException e) { + e.printStackTrace(); + } } public void addHistoryLoadedListener(HistoryLoadedCallback listener) { @@ -32,67 +44,50 @@ public class ChatHistory { historyListener.remove(listener); } - public void addMessageAddedListener(MessageAddedCallback listener) { - messageListener.add(listener); - } - - public void removeMessageAddedListener(MessageAddedCallback listener) { - messageListener.remove(listener); - } - private void notifyHistoryLoaded() { - historyListener.forEach(l -> l.onHistoryLoaded(user, history)); - } - - private void notifyMessageAdded(Message message) { - messageListener.forEach(l -> l.onMessageAdded(user, message)); + historyListener.forEach(l -> l.onHistoryLoaded(user)); } public void load() { - if (history == null) { - // TODO remove after tests - CurrentUser currentUser = CurrentUser.getInstance(); - history = new ArrayList<>(); - history.add(new Message(user, currentUser, new Date(), "Coucou toi")); - history.add(new Message(currentUser, user, new Date(),"Coucou " + user.getUsername())); - history.add(new Message(user, currentUser, new Date(),"oui")); - history.add(new Message(currentUser, user, new Date(),"merci")); -// db.getChatHistory(new Date(), new Date(), // TODO: put actual date +// db.getChatHistory(new Date(), new Date(), // TODO: put actual date // newHistory -> { // history = newHistory; // notifyHistoryLoaded(); // }); - } Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run() { - Platform.runLater(() -> notifyHistoryLoaded()); + Platform.runLater(() -> { + history.addAll(fakeHistory); + history.sort((message, t1) -> (int) (message.getDate().getTime() - t1.getDate().getTime())); + }); + notifyHistoryLoaded(); t.cancel(); } }, 1000); } + public ObservableList getHistory() { + return history; + } /** * @param message */ public void addMessage(Message message) { - db.addMessage(message, () -> { - if (history == null) { - history = new ArrayList<>(); - } - history.add(message); - notifyMessageAdded(message); - }); - } - - public interface MessageAddedCallback { - void onMessageAdded(PeerUser user, Message message); + Platform.runLater(() -> history.add(message)); +// db.addMessage(message, () -> { +// if (history == null) { +// history = new ArrayList<>(); +// } +// history.add(message); +// notifyMessageAdded(message); +// }); } public interface HistoryLoadedCallback { - void onHistoryLoaded(PeerUser user, ArrayList history); + void onHistoryLoaded(PeerUser user); } } diff --git a/src/main/java/fr/insa/clavardator/ui/chat/ChatController.java b/src/main/java/fr/insa/clavardator/ui/chat/ChatController.java index c9effb7..47b390a 100644 --- a/src/main/java/fr/insa/clavardator/ui/chat/ChatController.java +++ b/src/main/java/fr/insa/clavardator/ui/chat/ChatController.java @@ -7,16 +7,14 @@ import fr.insa.clavardator.ui.LoadingScreenController; import fr.insa.clavardator.ui.NoSelectionModel; import fr.insa.clavardator.users.PeerUser; import fr.insa.clavardator.util.ErrorCallback; -import fr.insa.clavardator.util.Log; import javafx.application.Platform; -import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.ListView; import javafx.scene.layout.VBox; import java.net.URL; -import java.util.ArrayList; import java.util.ResourceBundle; public class ChatController implements Initializable { @@ -29,13 +27,16 @@ public class ChatController implements Initializable { private ChatHeaderController chatHeaderController; @FXML private LoadingScreenController loadingController; - @FXML private VBox chatContainer; @FXML private VBox emptyContainer; - private PeerUser remoteUser; + private final ChatHistory.HistoryLoadedCallback onHistoryLoaded = (PeerUser user) -> { + if (user.equals(remoteUser)) { + setState(State.DONE); + } + }; public void addAttachmentListener(ButtonPressEvent listener) { chatFooterController.addAttachmentListener(listener); @@ -53,31 +54,25 @@ public class ChatController implements Initializable { if (this.remoteUser != null) { final ChatHistory oldHistory = this.remoteUser.getHistory(); oldHistory.removeHistoryLoadedListener(onHistoryLoaded); - oldHistory.removeMessageAddedListener(onMessageAdded); } final ChatHistory history = remoteUser.getHistory(); history.addHistoryLoadedListener(onHistoryLoaded); - history.addMessageAddedListener(onMessageAdded); + messageList.setItems(history.getHistory()); + messageList.getItems().addListener((ListChangeListener) (c) -> { + c.next(); + scrollToEnd(); + }); history.load(); this.remoteUser = remoteUser; } - private final ChatHistory.HistoryLoadedCallback onHistoryLoaded = (PeerUser user, ArrayList messages) -> { - if (user.equals(remoteUser)) { - messageList.setItems(FXCollections.observableArrayList(messages)); - messageList.scrollTo(messageList.getItems().size() - 1); - setState(State.DONE); + private void scrollToEnd() { + final int size = messageList.getItems().size(); + if (size > 0) { + Platform.runLater(() -> messageList.scrollTo(size - 1)); } - }; - - private final ChatHistory.MessageAddedCallback onMessageAdded = (PeerUser user, Message message) -> { - Log.v(this.getClass().getSimpleName(), "Message added: " + message.getText()); - Platform.runLater(() -> { - messageList.getItems().add(message); - messageList.scrollTo(messageList.getItems().size() - 1); - }); - }; + } private void setState(State state) { switch (state) { diff --git a/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemCell.java b/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemCell.java index 53c915a..6e5c72a 100644 --- a/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemCell.java +++ b/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemCell.java @@ -1,31 +1,36 @@ package fr.insa.clavardator.ui.chat; import fr.insa.clavardator.chat.Message; -import fr.insa.clavardator.users.CurrentUser; -import fr.insa.clavardator.users.User; import javafx.fxml.FXMLLoader; +import javafx.scene.Node; import javafx.scene.control.ListCell; import java.io.IOException; public class MessageListItemCell extends ListCell { + private MessageListItemController messageListItemController; + private Node view; + public MessageListItemCell() { setStyle("-fx-padding: 0px"); + FXMLLoader cellLoader = new FXMLLoader(getClass().getResource("messageListItem.fxml")); + try { + view = cellLoader.load(); + messageListItemController = cellLoader.getController(); + } catch (IOException e) { + e.printStackTrace(); + } } @Override protected void updateItem(Message item, boolean empty) { super.updateItem(item, empty); - if (item != null) { - try { - FXMLLoader cellLoader = new FXMLLoader(getClass().getResource("messageListItem.fxml")); - setGraphic(cellLoader.load()); - final MessageListItemController userListItemController = cellLoader.getController(); - userListItemController.setMessage(item); - } catch (IOException e) { - e.printStackTrace(); - } + if (item == null || empty) { + setGraphic(null); + } else { + setGraphic(view); + messageListItemController.setMessage(item); } } } \ No newline at end of file diff --git a/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemController.java b/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemController.java index 2542de1..cffaf1a 100644 --- a/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemController.java +++ b/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemController.java @@ -15,6 +15,8 @@ import java.util.ResourceBundle; public class MessageListItemController implements Initializable { + private Message currentMessage; + @FXML private VBox container; @FXML @@ -28,14 +30,19 @@ public class MessageListItemController implements Initializable { } public void setMessage(Message message) { - button.setText(message.getText()); - timestamp.setText(DateFormat.getTimeInstance().format(message.getDate())); - if (message.getSender().id == CurrentUser.getInstance().getId()) { - container.setAlignment(Pos.CENTER_RIGHT); - button.getStyleClass().add("message-self"); - } else { - container.setAlignment(Pos.CENTER_LEFT); - button.getStyleClass().add("message-other"); + if (!message.equals(currentMessage)) { + currentMessage = message; + button.setText(message.getText()); + timestamp.setText(DateFormat.getTimeInstance().format(message.getDate())); + if (message.getSender().id == CurrentUser.getInstance().getId()) { + container.setAlignment(Pos.CENTER_RIGHT); + button.getStyleClass().remove("message-other"); + button.getStyleClass().add("message-self"); + } else { + container.setAlignment(Pos.CENTER_LEFT); + button.getStyleClass().remove("message-self"); + button.getStyleClass().add("message-other"); + } } } } \ No newline at end of file diff --git a/src/main/java/fr/insa/clavardator/ui/users/UserListItemCell.java b/src/main/java/fr/insa/clavardator/ui/users/UserListItemCell.java index db9e6a4..ff5181f 100644 --- a/src/main/java/fr/insa/clavardator/ui/users/UserListItemCell.java +++ b/src/main/java/fr/insa/clavardator/ui/users/UserListItemCell.java @@ -3,6 +3,7 @@ package fr.insa.clavardator.ui.users; import fr.insa.clavardator.ui.UserSelectedEvent; import fr.insa.clavardator.users.PeerUser; import javafx.fxml.FXMLLoader; +import javafx.scene.Node; import javafx.scene.control.ListCell; import java.io.IOException; @@ -10,9 +11,18 @@ import java.io.IOException; public class UserListItemCell extends ListCell { private UserSelectedEvent listener; + private UserListItemController userListItemController; + private Node view; public UserListItemCell() { setStyle("-fx-padding: 0px"); + FXMLLoader cellLoader = new FXMLLoader(getClass().getResource("userListItem.fxml")); + try { + view = cellLoader.load(); + userListItemController = cellLoader.getController(); + } catch (IOException e) { + e.printStackTrace(); + } } public void setOnUserSelectedListener(UserSelectedEvent listener) { @@ -22,23 +32,17 @@ public class UserListItemCell extends ListCell { @Override protected void updateItem(PeerUser item, boolean empty) { super.updateItem(item, empty); - if (!empty && item != null) { - final FXMLLoader cellLoader = new FXMLLoader(getClass().getResource("userListItem.fxml")); - try { - setGraphic(cellLoader.load()); - UserListItemController userListItemController = cellLoader.getController(); - userListItemController.setUser(item); - userListItemController.setOnPressListener(() -> { - if (listener != null) { - listener.onSelected(item); - } - }); - userListItemController.setSelected(isSelected()); - } catch (IOException e) { - e.printStackTrace(); - } - } else { + if (item == null || empty) { setGraphic(null); + } else { + setGraphic(view); + userListItemController.setUser(item); + userListItemController.setOnPressListener(() -> { + if (listener != null) { + listener.onSelected(item); + } + }); + userListItemController.setSelected(isSelected()); } } }