fix javafx thread errors and improve chat performance
This commit is contained in:
parent
e7a77a8670
commit
e04b780397
5 changed files with 103 additions and 97 deletions
|
@ -4,24 +4,36 @@ import fr.insa.clavardator.db.DatabaseController;
|
||||||
import fr.insa.clavardator.users.CurrentUser;
|
import fr.insa.clavardator.users.CurrentUser;
|
||||||
import fr.insa.clavardator.users.PeerUser;
|
import fr.insa.clavardator.users.PeerUser;
|
||||||
import javafx.application.Platform;
|
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.ArrayList;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
public class ChatHistory {
|
public class ChatHistory {
|
||||||
private final DatabaseController db;
|
private final DatabaseController db;
|
||||||
private final PeerUser user;
|
private final PeerUser user;
|
||||||
|
private final ObservableList<Message> history;
|
||||||
private final ArrayList<HistoryLoadedCallback> historyListener;
|
private final ArrayList<HistoryLoadedCallback> historyListener;
|
||||||
private final ArrayList<MessageAddedCallback> messageListener;
|
private final ArrayList<Message> fakeHistory;
|
||||||
private ArrayList<Message> history;
|
|
||||||
|
|
||||||
public ChatHistory(PeerUser user) {
|
public ChatHistory(PeerUser user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
db = new DatabaseController();
|
db = new DatabaseController();
|
||||||
this.historyListener = new ArrayList<>();
|
history = FXCollections.observableArrayList();
|
||||||
this.messageListener = new ArrayList<>();
|
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) {
|
public void addHistoryLoadedListener(HistoryLoadedCallback listener) {
|
||||||
|
@ -32,67 +44,50 @@ public class ChatHistory {
|
||||||
historyListener.remove(listener);
|
historyListener.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMessageAddedListener(MessageAddedCallback listener) {
|
|
||||||
messageListener.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeMessageAddedListener(MessageAddedCallback listener) {
|
|
||||||
messageListener.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyHistoryLoaded() {
|
private void notifyHistoryLoaded() {
|
||||||
historyListener.forEach(l -> l.onHistoryLoaded(user, history));
|
historyListener.forEach(l -> l.onHistoryLoaded(user));
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyMessageAdded(Message message) {
|
|
||||||
messageListener.forEach(l -> l.onMessageAdded(user, message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load() {
|
public void load() {
|
||||||
if (history == null) {
|
// db.getChatHistory(new Date(), new Date(), // TODO: put actual date
|
||||||
// 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
|
|
||||||
// newHistory -> {
|
// newHistory -> {
|
||||||
// history = newHistory;
|
// history = newHistory;
|
||||||
// notifyHistoryLoaded();
|
// notifyHistoryLoaded();
|
||||||
// });
|
// });
|
||||||
}
|
|
||||||
Timer t = new Timer();
|
Timer t = new Timer();
|
||||||
t.schedule(new TimerTask() {
|
t.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
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();
|
t.cancel();
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ObservableList<Message> getHistory() {
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param message
|
* @param message
|
||||||
*/
|
*/
|
||||||
public void addMessage(Message message) {
|
public void addMessage(Message message) {
|
||||||
db.addMessage(message, () -> {
|
Platform.runLater(() -> history.add(message));
|
||||||
if (history == null) {
|
// db.addMessage(message, () -> {
|
||||||
history = new ArrayList<>();
|
// if (history == null) {
|
||||||
}
|
// history = new ArrayList<>();
|
||||||
history.add(message);
|
// }
|
||||||
notifyMessageAdded(message);
|
// history.add(message);
|
||||||
});
|
// notifyMessageAdded(message);
|
||||||
}
|
// });
|
||||||
|
|
||||||
public interface MessageAddedCallback {
|
|
||||||
void onMessageAdded(PeerUser user, Message message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface HistoryLoadedCallback {
|
public interface HistoryLoadedCallback {
|
||||||
void onHistoryLoaded(PeerUser user, ArrayList<Message> history);
|
void onHistoryLoaded(PeerUser user);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,14 @@ import fr.insa.clavardator.ui.LoadingScreenController;
|
||||||
import fr.insa.clavardator.ui.NoSelectionModel;
|
import fr.insa.clavardator.ui.NoSelectionModel;
|
||||||
import fr.insa.clavardator.users.PeerUser;
|
import fr.insa.clavardator.users.PeerUser;
|
||||||
import fr.insa.clavardator.util.ErrorCallback;
|
import fr.insa.clavardator.util.ErrorCallback;
|
||||||
import fr.insa.clavardator.util.Log;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class ChatController implements Initializable {
|
public class ChatController implements Initializable {
|
||||||
|
@ -29,13 +27,16 @@ public class ChatController implements Initializable {
|
||||||
private ChatHeaderController chatHeaderController;
|
private ChatHeaderController chatHeaderController;
|
||||||
@FXML
|
@FXML
|
||||||
private LoadingScreenController loadingController;
|
private LoadingScreenController loadingController;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private VBox chatContainer;
|
private VBox chatContainer;
|
||||||
@FXML
|
@FXML
|
||||||
private VBox emptyContainer;
|
private VBox emptyContainer;
|
||||||
|
|
||||||
private PeerUser remoteUser;
|
private PeerUser remoteUser;
|
||||||
|
private final ChatHistory.HistoryLoadedCallback onHistoryLoaded = (PeerUser user) -> {
|
||||||
|
if (user.equals(remoteUser)) {
|
||||||
|
setState(State.DONE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public void addAttachmentListener(ButtonPressEvent listener) {
|
public void addAttachmentListener(ButtonPressEvent listener) {
|
||||||
chatFooterController.addAttachmentListener(listener);
|
chatFooterController.addAttachmentListener(listener);
|
||||||
|
@ -53,31 +54,25 @@ public class ChatController implements Initializable {
|
||||||
if (this.remoteUser != null) {
|
if (this.remoteUser != null) {
|
||||||
final ChatHistory oldHistory = this.remoteUser.getHistory();
|
final ChatHistory oldHistory = this.remoteUser.getHistory();
|
||||||
oldHistory.removeHistoryLoadedListener(onHistoryLoaded);
|
oldHistory.removeHistoryLoadedListener(onHistoryLoaded);
|
||||||
oldHistory.removeMessageAddedListener(onMessageAdded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final ChatHistory history = remoteUser.getHistory();
|
final ChatHistory history = remoteUser.getHistory();
|
||||||
history.addHistoryLoadedListener(onHistoryLoaded);
|
history.addHistoryLoadedListener(onHistoryLoaded);
|
||||||
history.addMessageAddedListener(onMessageAdded);
|
messageList.setItems(history.getHistory());
|
||||||
|
messageList.getItems().addListener((ListChangeListener<? super Message>) (c) -> {
|
||||||
|
c.next();
|
||||||
|
scrollToEnd();
|
||||||
|
});
|
||||||
history.load();
|
history.load();
|
||||||
this.remoteUser = remoteUser;
|
this.remoteUser = remoteUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ChatHistory.HistoryLoadedCallback onHistoryLoaded = (PeerUser user, ArrayList<Message> messages) -> {
|
private void scrollToEnd() {
|
||||||
if (user.equals(remoteUser)) {
|
final int size = messageList.getItems().size();
|
||||||
messageList.setItems(FXCollections.observableArrayList(messages));
|
if (size > 0) {
|
||||||
messageList.scrollTo(messageList.getItems().size() - 1);
|
Platform.runLater(() -> messageList.scrollTo(size - 1));
|
||||||
setState(State.DONE);
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
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) {
|
private void setState(State state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
|
|
@ -1,31 +1,36 @@
|
||||||
package fr.insa.clavardator.ui.chat;
|
package fr.insa.clavardator.ui.chat;
|
||||||
|
|
||||||
import fr.insa.clavardator.chat.Message;
|
import fr.insa.clavardator.chat.Message;
|
||||||
import fr.insa.clavardator.users.CurrentUser;
|
|
||||||
import fr.insa.clavardator.users.User;
|
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class MessageListItemCell extends ListCell<Message> {
|
public class MessageListItemCell extends ListCell<Message> {
|
||||||
|
|
||||||
|
private MessageListItemController messageListItemController;
|
||||||
|
private Node view;
|
||||||
|
|
||||||
public MessageListItemCell() {
|
public MessageListItemCell() {
|
||||||
setStyle("-fx-padding: 0px");
|
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
|
@Override
|
||||||
protected void updateItem(Message item, boolean empty) {
|
protected void updateItem(Message item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
if (item != null) {
|
if (item == null || empty) {
|
||||||
try {
|
setGraphic(null);
|
||||||
FXMLLoader cellLoader = new FXMLLoader(getClass().getResource("messageListItem.fxml"));
|
} else {
|
||||||
setGraphic(cellLoader.load());
|
setGraphic(view);
|
||||||
final MessageListItemController userListItemController = cellLoader.getController();
|
messageListItemController.setMessage(item);
|
||||||
userListItemController.setMessage(item);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,6 +15,8 @@ import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class MessageListItemController implements Initializable {
|
public class MessageListItemController implements Initializable {
|
||||||
|
|
||||||
|
private Message currentMessage;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private VBox container;
|
private VBox container;
|
||||||
@FXML
|
@FXML
|
||||||
|
@ -28,14 +30,19 @@ public class MessageListItemController implements Initializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessage(Message message) {
|
public void setMessage(Message message) {
|
||||||
button.setText(message.getText());
|
if (!message.equals(currentMessage)) {
|
||||||
timestamp.setText(DateFormat.getTimeInstance().format(message.getDate()));
|
currentMessage = message;
|
||||||
if (message.getSender().id == CurrentUser.getInstance().getId()) {
|
button.setText(message.getText());
|
||||||
container.setAlignment(Pos.CENTER_RIGHT);
|
timestamp.setText(DateFormat.getTimeInstance().format(message.getDate()));
|
||||||
button.getStyleClass().add("message-self");
|
if (message.getSender().id == CurrentUser.getInstance().getId()) {
|
||||||
} else {
|
container.setAlignment(Pos.CENTER_RIGHT);
|
||||||
container.setAlignment(Pos.CENTER_LEFT);
|
button.getStyleClass().remove("message-other");
|
||||||
button.getStyleClass().add("message-other");
|
button.getStyleClass().add("message-self");
|
||||||
|
} else {
|
||||||
|
container.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
button.getStyleClass().remove("message-self");
|
||||||
|
button.getStyleClass().add("message-other");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ package fr.insa.clavardator.ui.users;
|
||||||
import fr.insa.clavardator.ui.UserSelectedEvent;
|
import fr.insa.clavardator.ui.UserSelectedEvent;
|
||||||
import fr.insa.clavardator.users.PeerUser;
|
import fr.insa.clavardator.users.PeerUser;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -10,9 +11,18 @@ import java.io.IOException;
|
||||||
public class UserListItemCell extends ListCell<PeerUser> {
|
public class UserListItemCell extends ListCell<PeerUser> {
|
||||||
|
|
||||||
private UserSelectedEvent listener;
|
private UserSelectedEvent listener;
|
||||||
|
private UserListItemController userListItemController;
|
||||||
|
private Node view;
|
||||||
|
|
||||||
public UserListItemCell() {
|
public UserListItemCell() {
|
||||||
setStyle("-fx-padding: 0px");
|
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) {
|
public void setOnUserSelectedListener(UserSelectedEvent listener) {
|
||||||
|
@ -22,23 +32,17 @@ public class UserListItemCell extends ListCell<PeerUser> {
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(PeerUser item, boolean empty) {
|
protected void updateItem(PeerUser item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
if (!empty && item != null) {
|
if (item == null || empty) {
|
||||||
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 {
|
|
||||||
setGraphic(null);
|
setGraphic(null);
|
||||||
|
} else {
|
||||||
|
setGraphic(view);
|
||||||
|
userListItemController.setUser(item);
|
||||||
|
userListItemController.setOnPressListener(() -> {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onSelected(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
userListItemController.setSelected(isSelected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue