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; package fr.insa.clavardator.chat;
import fr.insa.clavardator.db.DatabaseController; 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.ArrayList;
import java.util.Date;
public class ChatHistory { public class ChatHistory {
private final DatabaseController db; private final DatabaseController db;
private final User user; private final PeerUser user;
private ArrayList<Message> history = new ArrayList<>(); 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; this.user = user;
db = new DatabaseController(user); db = new DatabaseController(user);
this.historyListener = new ArrayList<>();
this.messageListener = new ArrayList<>();
} }
// Make this class observable public void addHistoryLoadedListener(HistoryLoadedCallback listener) {
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); historyListener.add(listener);
public void addObserver(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
} }
public void removeObserver(PropertyChangeListener listener) { public void addMessageAddedListener(MessageAddedCallback listener) {
pcs.removePropertyChangeListener(listener); messageListener.add(listener);
} }
private void notifyHistoryLoaded() {
historyListener.forEach(l -> l.onHistoryLoaded(history));
}
private void getHistory() { private void notifyMessageAdded(Message message) {
db.getChatHistory(new Date(), new Date(), // TODO: put actual date messageListener.forEach(l -> l.onMessageAdded(message));
newHistory -> { }
ArrayList<Message> oldHistory = history;
history = newHistory; public void load() {
pcs.firePropertyChange("history", oldHistory, history); // Does this work? 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 * @param message
*/ */
public void addMessage(Message message) { public void addMessage(Message message) {
db.addMessage(message, new DatabaseController.MessageCallback() { db.addMessage(message, () -> {
@Override history.add(message);
public void onMessageSaved(Message savedMessage) { notifyMessageAdded(message);
history.add(savedMessage);
pcs.firePropertyChange("history", null, history);
}
}); });
} }
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; package fr.insa.clavardator.chat;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.User; import fr.insa.clavardator.users.User;
import java.io.Serializable; import java.io.Serializable;
public class Message implements Serializable { public class Message implements Serializable {
private String text;
private final User recipient; private final User recipient;
private final User sender; private final User sender;
private final String text;
public Message(User sender, User recipient) { public Message(User sender, User recipient) {
this(sender, recipient, ""); this(sender, recipient, "");

View file

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

View file

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

View file

@ -1,8 +1,10 @@
package fr.insa.clavardator.ui.chat; package fr.insa.clavardator.ui.chat;
import fr.insa.clavardator.chat.ChatHistory;
import fr.insa.clavardator.chat.Message; import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.ui.ButtonPressEvent; import fr.insa.clavardator.ui.ButtonPressEvent;
import fr.insa.clavardator.ui.NoSelectionModel; import fr.insa.clavardator.ui.NoSelectionModel;
import fr.insa.clavardator.users.ActiveUser;
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.collections.FXCollections; import javafx.collections.FXCollections;
@ -12,6 +14,7 @@ import javafx.fxml.Initializable;
import javafx.scene.control.ListView; import javafx.scene.control.ListView;
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 {
@ -40,25 +43,32 @@ public class ChatController implements Initializable {
public void setCurrentUser(CurrentUser currentUser) { public void setCurrentUser(CurrentUser currentUser) {
this.chatHeaderController.setCurrentUser(currentUser);
this.currentUser = currentUser; this.currentUser = currentUser;
} }
public void setRemoteUser(PeerUser remoteUser) { public void setRemoteUser(PeerUser remoteUser) {
this.remoteUser = 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() { private void onHistoryLoaded(ArrayList<Message> messages) {
ObservableList<Message> messages = FXCollections.observableArrayList( messageList.setItems(FXCollections.observableArrayList(messages));
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);
messageList.scrollTo(messageList.getItems().size() - 1); messageList.scrollTo(messageList.getItems().size() - 1);
} }
private void onMessageAdded(Message message) {
messageList.getItems().add(message);
messageList.scrollTo(messageList.getItems().size() - 1);
}
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
messageList.setItems(null); messageList.setItems(null);

View file

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

View file

@ -1,7 +1,12 @@
package fr.insa.clavardator.ui.chat; package fr.insa.clavardator.ui.chat;
import fr.insa.clavardator.ui.ButtonPressEvent; 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.fxml.Initializable;
import javafx.scene.control.Label;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
@ -10,8 +15,18 @@ import java.util.ResourceBundle;
public class ChatHeaderController implements Initializable { public class ChatHeaderController implements Initializable {
@FXML
private Label currentUsernameLabel;
@FXML
private Label remoteUsernameLabel;
@FXML
private UserActiveIndicatorController indicatorController;
private List<ButtonPressEvent> editListeners; private List<ButtonPressEvent> editListeners;
private CurrentUser currentUser;
private PeerUser remoteUser;
public void addEditListener(ButtonPressEvent listener) { public void addEditListener(ButtonPressEvent listener) {
editListeners.add(listener); editListeners.add(listener);
} }
@ -27,4 +42,16 @@ public class ChatHeaderController implements Initializable {
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
editListeners = new ArrayList<>(); 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<ButtonPressEvent> refreshUserListeners;
final private List<UserSelectedEvent> userSelectedListeners; final private List<UserSelectedEvent> userSelectedListeners;
@FXML @FXML
private ListView<User> userList; private ListView<PeerUser> userList;
public UserListController() { public UserListController() {
super(); super();
@ -43,7 +43,7 @@ public class UserListController implements Initializable {
refreshUserListeners.forEach(ButtonPressEvent::onPress); 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(); final User currentSelectedUser = userList.getSelectionModel().getSelectedItem();
if (!user.equals(currentSelectedUser)) { if (!user.equals(currentSelectedUser)) {
userList.getSelectionModel().select(user); userList.getSelectionModel().select(user);
@ -53,7 +53,7 @@ public class UserListController implements Initializable {
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
ObservableList<User> activeList = null; ObservableList<PeerUser> activeList = null;
try { try {
activeList = FXCollections.observableArrayList( activeList = FXCollections.observableArrayList(
new PeerUser("Dodo0"), new PeerUser("Dodo0"),

View file

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

View file

@ -8,7 +8,7 @@
<HBox xmlns="http://javafx.com/javafx" <HBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml" xmlns:fx="http://javafx.com/fxml"
fx:controller="fr.insa.clavardator.ui.chat.ChatFooterController" 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> <padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/> <Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding> </padding>

View file

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

View file

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