feat: connect user list to ui
This commit is contained in:
parent
733d755c60
commit
c5d56a2604
13 changed files with 118 additions and 247 deletions
|
|
@ -1,25 +1,19 @@
|
||||||
package fr.insa.clavardator;
|
package fr.insa.clavardator;
|
||||||
|
|
||||||
import fr.insa.clavardator.network.ConnectionListener;
|
|
||||||
import fr.insa.clavardator.network.NetDiscoverer;
|
|
||||||
import fr.insa.clavardator.ui.MainController;
|
import fr.insa.clavardator.ui.MainController;
|
||||||
import fr.insa.clavardator.users.PeerUser;
|
import fr.insa.clavardator.users.User;
|
||||||
|
import fr.insa.clavardator.users.UserList;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
|
|
||||||
// See here : https://github.com/jfoenixadmin/JFoenix/blob/master/demo/src/main/java/demos/components/DrawerDemo.java
|
// See here : https://github.com/jfoenixadmin/JFoenix/blob/master/demo/src/main/java/demos/components/DrawerDemo.java
|
||||||
|
|
||||||
public class MainApp extends Application {
|
public class MainApp extends Application {
|
||||||
|
|
||||||
NetDiscoverer netDiscoverer;
|
private UserList userList;
|
||||||
private ConnectionListener connectionListener;
|
|
||||||
private PeerUser user1;
|
|
||||||
private PeerUser user2;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch(args);
|
launch(args);
|
||||||
|
|
@ -29,8 +23,11 @@ public class MainApp extends Application {
|
||||||
public void start(Stage stage) throws Exception {
|
public void start(Stage stage) throws Exception {
|
||||||
|
|
||||||
final FXMLLoader mainLoader = new FXMLLoader(getClass().getResource("ui/scene.fxml"));
|
final FXMLLoader mainLoader = new FXMLLoader(getClass().getResource("ui/scene.fxml"));
|
||||||
final MainController main = mainLoader.getController();
|
|
||||||
final Parent content = mainLoader.load();
|
final Parent content = mainLoader.load();
|
||||||
|
MainController mainController = mainLoader.getController();
|
||||||
|
|
||||||
|
userList = new UserList();
|
||||||
|
mainController.setUserList(userList);
|
||||||
|
|
||||||
Scene scene = new Scene(content);
|
Scene scene = new Scene(content);
|
||||||
|
|
||||||
|
|
@ -40,41 +37,11 @@ public class MainApp extends Application {
|
||||||
stage.setMinWidth(800);
|
stage.setMinWidth(800);
|
||||||
stage.setMaximized(true);
|
stage.setMaximized(true);
|
||||||
stage.show();
|
stage.show();
|
||||||
|
|
||||||
netDiscoverer = new NetDiscoverer();
|
|
||||||
|
|
||||||
// Network discovery test
|
|
||||||
netDiscoverer.startDiscoveryListening("Bob", null, Throwable::printStackTrace);
|
|
||||||
netDiscoverer.discoverActiveUsers("Broadcast",
|
|
||||||
(ipAddr, data) -> System.out.println("User detected at address : " + ipAddr.toString() + " with name " + data),
|
|
||||||
Throwable::printStackTrace);
|
|
||||||
|
|
||||||
// TCP communication tests
|
|
||||||
connectionListener = new ConnectionListener();
|
|
||||||
connectionListener.acceptConnection(socket -> user1.connect(socket,
|
|
||||||
() -> System.out.println("Connexion établie avec " + user2.getUsername()),
|
|
||||||
Throwable::printStackTrace),
|
|
||||||
e -> {
|
|
||||||
if (e instanceof java.io.EOFException) {
|
|
||||||
System.out.println("Connexion terminée");
|
|
||||||
} else {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
user2 = new PeerUser(InetAddress.getLocalHost().hashCode(), "Yohan");
|
|
||||||
user2.connect(InetAddress.getByName("ADDRESSE_IP"),
|
|
||||||
() -> System.out.println("Connexion établie avec " + user2.getUsername()),
|
|
||||||
Throwable::printStackTrace);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws Exception {
|
public void stop() throws Exception {
|
||||||
netDiscoverer.stopDiscovery();
|
userList.destroy();
|
||||||
connectionListener.stopAccepting();
|
|
||||||
user1.disconnect();
|
|
||||||
user2.disconnect();
|
|
||||||
super.stop();
|
super.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,6 +7,8 @@ import fr.insa.clavardator.ui.dialogs.EditUsernameDialogController;
|
||||||
import fr.insa.clavardator.ui.dialogs.SnackbarController;
|
import fr.insa.clavardator.ui.dialogs.SnackbarController;
|
||||||
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.CurrentUser;
|
||||||
|
import fr.insa.clavardator.users.UserList;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
|
@ -31,28 +33,34 @@ public class MainController implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
private AboutDialogController aboutDialogController;
|
private AboutDialogController aboutDialogController;
|
||||||
@FXML
|
@FXML
|
||||||
private UserListController userListController;
|
private UserListController listController;
|
||||||
@FXML
|
@FXML
|
||||||
private ChatController chatController;
|
private ChatController chatController;
|
||||||
@FXML
|
@FXML
|
||||||
private LoadingScreenController loadingController;
|
private LoadingScreenController loadingController;
|
||||||
@FXML
|
@FXML
|
||||||
private ErrorScreenController errorController;
|
private ErrorScreenController errorController;
|
||||||
|
|
||||||
private JFXSnackbar snackbar;
|
private JFXSnackbar snackbar;
|
||||||
|
private UserList userList;
|
||||||
|
|
||||||
public MainController() {
|
public MainController() {
|
||||||
currentUser = CurrentUser.getInstance();
|
currentUser = CurrentUser.getInstance();
|
||||||
currentUser.addObserver(propertyChangeEvent -> {
|
currentUser.addObserver(propertyChangeEvent -> {
|
||||||
if (propertyChangeEvent.getPropertyName().equals("state")) {
|
if (propertyChangeEvent.getPropertyName().equals("state")) {
|
||||||
final CurrentUser.State state = (CurrentUser.State) propertyChangeEvent.getNewValue();
|
final CurrentUser.State newState = (CurrentUser.State) propertyChangeEvent.getNewValue();
|
||||||
if (state == CurrentUser.State.VALID)
|
onCurrentUserStateChange(newState);
|
||||||
showChat();
|
|
||||||
else
|
|
||||||
showLogin(state == CurrentUser.State.INVALID);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onCurrentUserStateChange(CurrentUser.State newState) {
|
||||||
|
if (newState == CurrentUser.State.VALID)
|
||||||
|
startChat();
|
||||||
|
else
|
||||||
|
Platform.runLater(() -> showLogin(newState == CurrentUser.State.INVALID));
|
||||||
|
}
|
||||||
|
|
||||||
private void openEditUsernameDialog(EditUsernameDialogController.Mode mode) {
|
private void openEditUsernameDialog(EditUsernameDialogController.Mode mode) {
|
||||||
editUserDialogController.setOnDismissListener(() -> {
|
editUserDialogController.setOnDismissListener(() -> {
|
||||||
if (mode == EditUsernameDialogController.Mode.INITIAL) {
|
if (mode == EditUsernameDialogController.Mode.INITIAL) {
|
||||||
|
|
@ -81,6 +89,17 @@ public class MainController implements Initializable {
|
||||||
aboutDialogController.show(root);
|
aboutDialogController.show(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void discoverActiveUsers() {
|
||||||
|
if (userList != null)
|
||||||
|
userList.discoverActiveUsers((e) -> CurrentUser.getInstance().setState(CurrentUser.State.INVALID));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startChat() {
|
||||||
|
discoverActiveUsers();
|
||||||
|
userList.startDiscoveryListening();
|
||||||
|
Platform.runLater(this::showChat);
|
||||||
|
}
|
||||||
|
|
||||||
private void showChat() {
|
private void showChat() {
|
||||||
loadingController.hide();
|
loadingController.hide();
|
||||||
mainContainer.setVisible(true);
|
mainContainer.setVisible(true);
|
||||||
|
|
@ -110,11 +129,16 @@ public class MainController implements Initializable {
|
||||||
showError();
|
showError();
|
||||||
}
|
}
|
||||||
|
|
||||||
userListController.addRefreshUserListener(() -> System.out.println("refresh event"));
|
listController.setUserSelectedListener((user) -> chatController.setRemoteUser(user));
|
||||||
userListController.addUserSelectedListener((user) -> chatController.setRemoteUser(user));
|
|
||||||
chatController.addAttachmentListener(() -> System.out.println("attach event"));
|
chatController.addAttachmentListener(() -> System.out.println("attach event"));
|
||||||
chatController.addSendListener((text) -> System.out.println("sent : " + text));
|
chatController.addSendListener((text) -> System.out.println("sent : " + text));
|
||||||
toolbarController.addEditListener(() -> openEditUsernameDialog(EditUsernameDialogController.Mode.EDIT));
|
toolbarController.addEditListener(() -> openEditUsernameDialog(EditUsernameDialogController.Mode.EDIT));
|
||||||
toolbarController.addAboutListener(this::openAboutDialog);
|
toolbarController.addAboutListener(this::openAboutDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUserList(UserList userList) {
|
||||||
|
this.userList = userList;
|
||||||
|
listController.setUserList(userList);
|
||||||
|
listController.setRefreshUserListener(this::discoverActiveUsers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import fr.insa.clavardator.chat.Message;
|
||||||
import fr.insa.clavardator.ui.ButtonPressEvent;
|
import fr.insa.clavardator.ui.ButtonPressEvent;
|
||||||
import fr.insa.clavardator.ui.LoadingScreenController;
|
import fr.insa.clavardator.ui.LoadingScreenController;
|
||||||
import fr.insa.clavardator.ui.NoSelectionModel;
|
import fr.insa.clavardator.ui.NoSelectionModel;
|
||||||
import fr.insa.clavardator.users.ActiveUser;
|
|
||||||
import fr.insa.clavardator.users.PeerUser;
|
import fr.insa.clavardator.users.PeerUser;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
|
@ -15,7 +14,6 @@ import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class ChatController implements Initializable {
|
public class ChatController implements Initializable {
|
||||||
|
|
@ -97,7 +95,7 @@ public class ChatController implements Initializable {
|
||||||
public void initialize(URL url, ResourceBundle rb) {
|
public void initialize(URL url, ResourceBundle rb) {
|
||||||
loadingController.getRootStyle().clear();
|
loadingController.getRootStyle().clear();
|
||||||
loadingController.getRootStyle().add("inner");
|
loadingController.getRootStyle().add("inner");
|
||||||
messageList.setSelectionModel(new NoSelectionModel<Message>());
|
messageList.setSelectionModel(new NoSelectionModel<>());
|
||||||
messageList.setCellFactory(listView -> new MessageListItemCell());
|
messageList.setCellFactory(listView -> new MessageListItemCell());
|
||||||
setState(State.INITIAL);
|
setState(State.INITIAL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package fr.insa.clavardator.ui.users;
|
package fr.insa.clavardator.ui.users;
|
||||||
|
|
||||||
import fr.insa.clavardator.users.ActiveUser;
|
import fr.insa.clavardator.users.PeerUser;
|
||||||
import fr.insa.clavardator.users.User;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
|
|
@ -19,9 +18,9 @@ public class UserActiveIndicatorController implements Initializable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUser(User user) {
|
public void setUser(PeerUser user) {
|
||||||
circle.getStyleClass().clear();
|
circle.getStyleClass().clear();
|
||||||
if (user instanceof ActiveUser) {
|
if (user.isActive()) {
|
||||||
circle.getStyleClass().add("active-user-dot");
|
circle.getStyleClass().add("active-user-dot");
|
||||||
} else {
|
} else {
|
||||||
circle.getStyleClass().add("inactive-user-dot");
|
circle.getStyleClass().add("inactive-user-dot");
|
||||||
|
|
|
||||||
|
|
@ -4,69 +4,65 @@ import fr.insa.clavardator.ui.ButtonPressEvent;
|
||||||
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 fr.insa.clavardator.users.User;
|
import fr.insa.clavardator.users.User;
|
||||||
import javafx.collections.FXCollections;
|
import fr.insa.clavardator.users.UserList;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.application.Platform;
|
||||||
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 java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class UserListController implements Initializable {
|
public class UserListController implements Initializable {
|
||||||
|
|
||||||
final private List<ButtonPressEvent> refreshUserListeners;
|
private ButtonPressEvent refreshUserListener;
|
||||||
final private List<UserSelectedEvent> userSelectedListeners;
|
private UserSelectedEvent userSelectedListener;
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<PeerUser> userList;
|
private ListView<PeerUser> peerUserListView;
|
||||||
|
private UserList userList;
|
||||||
|
|
||||||
public UserListController() {
|
public UserListController() {
|
||||||
super();
|
|
||||||
refreshUserListeners = new ArrayList<>();
|
|
||||||
userSelectedListeners = new ArrayList<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRefreshUserListener(ButtonPressEvent listener) {
|
public void setRefreshUserListener(ButtonPressEvent listener) {
|
||||||
refreshUserListeners.add(listener);
|
refreshUserListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addUserSelectedListener(UserSelectedEvent listener) {
|
public void setUserSelectedListener(UserSelectedEvent listener) {
|
||||||
userSelectedListeners.add(listener);
|
userSelectedListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRefreshUserListPress() {
|
public void onRefreshUserListPress() {
|
||||||
refreshUserListeners.forEach(ButtonPressEvent::onPress);
|
refreshUserListener.onPress();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUserSelected(@org.jetbrains.annotations.NotNull PeerUser user) {
|
private void onUserSelected(@org.jetbrains.annotations.NotNull PeerUser user) {
|
||||||
final User currentSelectedUser = userList.getSelectionModel().getSelectedItem();
|
final User currentSelectedUser = peerUserListView.getSelectionModel().getSelectedItem();
|
||||||
if (!user.equals(currentSelectedUser)) {
|
if (!user.equals(currentSelectedUser)) {
|
||||||
userList.getSelectionModel().select(user);
|
peerUserListView.getSelectionModel().select(user);
|
||||||
userSelectedListeners.forEach(l -> l.onSelected(user));
|
userSelectedListener.onSelected(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle rb) {
|
public void initialize(URL url, ResourceBundle rb) {
|
||||||
ObservableList<PeerUser> activeList = FXCollections.observableArrayList(
|
peerUserListView.setCellFactory(listView -> {
|
||||||
new PeerUser(0, "Dodo0"),
|
|
||||||
new PeerUser(1, "Dodo3"),
|
|
||||||
new PeerUser(2, "Dodo2"),
|
|
||||||
new PeerUser(3, "Coucou0"),
|
|
||||||
new PeerUser(4, "Coucou1"),
|
|
||||||
new PeerUser(5, "Coucou3"),
|
|
||||||
new PeerUser(6, "Dodo1"),
|
|
||||||
new PeerUser(7, "Coucou2")
|
|
||||||
);
|
|
||||||
|
|
||||||
activeList.sort(null);
|
|
||||||
userList.setItems(activeList);
|
|
||||||
userList.setCellFactory(listView -> {
|
|
||||||
final UserListItemCell cell = new UserListItemCell();
|
final UserListItemCell cell = new UserListItemCell();
|
||||||
cell.setOnUserSelectedListener(this::onUserSelected);
|
cell.setOnUserSelectedListener(this::onUserSelected);
|
||||||
return cell;
|
return cell;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onUserConnected(PeerUser user) {
|
||||||
|
Platform.runLater(() -> peerUserListView.getItems().add(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onUserDisconnected(PeerUser user) {
|
||||||
|
Platform.runLater(() -> peerUserListView.getItems().remove(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserList(UserList userList) {
|
||||||
|
this.userList = userList;
|
||||||
|
userList.addActiveUsersObserver(this::onUserConnected, this::onUserDisconnected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,8 +2,7 @@ package fr.insa.clavardator.ui.users;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import fr.insa.clavardator.ui.ButtonPressEvent;
|
import fr.insa.clavardator.ui.ButtonPressEvent;
|
||||||
import fr.insa.clavardator.users.ActiveUser;
|
import fr.insa.clavardator.users.PeerUser;
|
||||||
import fr.insa.clavardator.users.User;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
|
||||||
|
|
@ -19,7 +18,7 @@ public class UserListItemController implements Initializable {
|
||||||
|
|
||||||
private ButtonPressEvent listener;
|
private ButtonPressEvent listener;
|
||||||
|
|
||||||
private User user;
|
private PeerUser user;
|
||||||
|
|
||||||
public void setOnPressListener(ButtonPressEvent listener) {
|
public void setOnPressListener(ButtonPressEvent listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
|
@ -43,7 +42,7 @@ public class UserListItemController implements Initializable {
|
||||||
resetBackground();
|
resetBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUser(User user) {
|
public void setUser(PeerUser user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
indicatorController.setUser(user);
|
indicatorController.setUser(user);
|
||||||
button.setText(user.getUsername());
|
button.setText(user.getUsername());
|
||||||
|
|
@ -51,7 +50,7 @@ public class UserListItemController implements Initializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetBackground() {
|
private void resetBackground() {
|
||||||
if (user != null && user instanceof ActiveUser) {
|
if (user != null && user.isActive()) {
|
||||||
button.getStyleClass().remove("inactive-user-item");
|
button.getStyleClass().remove("inactive-user-item");
|
||||||
button.getStyleClass().add("active-user-item");
|
button.getStyleClass().add("active-user-item");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
package fr.insa.clavardator.users;
|
|
||||||
|
|
||||||
import fr.insa.clavardator.chat.Message;
|
|
||||||
import fr.insa.clavardator.network.PeerConnection;
|
|
||||||
import fr.insa.clavardator.util.ErrorCallback;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public class ActiveUser extends PeerUser {
|
|
||||||
|
|
||||||
private final transient PeerConnection connection;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously creates a new ActiveUser by receiving information (id, username)
|
|
||||||
*
|
|
||||||
* @param ipAddr The IP address of the new user
|
|
||||||
* @param callback The function to call on success, with the new ActiveUser as parameter
|
|
||||||
* @param errorCallback The function to call on socket error
|
|
||||||
*/
|
|
||||||
public static void create(InetAddress ipAddr, UserConnectedCallback callback, ErrorCallback errorCallback) {
|
|
||||||
// Connect to the peer
|
|
||||||
new PeerConnection(ipAddr, (thisConnection) -> {
|
|
||||||
|
|
||||||
// Send our username
|
|
||||||
String currentUserUsername = CurrentUser.getInstance().getUsername();
|
|
||||||
int currentUserId = CurrentUser.getInstance().getId();
|
|
||||||
thisConnection.send(new UserInformation(currentUserId, currentUserUsername), null, errorCallback);
|
|
||||||
|
|
||||||
// Receive peer's username
|
|
||||||
thisConnection.receiveOne(msg -> {
|
|
||||||
assert msg instanceof UserInformation;
|
|
||||||
UserInformation userInfo = (UserInformation) msg;
|
|
||||||
ActiveUser user = new ActiveUser(userInfo.getId(), userInfo.getUsername(), thisConnection, errorCallback);
|
|
||||||
callback.onUserConnected();
|
|
||||||
|
|
||||||
}, errorCallback);
|
|
||||||
}, errorCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously creates a new ActiveUser by receiving information (id, username)
|
|
||||||
*
|
|
||||||
* @param socket A socket already connected to the user
|
|
||||||
* @param callback The function to call on success, with the new ActiveUser as parameter
|
|
||||||
* @param errorCallback The function to call on socket error
|
|
||||||
*/
|
|
||||||
public static void create(Socket socket, UserConnectedCallback callback, ErrorCallback errorCallback) {
|
|
||||||
PeerConnection connection = new PeerConnection(socket);
|
|
||||||
|
|
||||||
// Send our username
|
|
||||||
String currentUserUsername = CurrentUser.getInstance().getUsername();
|
|
||||||
int currentUserId = CurrentUser.getInstance().getId();
|
|
||||||
connection.send(new UserInformation(currentUserId, currentUserUsername), null, errorCallback);
|
|
||||||
|
|
||||||
// Receive peer's username
|
|
||||||
connection.receiveOne(msg -> {
|
|
||||||
assert msg instanceof UserInformation;
|
|
||||||
UserInformation userInfo = (UserInformation) msg;
|
|
||||||
ActiveUser user = new ActiveUser(userInfo.getId(), userInfo.getUsername(), connection, errorCallback);
|
|
||||||
callback.onUserConnected();
|
|
||||||
}, errorCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a message to this peer
|
|
||||||
*
|
|
||||||
* @param message The message to send
|
|
||||||
* @param callback The function to call when the message is sent
|
|
||||||
* @param errorCallback The function to call on error
|
|
||||||
*/
|
|
||||||
public void sendMessage(Message message, PeerConnection.MessageSentCallback callback, ErrorCallback errorCallback) {
|
|
||||||
connection.send(message, callback, errorCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the connection with the user.
|
|
||||||
* Must be called before exiting the app.
|
|
||||||
*/
|
|
||||||
public void destroy() {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private ActiveUser(int id, String username, PeerConnection connection, ErrorCallback errorCallback) {
|
|
||||||
super(id, username);
|
|
||||||
this.connection = connection;
|
|
||||||
subscribeToMessages(errorCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void subscribeToMessages(ErrorCallback errorCallback) {
|
|
||||||
connection.receive(
|
|
||||||
msg -> {
|
|
||||||
if (msg.getClass().isInstance(UserInformation.class)) {
|
|
||||||
assert ((UserInformation) msg).getId() == getId();
|
|
||||||
setUsername(((UserInformation) msg).getUsername());
|
|
||||||
|
|
||||||
} else if (msg.getClass().isInstance(Message.class)) {
|
|
||||||
assert ((Message) msg).getRecipient() != this;
|
|
||||||
history.addMessage((Message) msg);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
e -> {
|
|
||||||
if (e.getClass().isInstance(EOFException.class)) {
|
|
||||||
// TODO: notify disconnection
|
|
||||||
} else {
|
|
||||||
errorCallback.onError(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -35,7 +35,7 @@ public class CurrentUser extends User {
|
||||||
} else {
|
} else {
|
||||||
throw new SocketException();
|
throw new SocketException();
|
||||||
}
|
}
|
||||||
// TODO replace by db and network calls
|
// TODO place by db username fetching
|
||||||
Timer t = new Timer();
|
Timer t = new Timer();
|
||||||
t.schedule(new TimerTask() {
|
t.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -43,7 +43,7 @@ public class CurrentUser extends User {
|
||||||
Platform.runLater(() -> setState(CurrentUser.State.VALID));
|
Platform.runLater(() -> setState(CurrentUser.State.VALID));
|
||||||
t.cancel();
|
t.cancel();
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 500);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,13 @@ import fr.insa.clavardator.chat.ChatHistory;
|
||||||
import fr.insa.clavardator.chat.Message;
|
import fr.insa.clavardator.chat.Message;
|
||||||
import fr.insa.clavardator.network.PeerConnection;
|
import fr.insa.clavardator.network.PeerConnection;
|
||||||
import fr.insa.clavardator.util.ErrorCallback;
|
import fr.insa.clavardator.util.ErrorCallback;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
public class PeerUser extends User {
|
public class PeerUser extends User implements Comparable<PeerUser> {
|
||||||
private State state = State.DISCONNECTED;
|
private State state = State.DISCONNECTED;
|
||||||
private transient PeerConnection connection;
|
private transient PeerConnection connection;
|
||||||
|
|
||||||
|
|
@ -29,8 +30,7 @@ public class PeerUser extends User {
|
||||||
*/
|
*/
|
||||||
public void connect(InetAddress ipAddr, UserConnectedCallback callback, ErrorCallback errorCallback) {
|
public void connect(InetAddress ipAddr, UserConnectedCallback callback, ErrorCallback errorCallback) {
|
||||||
// Connect to the peer
|
// Connect to the peer
|
||||||
pcs.firePropertyChange("state", state, State.CONNECTING);
|
setState(State.CONNECTING);
|
||||||
state = State.CONNECTING;
|
|
||||||
connection = new PeerConnection(ipAddr, (thisConnection) -> {
|
connection = new PeerConnection(ipAddr, (thisConnection) -> {
|
||||||
init(thisConnection, callback, errorCallback);
|
init(thisConnection, callback, errorCallback);
|
||||||
}, e -> {
|
}, e -> {
|
||||||
|
|
@ -47,8 +47,7 @@ public class PeerUser extends User {
|
||||||
* @param errorCallback The function to call on socket error
|
* @param errorCallback The function to call on socket error
|
||||||
*/
|
*/
|
||||||
public void connect(Socket socket, UserConnectedCallback callback, ErrorCallback errorCallback) {
|
public void connect(Socket socket, UserConnectedCallback callback, ErrorCallback errorCallback) {
|
||||||
pcs.firePropertyChange("state", state, State.CONNECTING);
|
setState(State.CONNECTING);
|
||||||
state = State.CONNECTING;
|
|
||||||
connection = new PeerConnection(socket);
|
connection = new PeerConnection(socket);
|
||||||
|
|
||||||
init(connection, callback, errorCallback);
|
init(connection, callback, errorCallback);
|
||||||
|
|
@ -78,10 +77,7 @@ public class PeerUser extends User {
|
||||||
disconnect();
|
disconnect();
|
||||||
errorCallback.onError(e);
|
errorCallback.onError(e);
|
||||||
});
|
});
|
||||||
|
setState(State.CONNECTED);
|
||||||
// Update state to CONNECTED
|
|
||||||
pcs.firePropertyChange("state", state, State.CONNECTED);
|
|
||||||
state = State.CONNECTED;
|
|
||||||
|
|
||||||
}, e -> {
|
}, e -> {
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
@ -117,8 +113,7 @@ public class PeerUser extends User {
|
||||||
connection.close();
|
connection.close();
|
||||||
connection = null;
|
connection = null;
|
||||||
}
|
}
|
||||||
pcs.firePropertyChange("state", state, State.DISCONNECTED);
|
setState(State.DISCONNECTED);
|
||||||
state = State.DISCONNECTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -131,12 +126,34 @@ public class PeerUser extends User {
|
||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setState(State state) {
|
||||||
|
pcs.firePropertyChange("state", this.state, state);
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return state == State.CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
CONNECTING,
|
CONNECTING,
|
||||||
CONNECTED,
|
CONNECTED,
|
||||||
DISCONNECTED,
|
DISCONNECTED,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull PeerUser peerUser) {
|
||||||
|
if (peerUser.isActive() && !this.isActive()) {
|
||||||
|
return 1;
|
||||||
|
} else if (!peerUser.isActive() && this.isActive()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return getUsername().compareTo(peerUser.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
public interface UserConnectedCallback {
|
public interface UserConnectedCallback {
|
||||||
void onUserConnected();
|
void onUserConnected();
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyChangeSupport;
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class User implements Serializable, Comparable<User> {
|
public class User implements Serializable {
|
||||||
private String username;
|
private String username;
|
||||||
public int id;
|
public int id;
|
||||||
|
|
||||||
|
|
@ -44,15 +44,4 @@ public class User implements Serializable, Comparable<User> {
|
||||||
pcs.firePropertyChange("username", this.username, newUsername);
|
pcs.firePropertyChange("username", this.username, newUsername);
|
||||||
this.username = newUsername;
|
this.username = newUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(@NotNull User o) {
|
|
||||||
if ((o instanceof ActiveUser) && !(this instanceof ActiveUser)) {
|
|
||||||
return 1;
|
|
||||||
} else if (!(o instanceof ActiveUser) && (this instanceof ActiveUser)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return username.compareTo(o.username);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,14 @@ import fr.insa.clavardator.util.ErrorCallback;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class UserList {
|
public class UserList {
|
||||||
|
|
||||||
private Map<Integer, PeerUser> inactiveUsers;
|
private final Map<Integer, PeerUser> inactiveUsers = new HashMap<>();
|
||||||
private Map<Integer, PeerUser> activeUsers;
|
private final Map<Integer, PeerUser> activeUsers = new HashMap<>();
|
||||||
|
|
||||||
private final ArrayList<UserConnectionCallback> userConnectionObservers = new ArrayList<>();
|
private final ArrayList<UserConnectionCallback> userConnectionObservers = new ArrayList<>();
|
||||||
private final ArrayList<UserDisconnectionCallback> userDisconnectionObservers = new ArrayList<>();
|
private final ArrayList<UserDisconnectionCallback> userDisconnectionObservers = new ArrayList<>();
|
||||||
|
|
@ -33,13 +34,10 @@ public class UserList {
|
||||||
netDiscoverer.discoverActiveUsers("CLAVARDATOR_BROADCAST", (ipAddr, data) -> {
|
netDiscoverer.discoverActiveUsers("CLAVARDATOR_BROADCAST", (ipAddr, data) -> {
|
||||||
int id = getIdFromIp(ipAddr);
|
int id = getIdFromIp(ipAddr);
|
||||||
PeerUser user = inactiveUsers.get(id);
|
PeerUser user = inactiveUsers.get(id);
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
user = new PeerUser(id, "");
|
user = new PeerUser(id, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerUser finalUser = user;
|
PeerUser finalUser = user;
|
||||||
|
|
||||||
user.connect(ipAddr, () -> {
|
user.connect(ipAddr, () -> {
|
||||||
notifyConnectionObservers(finalUser);
|
notifyConnectionObservers(finalUser);
|
||||||
}, errorCallback);
|
}, errorCallback);
|
||||||
|
|
@ -47,12 +45,12 @@ public class UserList {
|
||||||
}, errorCallback);
|
}, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getIdFromIp(InetAddress ipAddr) {
|
public void startDiscoveryListening() {
|
||||||
return ipAddr.hashCode();
|
netDiscoverer.startDiscoveryListening("", null, Throwable::printStackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addActiveUser(ActiveUser user) {
|
private int getIdFromIp(InetAddress ipAddr) {
|
||||||
|
return ipAddr.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addActiveUsersObserver(UserConnectionCallback connectionCallback, UserDisconnectionCallback disconnectionCallback) {
|
public void addActiveUsersObserver(UserConnectionCallback connectionCallback, UserDisconnectionCallback disconnectionCallback) {
|
||||||
|
|
@ -109,11 +107,11 @@ public class UserList {
|
||||||
return inactiveUsers;
|
return inactiveUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserConnectionCallback {
|
public interface UserConnectionCallback {
|
||||||
void onUserConnected(PeerUser user);
|
void onUserConnected(PeerUser user);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserDisconnectionCallback {
|
public interface UserDisconnectionCallback {
|
||||||
void onUserDisconnected(PeerUser user);
|
void onUserDisconnected(PeerUser user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
<VBox>
|
<VBox>
|
||||||
<fx:include source="toolbar.fxml" fx:id="toolbar"/>
|
<fx:include source="toolbar.fxml" fx:id="toolbar"/>
|
||||||
<HBox VBox.vgrow="ALWAYS">
|
<HBox VBox.vgrow="ALWAYS">
|
||||||
<fx:include source="users/userList.fxml" fx:id="userList"/>
|
<fx:include source="users/userList.fxml" fx:id="list"/>
|
||||||
<fx:include source="chat/chat.fxml" fx:id="chat" HBox.hgrow="ALWAYS"/>
|
<fx:include source="chat/chat.fxml" fx:id="chat" HBox.hgrow="ALWAYS"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,6 @@
|
||||||
</graphic>
|
</graphic>
|
||||||
</JFXButton>
|
</JFXButton>
|
||||||
</HBox>
|
</HBox>
|
||||||
<ListView fx:id="userList" VBox.vgrow="ALWAYS"/>
|
<ListView fx:id="peerUserListView" VBox.vgrow="ALWAYS"/>
|
||||||
</VBox>
|
</VBox>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue