feat: sync chat with user selection

This commit is contained in:
Arnaud Vergnet 2020-12-02 12:16:30 +01:00
parent 657ab85915
commit ca8e267fb3
14 changed files with 131 additions and 59 deletions

View file

@ -1,42 +1,60 @@
package fr.insa.clavardator.chat;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.users.User;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.PeerUser;
import fr.insa.clavardator.users.UserList;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Date;
public class ChatHistory {
private final DatabaseController db;
private final User user;
private ArrayList<Message> history = new ArrayList<>();
private final PeerUser user;
private final ArrayList<HistoryLoadedCallback> historyListener;
private final ArrayList<MessageAddedCallback> messageListener;
private ArrayList<Message> history;
public ChatHistory(User user) {
public ChatHistory(PeerUser user) {
this.user = user;
db = new DatabaseController(user);
this.historyListener = new ArrayList<>();
this.messageListener = new ArrayList<>();
}
// Make this class observable
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public void addObserver(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
public void addHistoryLoadedListener(HistoryLoadedCallback listener) {
historyListener.add(listener);
}
public void removeObserver(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
public void addMessageAddedListener(MessageAddedCallback listener) {
messageListener.add(listener);
}
private void notifyHistoryLoaded() {
historyListener.forEach(l -> l.onHistoryLoaded(history));
}
private void getHistory() {
db.getChatHistory(new Date(), new Date(), // TODO: put actual date
newHistory -> {
ArrayList<Message> oldHistory = history;
history = newHistory;
pcs.firePropertyChange("history", oldHistory, history); // Does this work?
});
private void notifyMessageAdded(Message message) {
messageListener.forEach(l -> l.onMessageAdded(message));
}
public void load() {
if (history == null) {
// TODO remove after tests
CurrentUser currentUser = new CurrentUser("Moi", new UserList());
history = new ArrayList<>();
history.add(new Message(user, currentUser, "Coucou toi"));
history.add(new Message(currentUser, user, "Coucou " + user.getUsername()));
history.add(new Message(user, currentUser, "oui"));
history.add(new Message(currentUser, user, "merci"));
notifyHistoryLoaded();
// db.getChatHistory(new Date(), new Date(), // TODO: put actual date
// newHistory -> {
// history = newHistory;
// notifyHistoryLoaded();
// });
} else {
notifyHistoryLoaded();
}
}
@ -44,12 +62,18 @@ public class ChatHistory {
* @param message
*/
public void addMessage(Message message) {
db.addMessage(message, new DatabaseController.MessageCallback() {
@Override
public void onMessageSaved(Message savedMessage) {
history.add(savedMessage);
pcs.firePropertyChange("history", null, history);
}
db.addMessage(message, () -> {
history.add(message);
notifyMessageAdded(message);
});
}
public interface MessageAddedCallback {
void onMessageAdded(Message message);
}
public interface HistoryLoadedCallback {
void onHistoryLoaded(ArrayList<Message> history);
}
}

View file

@ -1,14 +1,13 @@
package fr.insa.clavardator.chat;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.User;
import java.io.Serializable;
public class Message implements Serializable {
private String text;
private final User recipient;
private final User sender;
private final String text;
public Message(User sender, User recipient) {
this(sender, recipient, "");

View file

@ -57,6 +57,6 @@ public class DatabaseController {
}
public interface MessageCallback {
void onMessageSaved(Message history);
void onMessageSaved();
}
}

View file

@ -2,6 +2,8 @@ package fr.insa.clavardator.ui;
import fr.insa.clavardator.ui.chat.ChatController;
import fr.insa.clavardator.ui.users.UserListController;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.UserList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
@ -17,11 +19,13 @@ public class MainController implements Initializable {
@Override
public void initialize(URL url, ResourceBundle rb) {
chatController.setCurrentUser(new CurrentUser("Moi", new UserList()));
userListController.addRefreshUserListener(() -> {
System.out.println("refresh event");
});
userListController.addUserSelectedListener((user) -> {
System.out.println(user.getUsername());
chatController.setRemoteUser(user);
});
chatController.addAttachmentListener(() -> {
System.out.println("attach event");

View file

@ -1,7 +1,7 @@
package fr.insa.clavardator.ui;
import fr.insa.clavardator.users.User;
import fr.insa.clavardator.users.PeerUser;
public interface UserSelectedEvent {
public void onSelected(User user);
void onSelected(PeerUser user);
}

View file

@ -1,8 +1,10 @@
package fr.insa.clavardator.ui.chat;
import fr.insa.clavardator.chat.ChatHistory;
import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.ui.ButtonPressEvent;
import fr.insa.clavardator.ui.NoSelectionModel;
import fr.insa.clavardator.users.ActiveUser;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.PeerUser;
import javafx.collections.FXCollections;
@ -12,6 +14,7 @@ import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
public class ChatController implements Initializable {
@ -40,25 +43,32 @@ public class ChatController implements Initializable {
public void setCurrentUser(CurrentUser currentUser) {
this.chatHeaderController.setCurrentUser(currentUser);
this.currentUser = currentUser;
}
public void setRemoteUser(PeerUser remoteUser) {
this.remoteUser = remoteUser;
loadMessageList();
this.chatHeaderController.setRemoteUser(remoteUser);
this.chatFooterController.setEnabled(remoteUser instanceof ActiveUser);
final ChatHistory history = remoteUser.getHistory();
history.addHistoryLoadedListener(this::onHistoryLoaded);
history.addMessageAddedListener(this::onMessageAdded);
history.load();
}
private void loadMessageList() {
ObservableList<Message> messages = FXCollections.observableArrayList(
new Message(remoteUser, currentUser, "Messsssage 1"),
new Message(remoteUser, currentUser, "Messsssage 2"),
new Message(currentUser, remoteUser, "Messsssage 3"),
new Message(remoteUser, currentUser, "Messsssage 4")
);
messageList.setItems(messages);
private void onHistoryLoaded(ArrayList<Message> messages) {
messageList.setItems(FXCollections.observableArrayList(messages));
messageList.scrollTo(messageList.getItems().size() - 1);
}
private void onMessageAdded(Message message) {
messageList.getItems().add(message);
messageList.scrollTo(messageList.getItems().size() - 1);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
messageList.setItems(null);

View file

@ -1,7 +1,9 @@
package fr.insa.clavardator.ui.chat;
import fr.insa.clavardator.ui.ButtonPressEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.HBox;
import java.net.URL;
import java.util.ArrayList;
@ -10,6 +12,9 @@ import java.util.ResourceBundle;
public class ChatFooterController implements Initializable {
@FXML
private HBox container;
private List<ButtonPressEvent> attachmentListeners;
private List<ButtonPressEvent> sendListeners;
@ -27,6 +32,10 @@ public class ChatFooterController implements Initializable {
sendListeners.forEach(ButtonPressEvent::onPress);
}
public void setEnabled(boolean enabled) {
container.setDisable(!enabled);
}
@Override
public void initialize(URL location, ResourceBundle resources) {
attachmentListeners = new ArrayList<>();

View file

@ -1,7 +1,12 @@
package fr.insa.clavardator.ui.chat;
import fr.insa.clavardator.ui.ButtonPressEvent;
import fr.insa.clavardator.ui.users.UserActiveIndicatorController;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.PeerUser;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import java.net.URL;
import java.util.ArrayList;
@ -10,8 +15,18 @@ import java.util.ResourceBundle;
public class ChatHeaderController implements Initializable {
@FXML
private Label currentUsernameLabel;
@FXML
private Label remoteUsernameLabel;
@FXML
private UserActiveIndicatorController indicatorController;
private List<ButtonPressEvent> editListeners;
private CurrentUser currentUser;
private PeerUser remoteUser;
public void addEditListener(ButtonPressEvent listener) {
editListeners.add(listener);
}
@ -27,4 +42,16 @@ public class ChatHeaderController implements Initializable {
public void initialize(URL location, ResourceBundle resources) {
editListeners = new ArrayList<>();
}
public void setCurrentUser(CurrentUser currentUser) {
this.currentUser = currentUser;
currentUsernameLabel.setText(currentUser.getUsername());
}
public void setRemoteUser(PeerUser remoteUser) {
this.remoteUser = remoteUser;
remoteUsernameLabel.setText(remoteUser.getUsername());
indicatorController.setUser(remoteUser);
indicatorController.setSize(10.0);
}
}

View file

@ -28,4 +28,8 @@ public class UserActiveIndicatorController implements Initializable {
}
}
public void setSize(double value) {
circle.setRadius(value);
}
}

View file

@ -23,7 +23,7 @@ public class UserListController implements Initializable {
final private List<ButtonPressEvent> refreshUserListeners;
final private List<UserSelectedEvent> userSelectedListeners;
@FXML
private ListView<User> userList;
private ListView<PeerUser> userList;
public UserListController() {
super();
@ -43,7 +43,7 @@ public class UserListController implements Initializable {
refreshUserListeners.forEach(ButtonPressEvent::onPress);
}
private void onUserSelected(@org.jetbrains.annotations.NotNull User user) {
private void onUserSelected(@org.jetbrains.annotations.NotNull PeerUser user) {
final User currentSelectedUser = userList.getSelectionModel().getSelectedItem();
if (!user.equals(currentSelectedUser)) {
userList.getSelectionModel().select(user);
@ -53,7 +53,7 @@ public class UserListController implements Initializable {
@Override
public void initialize(URL url, ResourceBundle rb) {
ObservableList<User> activeList = null;
ObservableList<PeerUser> activeList = null;
try {
activeList = FXCollections.observableArrayList(
new PeerUser("Dodo0"),

View file

@ -1,13 +1,13 @@
package fr.insa.clavardator.ui.users;
import fr.insa.clavardator.ui.UserSelectedEvent;
import fr.insa.clavardator.users.User;
import fr.insa.clavardator.users.PeerUser;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ListCell;
import java.io.IOException;
public class UserListItemCell extends ListCell<User> {
public class UserListItemCell extends ListCell<PeerUser> {
private UserSelectedEvent listener;
@ -20,7 +20,7 @@ public class UserListItemCell extends ListCell<User> {
}
@Override
protected void updateItem(User item, boolean empty) {
protected void updateItem(PeerUser item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
final FXMLLoader cellLoader = new FXMLLoader(getClass().getResource("userListItem.fxml"));

View file

@ -8,7 +8,7 @@
<HBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="fr.insa.clavardator.ui.chat.ChatFooterController"
stylesheets="@../styles.css" styleClass="container" alignment="CENTER" spacing="10.0">
stylesheets="@../styles.css" styleClass="container" alignment="CENTER" spacing="10.0" fx:id="container">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>

View file

@ -15,7 +15,7 @@
<Insets left="20" right="20"/>
</padding>
<Label text="Connecté en tant que : "/>
<Label text="&lt;USERNAME&gt;"/>
<Label text="&lt;USERNAME&gt;" fx:id="currentUsernameLabel"/>
<JFXButton mnemonicParsing="false" onMouseClicked="#onEditPress">
<graphic>
<FontIcon iconLiteral="fas-user-edit" iconSize="24"/>
@ -32,7 +32,7 @@
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</padding>
<Circle radius="7.0" styleClass="active-user-dot"/>
<Label text="USER NAME" styleClass="current-user"/>
<fx:include source="../users/userActiveIndicator.fxml" fx:id="indicator" />
<Label text="USER NAME" styleClass="current-user" fx:id="remoteUsernameLabel"/>
</HBox>
</VBox>

View file

@ -1,16 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.Circle?>
<AnchorPane xmlns="http://javafx.com/javafx"
<HBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="fr.insa.clavardator.ui.users.UserActiveIndicatorController"
stylesheets="@../styles.css"
styleClass="inner">
stylesheets="@../styles.css" alignment="CENTER">
<Circle fx:id="circle" radius="5.0" styleClass="active-user-dot"/>
</AnchorPane>
</HBox>