feat: show snackbar on username change

This commit is contained in:
Arnaud Vergnet 2020-12-05 17:49:14 +01:00
parent 2fe0289f9f
commit fb3460f4b8
7 changed files with 480 additions and 67 deletions

View file

@ -1,24 +1,58 @@
package fr.insa.clavardator.ui; package fr.insa.clavardator.ui;
import com.jfoenix.controls.JFXSnackbar;
import fr.insa.clavardator.ui.chat.ChatController; import fr.insa.clavardator.ui.chat.ChatController;
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.ui.users.UserListController;
import fr.insa.clavardator.users.CurrentUser; import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.UserList; import fr.insa.clavardator.users.UserList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class MainController implements Initializable { public class MainController implements Initializable {
@FXML
private StackPane root;
@FXML
private EditUsernameDialogController editUserDialogController;
@FXML @FXML
private UserListController userListController; private UserListController userListController;
@FXML @FXML
private ChatController chatController; private ChatController chatController;
private JFXSnackbar snackbar;
private void openEditUsernameDialog() throws IOException {
editUserDialogController.setMode(EditUsernameDialogController.Mode.EDIT);
editUserDialogController.setOnSuccessListener(() -> {
System.out.println("success");
try {
final FXMLLoader loader = new FXMLLoader(getClass().getResource("dialogs/snackbar.fxml"));
snackbar.enqueue(new JFXSnackbar.SnackbarEvent(
loader.load()
));
final SnackbarController controller = loader.getController();
controller.setText("Nom d'utilisateur changé !");
controller.setMode(SnackbarController.Mode.SUCCESS);
} catch (IOException e) {
e.printStackTrace();
}
});
editUserDialogController.show(root);
}
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
snackbar = new JFXSnackbar(root);
chatController.setCurrentUser(new CurrentUser("Moi", new UserList())); chatController.setCurrentUser(new CurrentUser("Moi", new UserList()));
userListController.addRefreshUserListener(() -> { userListController.addRefreshUserListener(() -> {
System.out.println("refresh event"); System.out.println("refresh event");
@ -34,7 +68,11 @@ public class MainController implements Initializable {
System.out.println("send event"); System.out.println("send event");
}); });
chatController.addEditListener(() -> { chatController.addEditListener(() -> {
System.out.println("edit event"); try {
openEditUsernameDialog();
} catch (IOException e) {
e.printStackTrace();
}
}); });
} }
} }

View file

@ -0,0 +1,149 @@
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.RequiredFieldValidator;
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 EditUsernameDialogController implements Initializable {
enum State {
VALID,
INVALID,
NETWORK
}
@FXML
private Label titleLabel;
@FXML
private Label descriptionLabel;
@FXML
private JFXDialog dialog;
@FXML
private JFXTextField textField;
@FXML
private JFXButton confirmButton;
@FXML
private JFXButton cancelButton;
private State currentState;
private Validator validator;
private ButtonPressEvent successListener;
public void setOnSuccessListener(ButtonPressEvent listener) {
this.successListener = listener;
}
public void show(StackPane root) {
setLocked(false);
setFieldError(State.VALID);
textField.setText("");
dialog.show(root);
}
public void hide() {
dialog.close();
}
public void onCancel() {
hide();
}
private void setLocked(boolean state) {
confirmButton.setDisable(state);
cancelButton.setDisable(state);
dialog.setOverlayClose(!state);
textField.setDisable(state);
}
private void onSuccess() {
setFieldError(State.VALID);
setLocked(false);
hide();
successListener.onPress();
}
private void onError() {
validator.setMessage("Nom d'utilisateur invalide");
setFieldError(State.INVALID);
setLocked(false);
}
private void setFieldError(State state) {
currentState = state;
textField.validate();
}
public void onConfirm() {
setLocked(true);
// TODO replace by network call
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
// onError();
onSuccess();
}
}, 1000);
}
public void onUsernameChange(ObservableValue<? extends String> observable, String oldText, String newText) {
setFieldError(State.VALID);
confirmButton.setDisable(newText.isEmpty());
}
public void setMode(Mode mode) {
switch (mode) {
case INITIAL:
titleLabel.setText("Nom d'utilisateur");
descriptionLabel.setText("Choisissez votre nom d'utilisateur. Vous pourrez le changer plus tard");
break;
case ERROR:
titleLabel.setText("Nom d'utilisateur expiré");
descriptionLabel.setText("Votre nom d'utilisateur n'est plus valide, merci d'en choisir un autre.");
break;
case EDIT:
titleLabel.setText("Changer le nom d'utilisateur");
descriptionLabel.setText("Entrez votre nouveau nom d'utilisateur");
break;
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
validator = new Validator();
currentState = State.VALID;
setMode(Mode.INITIAL);
confirmButton.setDisable(true);
textField.textProperty().addListener(this::onUsernameChange);
textField.getValidators().add(validator);
}
public enum Mode {
INITIAL,
ERROR,
EDIT
}
class Validator extends ValidatorBase {
@Override
protected void eval() {
this.hasErrors = new ReadOnlyBooleanWrapper(currentState != State.VALID);
}
}
}

