fix javafx thread errors and improve chat performance

This commit is contained in:
Arnaud Vergnet 2021-01-03 13:46:46 +01:00
parent e7a77a8670
commit e04b780397
5 changed files with 103 additions and 97 deletions

View file

@ -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<Message> history;
private final ArrayList<HistoryLoadedCallback> historyListener;
private final ArrayList<MessageAddedCallback> messageListener;
private ArrayList<Message> history;
private final ArrayList<Message> 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<Message> 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<Message> history);
void onHistoryLoaded(PeerUser user);
}
}

View file

@ -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<? super Message>) (c) -> {
c.next();
scrollToEnd();
});
history.load();
this.remoteUser = remoteUser;
}
private final ChatHistory.HistoryLoadedCallback onHistoryLoaded = (PeerUser user, ArrayList<Message> 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) {

View file

@ -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<Message> {
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);
}
}
}

View file

@ -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");
}
}
}
}

View file

@ -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<PeerUser> {
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<PeerUser> {
@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());
}
}
}