From fb3460f4b8e6999b92118b6d4e6b01cd43520eba Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Sat, 5 Dec 2020 17:49:14 +0100 Subject: [PATCH] feat: show snackbar on username change --- .../insa/clavardator/ui/MainController.java | 40 +++- .../dialogs/EditUsernameDialogController.java | 149 +++++++++++++ .../ui/dialogs/SnackbarController.java | 64 ++++++ .../ui/dialogs/editUsernameDialog.fxml | 46 ++++ .../insa/clavardator/ui/dialogs/snackbar.fxml | 25 +++ .../fr/insa/clavardator/ui/scene.fxml | 13 +- .../fr/insa/clavardator/ui/styles.css | 210 +++++++++++++----- 7 files changed, 480 insertions(+), 67 deletions(-) create mode 100644 src/main/java/fr/insa/clavardator/ui/dialogs/EditUsernameDialogController.java create mode 100644 src/main/java/fr/insa/clavardator/ui/dialogs/SnackbarController.java create mode 100644 src/main/resources/fr/insa/clavardator/ui/dialogs/editUsernameDialog.fxml create mode 100644 src/main/resources/fr/insa/clavardator/ui/dialogs/snackbar.fxml diff --git a/src/main/java/fr/insa/clavardator/ui/MainController.java b/src/main/java/fr/insa/clavardator/ui/MainController.java index 047cf9b..2be3a92 100644 --- a/src/main/java/fr/insa/clavardator/ui/MainController.java +++ b/src/main/java/fr/insa/clavardator/ui/MainController.java @@ -1,24 +1,58 @@ package fr.insa.clavardator.ui; +import com.jfoenix.controls.JFXSnackbar; 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.users.CurrentUser; import fr.insa.clavardator.users.UserList; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; +import javafx.scene.control.Label; +import javafx.scene.layout.StackPane; +import java.io.IOException; import java.net.URL; import java.util.ResourceBundle; public class MainController implements Initializable { + @FXML + private StackPane root; + + @FXML + private EditUsernameDialogController editUserDialogController; @FXML private UserListController userListController; @FXML 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 public void initialize(URL url, ResourceBundle rb) { + snackbar = new JFXSnackbar(root); chatController.setCurrentUser(new CurrentUser("Moi", new UserList())); userListController.addRefreshUserListener(() -> { System.out.println("refresh event"); @@ -34,7 +68,11 @@ public class MainController implements Initializable { System.out.println("send event"); }); chatController.addEditListener(() -> { - System.out.println("edit event"); + try { + openEditUsernameDialog(); + } catch (IOException e) { + e.printStackTrace(); + } }); } } diff --git a/src/main/java/fr/insa/clavardator/ui/dialogs/EditUsernameDialogController.java b/src/main/java/fr/insa/clavardator/ui/dialogs/EditUsernameDialogController.java new file mode 100644 index 0000000..b91529e --- /dev/null +++ b/src/main/java/fr/insa/clavardator/ui/dialogs/EditUsernameDialogController.java @@ -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 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); + } + } +} diff --git a/src/main/java/fr/insa/clavardator/ui/dialogs/SnackbarController.java b/src/main/java/fr/insa/clavardator/ui/dialogs/SnackbarController.java new file mode 100644 index 0000000..7ffb879 --- /dev/null +++ b/src/main/java/fr/insa/clavardator/ui/dialogs/SnackbarController.java @@ -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 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 + } +} diff --git a/src/main/resources/fr/insa/clavardator/ui/dialogs/editUsernameDialog.fxml b/src/main/resources/fr/insa/clavardator/ui/dialogs/editUsernameDialog.fxml new file mode 100644 index 0000000..479b5a6 --- /dev/null +++ b/src/main/resources/fr/insa/clavardator/ui/dialogs/editUsernameDialog.fxml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/fr/insa/clavardator/ui/dialogs/snackbar.fxml b/src/main/resources/fr/insa/clavardator/ui/dialogs/snackbar.fxml new file mode 100644 index 0000000..a4c8bf9 --- /dev/null +++ b/src/main/resources/fr/insa/clavardator/ui/dialogs/snackbar.fxml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/src/main/resources/fr/insa/clavardator/ui/scene.fxml b/src/main/resources/fr/insa/clavardator/ui/scene.fxml index cdf83e2..58813c0 100644 --- a/src/main/resources/fr/insa/clavardator/ui/scene.fxml +++ b/src/main/resources/fr/insa/clavardator/ui/scene.fxml @@ -1,12 +1,13 @@ - - - + + + + + - + diff --git a/src/main/resources/fr/insa/clavardator/ui/styles.css b/src/main/resources/fr/insa/clavardator/ui/styles.css index 7aab716..9d946a5 100644 --- a/src/main/resources/fr/insa/clavardator/ui/styles.css +++ b/src/main/resources/fr/insa/clavardator/ui/styles.css @@ -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 { - -fx-text-fill: #EAEAEA; -fx-font-size: 20; + -fx-text-fill: -text; } .ikonli-font-icon { - -fx-icon-color: #EAEAEA; -} - -.container { - -fx-background-color: #33333B; -} - -.inner { - -fx-background-color: #36383E; + -fx-icon-color: -text; } .jfx-button { - -fx-background-color: #32338F; + -fx-background-color: -primary; + -fx-background-radius: 5; + -jfx-button-type: "RAISED"; + -fx-cursor: "hand"; } -.active-user-item { - -fx-background-color: #3e4046; +.jfx-text-field { + -jfx-focus-color: -primary; } -.inactive-user-item { - -fx-background-color: #36383E; +.container { + -fx-background-color: -background; } -.selected-user-item { - -fx-background-color: #32338F; +.inner, .list-cell:empty { + -fx-background-color: -background-light; } .active-user-dot { - -fx-fill: #32b612; + -fx-fill: -success; } .inactive-user-dot { - -fx-fill: #5b5b5b; + -fx-fill: -background-lighter; } -.message-self, .message-other { - -fx-font-size: 18; +.background-success { + -fx-background-color: -success; } -.message-self { - -fx-background-color: #347dbd; +.background-danger { + -fx-background-color: -danger; } -.message-other { - -fx-background-color: #555555; -} - -.timestamp { - -fx-text-fill: #c9c9c9; - -fx-font-size: 12; +.background-warning { + -fx-background-color: -warn; } .current-user { -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 { + -fx-background-color: -background-light; -fx-padding: 0; - -fx-background-color: #36383E; } -.list-cell:empty { - -fx-background-color: #36383E; +.snackbar-container { + -fx-background-color: -background-alert; + -fx-border-radius: 10; + -fx-background-radius: 10; + -fx-border-width: 0.5; } -.jfx-text-field { - -jfx-focus-color: #32338F; +.snackbar-container-info { + -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 *********************************************************/ .scroll-bar:horizontal .track, -.scroll-bar:vertical .track{ - -fx-background-color : #33333B; - -fx-border-color :transparent; - -fx-background-radius : 0.0em; - -fx-border-radius :2.0em; +.scroll-bar:vertical .track { + -fx-background-color: #33333B; + -fx-border-color: transparent; + -fx-background-radius: 0.0em; + -fx-border-radius: 2.0em; } -.scroll-bar:horizontal .increment-button , +.scroll-bar:horizontal .increment-button, .scroll-bar:horizontal .decrement-button { - -fx-background-color :transparent; - -fx-background-radius : 0.0em; - -fx-padding :0.0 0.0 10.0 0.0; + -fx-background-color: transparent; + -fx-background-radius: 0.0em; + -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 { - -fx-background-color :transparent; - -fx-background-radius : 0.0em; - -fx-padding :0.0 10.0 0.0 0.0; + -fx-background-color: transparent; + -fx-background-radius: 0.0em; + -fx-padding: 0.0 10.0 0.0 0.0; } .scroll-bar .increment-arrow, -.scroll-bar .decrement-arrow{ - -fx-shape : " "; - -fx-padding :0.15em 0.0; +.scroll-bar .decrement-arrow { + -fx-shape: " "; + -fx-padding: 0.15em 0.0; } .scroll-bar:vertical .increment-arrow, -.scroll-bar:vertical .decrement-arrow{ - -fx-shape : " "; - -fx-padding :0.0 0.15em; +.scroll-bar:vertical .decrement-arrow { + -fx-shape: " "; + -fx-padding: 0.0 0.15em; } .scroll-bar:horizontal .thumb, .scroll-bar:vertical .thumb { - -fx-background-color :derive(#33333B,50.0%); - -fx-background-insets : 2.0, 0.0, 0.0; - -fx-background-radius : 1.0em; + -fx-background-color: derive(#33333B, 50.0%); + -fx-background-insets: 2.0, 0.0, 0.0; + -fx-background-radius: 1.0em; } .scroll-bar:horizontal .thumb:hover, .scroll-bar:vertical .thumb:hover { - -fx-background-color :derive(#33333B,80.0%); - -fx-background-insets : 2.0, 0.0, 0.0; - -fx-background-radius : 1.0em; + -fx-background-color: derive(#33333B, 80.0%); + -fx-background-insets: 2.0, 0.0, 0.0; + -fx-background-radius: 1.0em; } \ No newline at end of file