View file

@ -0,0 +1,64 @@
package fr.insa.clavardator.ui.dialogs;
import com.jfoenix.effects.JFXDepthManager;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import org.kordamp.ikonli.javafx.FontIcon;
import java.net.URL;
import java.util.Arrays;
import java.util.ResourceBundle;
public class SnackbarController implements Initializable {
@FXML
public Label label;
@FXML
public FontIcon icon;
@FXML
public HBox container;
public void setText(String text) {
label.setText(text);
}
public void setMode(Mode mode) {
ObservableList<String> styleClasses = container.getStyleClass();
styleClasses.clear();
styleClasses.add("snackbar-container");
switch (mode) {
case INFO:
styleClasses.add("snackbar-container-info");
icon.setIconLiteral("fas-info-circle");
break;
case WARNING:
styleClasses.add("snackbar-container-warning");
icon.setIconLiteral("fas-exclamation-triangle");
break;
case ERROR:
styleClasses.add("snackbar-container-danger");
icon.setIconLiteral("fas-times-circle");
break;
case SUCCESS:
styleClasses.add("snackbar-container-success");
icon.setIconLiteral("fas-check-circle");
break;
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
setMode(Mode.INFO);
JFXDepthManager.setDepth(container, 1);
}
public enum Mode {
INFO,
WARNING,
ERROR,
SUCCESS
}
}

View file

@ -0,0 +1,46 @@
<?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.EditUsernameDialogController"
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" fx:id="titleLabel">TITLE</Label>
<VBox VBox.vgrow="ALWAYS" alignment="CENTER" spacing="30">
<Label VBox.vgrow="ALWAYS" fx:id="descriptionLabel">DESCRIPTION</Label>
<JFXTextField HBox.hgrow="ALWAYS" fx:id="textField" promptText="Nom d'utilisateur" labelFloat="true"/>
</VBox>
</VBox>
<HBox spacing="50" alignment="CENTER">
<JFXButton text="Annuler" styleClass="background-danger" fx:id="cancelButton" onAction="#onCancel">
<graphic>
<FontIcon iconLiteral="fas-times"/>
</graphic>
</JFXButton>
<JFXButton text="Valider" styleClass="background-success" fx:id="confirmButton" onAction="#onConfirm">
<graphic>
<FontIcon iconLiteral="fas-check"/>
</graphic>
</JFXButton>
</HBox>
</VBox>
</AnchorPane>
</JFXDialog>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
<?import javafx.geometry.Insets?>
<AnchorPane xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="fr.insa.clavardator.ui.dialogs.SnackbarController"
stylesheets="@../styles.css">
<HBox fx:id="container" alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="400" AnchorPane.rightAnchor="0"
AnchorPane.leftAnchor="0" AnchorPane.topAnchor="0" AnchorPane.bottomAnchor="100"
styleClass="snackbar-container">
<padding>
<Insets left="10" right="10" top="10" bottom="10"/>
</padding>
<Label HBox.hgrow="ALWAYS" fx:id="label">
<graphic>
<FontIcon fx:id="icon"/>
</graphic>
TEXT
</Label>
</HBox>
</AnchorPane>

View file

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<!--suppress JavaFxUnresolvedFxIdReference --> <!--suppress JavaFxUnresolvedFxIdReference -->
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" <?import javafx.scene.layout.HBox?>
xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.insa.clavardator.ui.MainController"> <?import javafx.scene.layout.StackPane?>
<HBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" <StackPane xmlns:fx="http://javafx.com/fxml/1"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> 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="users/userList.fxml" fx:id="userList"/>
<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>
</AnchorPane> </StackPane>

View file

@ -1,128 +1,218 @@
/********************************************************
THEME
*********************************************************/
* {
-primary: #296ba4;
-text: #EAEAEA;
-caption: #c9c9c9;
-background: #33333B;
-background-light: #36383E;
-background-lighter: #3e4046;
-background-alert: #dfdfdf;
-success: #32b612;
-warn: #c4980a;
-danger: #b62424;
}
/********************************************************
STYLE
*********************************************************/
.label, .button, .jfx-text-field { .label, .button, .jfx-text-field {
-fx-text-fill: #EAEAEA;
-fx-font-size: 20; -fx-font-size: 20;
-fx-text-fill: -text;
} }
.ikonli-font-icon { .ikonli-font-icon {
-fx-icon-color: #EAEAEA; -fx-icon-color: -text;
}
.container {
-fx-background-color: #33333B;
}
.inner {
-fx-background-color: #36383E;
} }
.jfx-button { .jfx-button {
-fx-background-color: #32338F; -fx-background-color: -primary;
-fx-background-radius: 5;
-jfx-button-type: "RAISED";
-fx-cursor: "hand";
} }
.active-user-item { .jfx-text-field {
-fx-background-color: #3e4046; -jfx-focus-color: -primary;
} }
.inactive-user-item { .container {
-fx-background-color: #36383E; -fx-background-color: -background;
} }
.selected-user-item { .inner, .list-cell:empty {
-fx-background-color: #32338F; -fx-background-color: -background-light;
} }
.active-user-dot { .active-user-dot {
-fx-fill: #32b612; -fx-fill: -success;
} }
.inactive-user-dot { .inactive-user-dot {
-fx-fill: #5b5b5b; -fx-fill: -background-lighter;
} }
.message-self, .message-other { .background-success {
-fx-font-size: 18; -fx-background-color: -success;
} }
.message-self { .background-danger {
-fx-background-color: #347dbd; -fx-background-color: -danger;
} }
.message-other { .background-warning {
-fx-background-color: #555555; -fx-background-color: -warn;
}
.timestamp {
-fx-text-fill: #c9c9c9;
-fx-font-size: 12;
} }
.current-user { .current-user {
-fx-font-size: 25; -fx-font-size: 25;
} }
.dialog-title {
-fx-font-size: 30;
}
.timestamp {
-fx-text-fill: -caption;
-fx-font-size: 12;
}
.message-self, .message-other {
-fx-background-radius: 20;
-fx-font-size: 18;
}
.message-other {
-fx-background-color: -background-lighter;
}
.message-self {
-fx-background-color: -primary;
}
.selected-user-item, .active-user-item, .inactive-user-item {
-fx-background-radius: 0 20 20 0;
-jfx-button-type: "FLAT";
}
.active-user-item {
-fx-background-color: -background-lighter;
}
.inactive-user-item {
-fx-background-color: -background-light;
}
.selected-user-item {
-fx-background-color: -primary;
}
.list-view { .list-view {
-fx-background-color: -background-light;
-fx-padding: 0; -fx-padding: 0;
-fx-background-color: #36383E;
} }
.list-cell:empty { .snackbar-container {
-fx-background-color: #36383E; -fx-background-color: -background-alert;
-fx-border-radius: 10;
-fx-background-radius: 10;
-fx-border-width: 0.5;
} }
.jfx-text-field { .snackbar-container-info {
-jfx-focus-color: #32338F; -fx-text-fill: -primary;
-fx-border-color: -primary;
} }
.snackbar-container-info * {
-fx-text-fill: -primary;
-fx-icon-color: -primary;
}
.snackbar-container-success {
-fx-border-color: -success;
}
.snackbar-container-success * {
-fx-text-fill: -success;
-fx-icon-color: -success;
}
.snackbar-container-warning {
-fx-border-color: -warn;
}
.snackbar-container-warning * {
-fx-text-fill: -warn;
-fx-icon-color: -warn;
}
.snackbar-container-danger {
-fx-border-color: -danger;
}
.snackbar-container-danger * {
-fx-text-fill: -danger;
-fx-icon-color: -danger;
}
/******************************************************** /********************************************************
SCROLLBARS SCROLLBARS
*********************************************************/ *********************************************************/
.scroll-bar:horizontal .track, .scroll-bar:horizontal .track,
.scroll-bar:vertical .track{ .scroll-bar:vertical .track {
-fx-background-color : #33333B; -fx-background-color: #33333B;
-fx-border-color :transparent; -fx-border-color: transparent;
-fx-background-radius : 0.0em; -fx-background-radius: 0.0em;
-fx-border-radius :2.0em; -fx-border-radius: 2.0em;
} }
.scroll-bar:horizontal .increment-button , .scroll-bar:horizontal .increment-button,
.scroll-bar:horizontal .decrement-button { .scroll-bar:horizontal .decrement-button {
-fx-background-color :transparent; -fx-background-color: transparent;
-fx-background-radius : 0.0em; -fx-background-radius: 0.0em;
-fx-padding :0.0 0.0 10.0 0.0; -fx-padding: 0.0 0.0 10.0 0.0;
} }
.scroll-bar:vertical .increment-button , .scroll-bar:vertical .increment-button,
.scroll-bar:vertical .decrement-button { .scroll-bar:vertical .decrement-button {
-fx-background-color :transparent; -fx-background-color: transparent;
-fx-background-radius : 0.0em; -fx-background-radius: 0.0em;
-fx-padding :0.0 10.0 0.0 0.0; -fx-padding: 0.0 10.0 0.0 0.0;
} }
.scroll-bar .increment-arrow, .scroll-bar .increment-arrow,
.scroll-bar .decrement-arrow{ .scroll-bar .decrement-arrow {
-fx-shape : " "; -fx-shape: " ";
-fx-padding :0.15em 0.0; -fx-padding: 0.15em 0.0;
} }
.scroll-bar:vertical .increment-arrow, .scroll-bar:vertical .increment-arrow,
.scroll-bar:vertical .decrement-arrow{ .scroll-bar:vertical .decrement-arrow {
-fx-shape : " "; -fx-shape: " ";
-fx-padding :0.0 0.15em; -fx-padding: 0.0 0.15em;
} }
.scroll-bar:horizontal .thumb, .scroll-bar:horizontal .thumb,
.scroll-bar:vertical .thumb { .scroll-bar:vertical .thumb {
-fx-background-color :derive(#33333B,50.0%); -fx-background-color: derive(#33333B, 50.0%);
-fx-background-insets : 2.0, 0.0, 0.0; -fx-background-insets: 2.0, 0.0, 0.0;
-fx-background-radius : 1.0em; -fx-background-radius: 1.0em;
} }
.scroll-bar:horizontal .thumb:hover, .scroll-bar:horizontal .thumb:hover,
.scroll-bar:vertical .thumb:hover { .scroll-bar:vertical .thumb:hover {
-fx-background-color :derive(#33333B,80.0%); -fx-background-color: derive(#33333B, 80.0%);
-fx-background-insets : 2.0, 0.0, 0.0; -fx-background-insets: 2.0, 0.0, 0.0;
-fx-background-radius : 1.0em; -fx-background-radius: 1.0em;
} }