Compare commits

...

3 commits

Author SHA1 Message Date
Arnaud Vergnet
e02ea55179 feat: add initial loading screen 2020-12-06 16:05:58 +01:00
Arnaud Vergnet
4ba39b3cc3 feat: show loading indicator on chat change 2020-12-06 15:34:25 +01:00
Arnaud Vergnet
93924d1bbd feat: move toolbar outside of chat 2020-12-06 14:51:25 +01:00
13 changed files with 327 additions and 107 deletions

View file

@ -3,8 +3,11 @@ package fr.insa.clavardator.chat;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.PeerUser;
import javafx.application.Platform;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
public class ChatHistory {
private final DatabaseController db;
@ -51,7 +54,13 @@ public class ChatHistory {
// notifyHistoryLoaded();
// });
}
notifyHistoryLoaded();
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
Platform.runLater(() -> notifyHistoryLoaded());
}
}, 1000);
}

View file

@ -2,28 +2,40 @@ package fr.insa.clavardator.ui;
import com.jfoenix.controls.JFXSnackbar;
import fr.insa.clavardator.ui.chat.ChatController;
import fr.insa.clavardator.ui.dialogs.AboutDialogController;
import fr.insa.clavardator.ui.dialogs.EditUsernameDialogController;
import fr.insa.clavardator.ui.dialogs.SnackbarController;
import fr.insa.clavardator.ui.users.UserListController;
import fr.insa.clavardator.users.CurrentUser;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
public class MainController implements Initializable {
@FXML
private StackPane root;
@FXML
private VBox loadingContainer;
@FXML
private VBox loginContainer;
@FXML
private ToolbarController toolbarController;
@FXML
private EditUsernameDialogController editUserDialogController;
@FXML
private AboutDialogController aboutDialogController;
@FXML
private UserListController userListController;
@FXML
private ChatController chatController;
@ -31,7 +43,6 @@ public class MainController implements Initializable {
private JFXSnackbar snackbar;
private void openEditUsernameDialog() throws IOException {
editUserDialogController.setMode(EditUsernameDialogController.Mode.EDIT);
editUserDialogController.setOnSuccessListener(() -> {
System.out.println("success");
try {
@ -46,32 +57,51 @@ public class MainController implements Initializable {
e.printStackTrace();
}
});
editUserDialogController.show(root);
editUserDialogController.show(root, EditUsernameDialogController.Mode.EDIT);
}
private void showChat() {
loadingContainer.setVisible(false);
loginContainer.setVisible(false);
}
private void showLogin() {
loadingContainer.setVisible(false);
loginContainer.setVisible(true);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
snackbar = new JFXSnackbar(root);
chatController.setCurrentUser(CurrentUser.getInstance());
userListController.addRefreshUserListener(() -> {
System.out.println("refresh event");
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
Platform.runLater(() -> CurrentUser.getInstance().setState(CurrentUser.State.VALID));
}
}, 2000);
CurrentUser.getInstance().addObserver(propertyChangeEvent -> {
if (propertyChangeEvent.getPropertyName().equals("state")) {
if (propertyChangeEvent.getNewValue().equals(CurrentUser.State.VALID))
showChat();
else
showLogin();
}
});
userListController.addUserSelectedListener((user) -> {
System.out.println(user.getUsername());
chatController.setRemoteUser(user);
});
chatController.addAttachmentListener(() -> {
System.out.println("attach event");
});
chatController.addSendListener(() -> {
System.out.println("send event");
});
chatController.addEditListener(() -> {
userListController.addRefreshUserListener(() -> System.out.println("refresh event"));
userListController.addUserSelectedListener((user) -> chatController.setRemoteUser(user));
chatController.addAttachmentListener(() -> System.out.println("attach event"));
chatController.addSendListener(() -> System.out.println("send event"));
toolbarController.addEditListener(() -> {
try {
openEditUsernameDialog();
} catch (IOException e) {
e.printStackTrace();
}
});
toolbarController.addAboutListener(() -> aboutDialogController.show(root));
}
}

View file

@ -0,0 +1,42 @@
package fr.insa.clavardator.ui;
import fr.insa.clavardator.users.CurrentUser;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
public class ToolbarController implements Initializable {
@FXML
private Label currentUsernameLabel;
private List<ButtonPressEvent> editListeners;
private List<ButtonPressEvent> aboutListeners;
public void addEditListener(ButtonPressEvent listener) {
editListeners.add(listener);
}
public void addAboutListener(ButtonPressEvent listener) {
aboutListeners.add(listener);
}
public void onEditPress() {
editListeners.forEach(ButtonPressEvent::onPress);
}
public void onAboutPress() {
aboutListeners.forEach(ButtonPressEvent::onPress);
}
@Override
public void initialize(URL location, ResourceBundle resources) {
currentUsernameLabel.setText(CurrentUser.getInstance().getUsername());
editListeners = new ArrayList<>();
aboutListeners = new ArrayList<>();
}
}

View file

@ -5,16 +5,16 @@ 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;
import javafx.collections.ObservableList;
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.Arrays;
import java.util.ResourceBundle;
public class ChatController implements Initializable {
@ -26,8 +26,12 @@ public class ChatController implements Initializable {
@FXML
private ChatHeaderController chatHeaderController;
private CurrentUser currentUser;
private PeerUser remoteUser;
@FXML
private VBox chatContainer;
@FXML
private VBox emptyContainer;
@FXML
private VBox loadingContainer;
public void addAttachmentListener(ButtonPressEvent listener) {
chatFooterController.addAttachmentListener(listener);
@ -37,20 +41,9 @@ public class ChatController implements Initializable {
chatFooterController.addSendListener(listener);
}
public void addEditListener(ButtonPressEvent listener) {
chatHeaderController.addEditListener(listener);
}
public void setCurrentUser(CurrentUser currentUser) {
this.chatHeaderController.setCurrentUser(currentUser);
this.currentUser = currentUser;
}
public void setRemoteUser(PeerUser remoteUser) {
this.remoteUser = remoteUser;
this.chatHeaderController.setRemoteUser(remoteUser);
this.chatFooterController.setEnabled(remoteUser instanceof ActiveUser);
setState(State.LOADING);
final ChatHistory history = remoteUser.getHistory();
history.addHistoryLoadedListener(this::onHistoryLoaded);
@ -61,6 +54,7 @@ public class ChatController implements Initializable {
private void onHistoryLoaded(ArrayList<Message> messages) {
messageList.setItems(FXCollections.observableArrayList(messages));
messageList.scrollTo(messageList.getItems().size() - 1);
setState(State.DONE);
}
private void onMessageAdded(Message message) {
@ -68,12 +62,41 @@ public class ChatController implements Initializable {
messageList.scrollTo(messageList.getItems().size() - 1);
}
private void setState(State state) {
switch (state) {
case INITIAL:
emptyContainer.setVisible(true);
chatFooterController.setEnabled(false);
chatContainer.setVisible(false);
loadingContainer.setVisible(false);
messageList.setItems(null);
break;
case LOADING:
chatContainer.setVisible(true);
loadingContainer.setVisible(true);
chatFooterController.setEnabled(false);
emptyContainer.setVisible(false);
break;
case DONE:
chatFooterController.setEnabled(true);
chatContainer.setVisible(true);
emptyContainer.setVisible(false);
loadingContainer.setVisible(false);
break;
}
}
@Override
public void initialize(URL url, ResourceBundle rb) {
messageList.setItems(null);
messageList.setSelectionModel(new NoSelectionModel<Message>());
messageList.setCellFactory(listView -> new MessageListItemCell());
setState(State.INITIAL);
}
private enum State {
INITIAL,
LOADING,
DONE
}
}

View file

@ -1,8 +1,6 @@
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;
@ -10,46 +8,20 @@ import javafx.scene.control.Label;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
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);
}
public void onEditPress() {
editListeners.forEach(ButtonPressEvent::onPress);
}
public void onAboutPress() {
}
@Override
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

@ -0,0 +1,40 @@
package fr.insa.clavardator.ui.dialogs;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.base.ValidatorBase;
import fr.insa.clavardator.ui.ButtonPressEvent;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
public class AboutDialogController implements Initializable {
@FXML
private JFXDialog dialog;
public void show(StackPane root) {
dialog.show(root);
}
public void hide() {
dialog.close();
}
public void onDismiss() {
hide();
}
@Override
public void initialize(URL location, ResourceBundle resources) {
}
}

View file

@ -47,10 +47,10 @@ public class EditUsernameDialogController implements Initializable {
this.successListener = listener;
}
public void show(StackPane root) {
public void show(StackPane root, Mode mode) {
setLocked(false);
setFieldError(State.VALID);
textField.setText("");
setMode(mode);
dialog.show(root);
}

View file

@ -1,10 +1,15 @@
package fr.insa.clavardator.users;
import org.jetbrains.annotations.Nullable;
public class CurrentUser extends User {
private static CurrentUser instance = null;
private State state;
private CurrentUser(int uniqueId, String username) {
super(uniqueId, username);
state = State.UNINITIALIZED;
}
/**
@ -27,4 +32,20 @@ public class CurrentUser extends User {
public static CurrentUser getInstance() {
return instance;
}
public State getState() {
return state;
}
public void setState(State state) {
instance.pcs.firePropertyChange("state", this.state, state);
this.state = state;
}
public enum State {
UNINITIALIZED,
VALID,
INVALID
}
}

View file

@ -3,13 +3,26 @@
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.*?>
<!--suppress JavaFxUnresolvedFxIdReference -->
<?import javafx.scene.control.Label?>
<?import com.jfoenix.controls.JFXSpinner?>
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.insa.clavardator.ui.chat.ChatController"
stylesheets="@../styles.css" styleClass="container">
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<fx:include source="chatHeader.fxml" fx:id="chatHeader"/>
<ListView fx:id="messageList" VBox.vgrow="ALWAYS"/>
<fx:include source="chatFooter.fxml" fx:id="chatFooter"/>
</VBox>
<StackPane AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<VBox fx:id="chatContainer">
<fx:include source="chatHeader.fxml" fx:id="chatHeader"/>
<StackPane VBox.vgrow="ALWAYS">
<ListView fx:id="messageList"/>
<VBox alignment="CENTER" fx:id="loadingContainer" styleClass="inner">
<JFXSpinner />
</VBox>
</StackPane>
<fx:include source="chatFooter.fxml" fx:id="chatFooter"/>
</VBox>
<VBox alignment="CENTER" fx:id="emptyContainer" styleClass="container">
<Label>Cliquez sur utilisateur pour ouvrir la discussion</Label>
</VBox>
</StackPane>
</AnchorPane>

View file

@ -1,38 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.Circle?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="fr.insa.clavardator.ui.chat.ChatHeaderController"
stylesheets="@../styles.css" styleClass="container">
<HBox alignment="CENTER_LEFT" prefHeight="64.0" spacing="10">
<padding>
<Insets left="20" right="20"/>
</padding>
<Label text="Connecté en tant que : "/>
<Label text="&lt;USERNAME&gt;" fx:id="currentUsernameLabel"/>
<JFXButton mnemonicParsing="false" onMouseClicked="#onEditPress">
<graphic>
<FontIcon iconLiteral="fas-user-edit" iconSize="24"/>
</graphic>
</JFXButton>
<Pane HBox.hgrow="ALWAYS"/>
<JFXButton mnemonicParsing="false" onMouseClicked="#onAboutPress">
<graphic>
<FontIcon iconLiteral="fas-info" iconSize="24"/>
</graphic>
</JFXButton>
</HBox>
<HBox alignment="CENTER_LEFT" spacing="5" prefHeight="45">
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="fr.insa.clavardator.ui.chat.ChatHeaderController"
stylesheets="@../styles.css" styleClass="container">
<HBox alignment="CENTER_LEFT" spacing="5" prefHeight="64">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</padding>
<fx:include source="../users/userActiveIndicator.fxml" fx:id="indicator" />
<fx:include source="../users/userActiveIndicator.fxml" fx:id="indicator"/>
<Label text="USER NAME" styleClass="current-user" fx:id="remoteUsernameLabel"/>
</HBox>
</VBox>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialog?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
<JFXDialog xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="fr.insa.clavardator.ui.dialogs.AboutDialogController"
stylesheets="@../styles.css" fx:id="dialog">
<AnchorPane
prefWidth="600"
prefHeight="400" styleClass="container">
<VBox AnchorPane.topAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.bottomAnchor="0">
<padding>
<Insets left="10" right="10" bottom="10" top="10"/>
</padding>
<VBox VBox.vgrow="ALWAYS" spacing="10">
<padding>
<Insets bottom="10"/>
</padding>
<Label styleClass="dialog-title" >À Propos</Label>
<VBox VBox.vgrow="ALWAYS" alignment="CENTER" spacing="30">
<Label VBox.vgrow="ALWAYS">Application réalisée par Yohan SIMARD et Arnaud VERGNET</Label>
<Label VBox.vgrow="ALWAYS">INSA Toulouse 2020-2021</Label>
<Label VBox.vgrow="ALWAYS">4IR Projet POO/COO</Label>
</VBox>
</VBox>
<HBox spacing="50" alignment="CENTER">
<JFXButton text="OK" styleClass="background-success" onAction="#onDismiss">
<graphic>
<FontIcon iconLiteral="fas-check"/>
</graphic>
</JFXButton>
</HBox>
</VBox>
</AnchorPane>
</JFXDialog>

View file

@ -1,13 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress JavaFxUnresolvedFxIdReference -->
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import com.jfoenix.controls.JFXSpinner?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<StackPane xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/11.0.1" fx:controller="fr.insa.clavardator.ui.MainController" fx:id="root">
<fx:include source="dialogs/editUsernameDialog.fxml" fx:id="editUserDialog"/>
<HBox>
<fx:include source="users/userList.fxml" fx:id="userList"/>
<fx:include source="chat/chat.fxml" fx:id="chat" HBox.hgrow="ALWAYS"/>
</HBox>
xmlns="http://javafx.com/javafx/11.0.1"
fx:controller="fr.insa.clavardator.ui.MainController"
stylesheets="@styles.css"
styleClass="container"
fx:id="root">
<StackPane fx:id="mainContainer">
<fx:include source="dialogs/editUsernameDialog.fxml" fx:id="editUserDialog"/>
<fx:include source="dialogs/aboutDialog.fxml" fx:id="aboutDialog"/>
<VBox>
<fx:include source="toolbar.fxml" fx:id="toolbar"/>
<HBox VBox.vgrow="ALWAYS">
<fx:include source="users/userList.fxml" fx:id="userList"/>
<fx:include source="chat/chat.fxml" fx:id="chat" HBox.hgrow="ALWAYS"/>
</HBox>
</VBox>
</StackPane>
<VBox alignment="CENTER" fx:id="loginContainer" styleClass="container" spacing="30">
<Label>ERROR</Label>
</VBox>
<VBox alignment="CENTER" fx:id="loadingContainer" styleClass="container" spacing="30">
<Label>Initialisation de Clavardator...</Label>
<JFXSpinner/>
</VBox>
</StackPane>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="fr.insa.clavardator.ui.ToolbarController"
stylesheets="@styles.css" styleClass="container">
<HBox alignment="CENTER_LEFT" prefHeight="64.0" spacing="10">
<padding>
<Insets left="20" right="20"/>
</padding>
<Label text="Connecté en tant que : "/>
<Label text="&lt;USERNAME&gt;" fx:id="currentUsernameLabel"/>
<JFXButton mnemonicParsing="false" onMouseClicked="#onEditPress">
<graphic>
<FontIcon iconLiteral="fas-user-edit" iconSize="24"/>
</graphic>
</JFXButton>
<Pane HBox.hgrow="ALWAYS"/>
<JFXButton mnemonicParsing="false" onMouseClicked="#onAboutPress">
<graphic>
<FontIcon iconLiteral="fas-info" iconSize="24"/>
</graphic>
</JFXButton>
</HBox>
</VBox>