diff --git a/demo/src/main/java/demos/components/NotificationDemo.java b/demo/src/main/java/demos/components/NotificationDemo.java new file mode 100644 index 000000000..cfb28e206 --- /dev/null +++ b/demo/src/main/java/demos/components/NotificationDemo.java @@ -0,0 +1,75 @@ +package demos.components; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXNotifications; +import com.jfoenix.notification.template.JFXSimpleNotificationTemplate; +import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon; +import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView; +import javafx.application.Application; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.StackPane; +import javafx.stage.Stage; +import javafx.util.Duration; + +public final class NotificationDemo extends Application { + + @Override + public void start(Stage stage) { + JFXButton buttonTopLeft = new JFXButton("Open TOP LEFT"); + JFXButton buttonTopCenter = new JFXButton("Open TOP CENTER"); + JFXButton buttonTopRight = new JFXButton("Open TOP RIGHT"); + JFXButton buttonCenterLeft = new JFXButton("Open CENTER LEFT"); + JFXButton buttonCenter = new JFXButton("Open CENTER"); + JFXButton buttonCenterRight = new JFXButton("Open CENTER RIGHT"); + JFXButton buttonBottomLeft = new JFXButton("Open BOTTOM LEFT"); + JFXButton buttonBottomCenter = new JFXButton("Open BOTTOM CENTER"); + JFXButton buttonBottomRight = new JFXButton("Open BOTTOM RIGHT"); + + buttonTopLeft.setOnAction( __ -> showDialog(Pos.TOP_LEFT)); + buttonTopCenter.setOnAction( __ -> showDialog(Pos.TOP_CENTER)); + buttonTopRight.setOnAction( __ -> showDialog(Pos.TOP_RIGHT)); + buttonCenterLeft.setOnAction( __ -> showDialog(Pos.CENTER_LEFT)); + buttonCenter.setOnAction( __ -> showDialog(Pos.CENTER)); + buttonCenterRight.setOnAction( __ -> showDialog(Pos.CENTER_RIGHT)); + buttonBottomLeft.setOnAction( __ -> showDialog(Pos.BOTTOM_LEFT)); + buttonBottomCenter.setOnAction( __ -> showDialog(Pos.BOTTOM_CENTER)); + buttonBottomRight.setOnAction( __ -> showDialog(Pos.BOTTOM_RIGHT)); + FlowPane pane = new FlowPane(); + pane.setHgap(5); + pane.setVgap(5); + pane.getChildren().addAll(buttonTopLeft,buttonTopCenter,buttonTopRight,buttonCenterLeft, + buttonCenter,buttonCenterRight,buttonBottomLeft,buttonBottomCenter,buttonBottomRight); + pane.getChildren().forEach(button -> { + button.setStyle("-fx-background-color: WHITE"); + ((JFXButton)button).setButtonType(JFXButton.ButtonType.RAISED); + }); + final Scene scene = new Scene(pane, 800, 200); + scene.getStylesheets().addAll(NotificationDemo.class.getResource("/css/jfoenix-fonts.css").toExternalForm(), + NotificationDemo.class.getResource("/css/jfoenix-design.css").toExternalForm(), + NotificationDemo.class.getResource("/css/jfoenix-components.css").toExternalForm()); + stage.setTitle("JFXNotification Demo"); + stage.setScene(scene); + stage.show(); + } + + private void showDialog(Pos pos){ + JFXSimpleNotificationTemplate template = new JFXSimpleNotificationTemplate(); + FontAwesomeIconView icon = new FontAwesomeIconView(FontAwesomeIcon.GLASS); + template.setHeader(icon, "Fast Food"); + template.setBody("Lily (MacDonald)","Su pedido esta listo, solo debe recogerlo en el lugar mas solicitado"); + JFXButton aceptar = new JFXButton("Responder"); + template.setActions(aceptar); + JFXNotifications.create().position(pos) + .hideAfter(Duration.seconds(6)) + .template(template) + .showMessage(); + } + + public static void main(String[] args) { + launch(args); + } + +} diff --git a/demo/src/main/java/demos/components/PopupDemo.java b/demo/src/main/java/demos/components/PopupDemo.java index 1ea7b303d..f5bce0f04 100644 --- a/demo/src/main/java/demos/components/PopupDemo.java +++ b/demo/src/main/java/demos/components/PopupDemo.java @@ -39,6 +39,7 @@ public void start(Stage primaryStage) throws Exception { main.getChildren().add(container); JFXPopup popup = new JFXPopup(list); + rippler.setOnMouseClicked(e -> popup.show(rippler, PopupVPosition.TOP, PopupHPosition.LEFT)); final Scene scene = new Scene(main, 800, 800); diff --git a/demo/src/main/resources/css/jfoenix-components.css b/demo/src/main/resources/css/jfoenix-components.css index b1dc2e58a..d98aedd18 100644 --- a/demo/src/main/resources/css/jfoenix-components.css +++ b/demo/src/main/resources/css/jfoenix-components.css @@ -340,4 +340,23 @@ -fx-padding: 5 0 5 0; } +.jfx-notification-template .jfx-notification-action { + -fx-spacing: 5; +} +.jfx-notification-template .jfx-notification-action > .btn-action { + -jfx-disable-visual-focus: true; + -fx-text-fill: #2E7D32; + -fx-background-insets: 0; + -fx-padding: 0 0 0 0; + -fx-alignment: center; + -fx-font-family: "Roboto Medium"; + -fx-cursor: HAND; + -fx-pref-width: 90; + -fx-pref-height: 30; +} + +.jfx-notification-template .jfx-notification-header > .glyph-icon{ + -glyph-size: 16; + -fx-fill: #2E7D32; +} diff --git a/jfoenix/src/main/java/com/jfoenix/controls/JFXNotifications.java b/jfoenix/src/main/java/com/jfoenix/controls/JFXNotifications.java new file mode 100644 index 000000000..e9682d454 --- /dev/null +++ b/jfoenix/src/main/java/com/jfoenix/controls/JFXNotifications.java @@ -0,0 +1,360 @@ +package com.jfoenix.controls; + +import com.jfoenix.notification.JFXAbstractNotificationTemplate; +import com.jfoenix.skins.JFXNotificationBar; +import javafx.animation.*; +import javafx.geometry.Pos; +import javafx.geometry.Rectangle2D; +import javafx.scene.Node; +import javafx.stage.Popup; +import javafx.stage.PopupWindow; +import javafx.stage.Screen; +import javafx.stage.Window; +import javafx.util.Duration; +import java.lang.ref.WeakReference; +import java.util.*; + +public class JFXNotifications { + + private Pos position = Pos.BOTTOM_RIGHT; + private Duration hideAfterDuration = Duration.seconds(5); + private Window owner; + private JFXAbstractNotificationTemplate notificationTemplate; + private Screen screen = Screen.getPrimary(); + + /** + * Call this to begin the process of building a notification to show. + */ + public static JFXNotifications create() { + return new JFXNotifications(); + } + + /** + * Specify the position of the notification on screen, by default it is + * {@link Pos#BOTTOM_RIGHT bottom-right}. + */ + public JFXNotifications position(Pos position) { + this.position = position; + return this; + } + + public JFXNotifications template(JFXAbstractNotificationTemplate notificationTemplate){ + this.notificationTemplate = notificationTemplate; + return this; + } + + /** + * The dialog window owner - which can be {@link Screen}, {@link Window} + * or {@link Node}. If specified, the notifications will be inside + * the owner, otherwise the notifications will be shown within the whole + * primary (default) screen. + */ + public JFXNotifications owner(Object owner) { + if (owner instanceof Screen) { + this.screen = (Screen) owner; + } else { + this.owner = getWindow(owner); + } + return this; + } + + /** + * Specify the duration that the notification should show, after which it + * will be hidden. + */ + public JFXNotifications hideAfter(Duration duration) { + this.hideAfterDuration = duration; + return this; + } + + /** + * Instructs the notification to be shown, and that it should use the + * built-in 'confirm' graphic. + */ + public void showMessage() { + show(); + } + + /** + * Instructs the notification to be shown. + */ + private void show() { + JFXNotifications.NotificationPopupHandler.getInstance().show(this); + } + + /*************************************************************************** + * * Private support classes * * + **************************************************************************/ + + private static final class NotificationPopupHandler { + + private static final JFXNotifications.NotificationPopupHandler INSTANCE = new JFXNotifications.NotificationPopupHandler(); + + private double startX; + private double startY; + private double screenWidth; + private double screenHeight; + + static JFXNotifications.NotificationPopupHandler getInstance() { + return INSTANCE; + } + + private final Map> popupsMap = new HashMap<>(); + private final double padding = 15; + + private ParallelTransition parallelTransition = new ParallelTransition(); + + private boolean isShowing = false; + + void show(JFXNotifications notification) { + Window window; + if (notification.owner == null) { + Rectangle2D screenBounds = notification.screen.getVisualBounds(); + startX = screenBounds.getMinX(); + startY = screenBounds.getMinY(); + screenWidth = screenBounds.getWidth(); + screenHeight = screenBounds.getHeight(); + + window = getWindow(null); + } else { + startX = notification.owner.getX(); + startY = notification.owner.getY(); + screenWidth = notification.owner.getWidth(); + screenHeight = notification.owner.getHeight(); + window = notification.owner; + } + show(window, notification); + } + + private void show(Window owner, final JFXNotifications notification) { + final Popup popup = new Popup(); + popup.setAutoFix(false); + final Pos p = notification.position; + + notification.notificationTemplate.setNotificationPane(new JFXNotificationBar() { + + @Override + public boolean isShowing() { + return isShowing; + } + + @Override + public boolean isShowFromTop() { + return JFXNotifications.NotificationPopupHandler.this.isShowFromTop(notification.position); + } + + @Override + public Node getContentPane() { + return notification.notificationTemplate; + } + + @Override + public void hide() { + isShowing = false; + createHideTimeline(popup, this, p, Duration.ZERO).play(); + } + + @Override + public double getContainerHeight() { + return startY + screenHeight; + } + + @Override + public void relocateInParent(double x, double y) { + switch (p) { + case BOTTOM_LEFT: + case BOTTOM_CENTER: + case BOTTOM_RIGHT: + popup.setAnchorY(y - padding); + break; + default: break; + } + } + }); + + popup.getContent().add(notification.notificationTemplate.getNotificationBar()); + popup.show(owner, 0, 0); + + double anchorX, anchorY; + final double barWidth = notification.notificationTemplate.getNotificationBar().getWidth(); + final double barHeight = notification.notificationTemplate.getNotificationBar().getHeight(); + + switch (p) { + case TOP_LEFT: + case CENTER_LEFT: + case BOTTOM_LEFT: + anchorX = padding + startX; + break; + + case TOP_CENTER: + case CENTER: + case BOTTOM_CENTER: + anchorX = startX + (screenWidth / 2.0) - barWidth / 2.0 - padding / 2.0; + break; + + default: + case TOP_RIGHT: + case CENTER_RIGHT: + case BOTTOM_RIGHT: + anchorX = startX + screenWidth - barWidth - padding; + break; + } + switch (p) { + case TOP_LEFT: + case TOP_CENTER: + case TOP_RIGHT: + anchorY = padding + startY; + break; + case CENTER_LEFT: + case CENTER: + case CENTER_RIGHT: + anchorY = startY + (screenHeight / 2.0) - barHeight - padding / 2; + break; + default: + case BOTTOM_LEFT: + case BOTTOM_CENTER: + case BOTTOM_RIGHT: + anchorY = startY + screenHeight - barHeight - padding; + break; + } + + popup.setAnchorX(anchorX); + popup.setAnchorY(anchorY); + + isShowing = true; + notification.notificationTemplate.getNotificationBar().doShow(); + + addPopupToMap(p, popup); + + Timeline timeline = createHideTimeline(popup, notification.notificationTemplate.getNotificationBar(), p, notification.hideAfterDuration); + timeline.play(); + } + + private void hide(Popup popup, Pos p) { + popup.hide(); + removePopupFromMap(p, popup); + } + + private Timeline createHideTimeline(final Popup popup, JFXNotificationBar bar, final Pos p, Duration startDelay) { + KeyValue fadeOutBegin = new KeyValue(bar.opacityProperty(), 1.0); + KeyValue fadeOutEnd = new KeyValue(bar.opacityProperty(), 0.0); + + KeyFrame kfBegin = new KeyFrame(Duration.ZERO, fadeOutBegin); + KeyFrame kfEnd = new KeyFrame(Duration.millis(500), fadeOutEnd); + + Timeline timeline = new Timeline(kfBegin, kfEnd); + timeline.setDelay(startDelay); + timeline.setOnFinished(e -> hide(popup, p)); + + return timeline; + } + + private void addPopupToMap(Pos p, Popup popup) { + Map popups; + if (!popupsMap.containsKey(p)) { + popups = new LinkedHashMap<>(); + popupsMap.put(p, popups); + } else popups = popupsMap.get(p); + + doAnimation(p, popup); + if(isShowFromTop(p)) popups.put(popup, null); + else popups.put(popup, popup.getAnchorY()); + } + + private void removePopupFromMap(Pos p, Popup popup) { + if (popupsMap.containsKey(p)) { + LinkedHashMap popups = (LinkedHashMap) popupsMap.get(p); + popups.remove(popup); + } + } + + private void doAnimation(Pos p, Popup changedPopup) { + Map popups = popupsMap.get(p); + if (popups == null) return; + + parallelTransition.stop(); + parallelTransition.getChildren().clear(); + + final boolean isShowFromTop = isShowFromTop(p); + + popups.forEach((popup, height) -> { + final double newPopupHeight = changedPopup.getContent().get(0).getBoundsInParent().getHeight(); + final double anchorYTarget; + if(isShowFromTop) { + anchorYTarget = startY + newPopupHeight + padding + ((Objects.isNull(height)) ? 0 : height); + if(height == null) popups.put(popup, newPopupHeight); + else popups.put(popup, newPopupHeight + height); + } else { + anchorYTarget = ((changedPopup.getAnchorY() - newPopupHeight)) + (height - changedPopup.getAnchorY()) ; + popups.put(popup, height - newPopupHeight); + } + + if (anchorYTarget < 0) popup.hide(); + final double oldAnchorY = popup.getAnchorY(); + + final double distance = anchorYTarget - oldAnchorY; + + Transition t = new JFXNotifications.NotificationPopupHandler.CustomTransition(popup, oldAnchorY, distance); + t.setCycleCount(1); + parallelTransition.getChildren().add(t); + }); + parallelTransition.play(); + } + + private boolean isShowFromTop(Pos p) { + switch (p) { + case TOP_LEFT: + case TOP_CENTER: + case TOP_RIGHT: + return true; + default: + return false; + } + } + + class CustomTransition extends Transition { + + private WeakReference popupWeakReference; + private double oldAnchorY; + private double distance; + + CustomTransition(Popup popup, double oldAnchorY, double distance) { + popupWeakReference = new WeakReference<>(popup); + this.oldAnchorY = oldAnchorY; + this.distance = distance; + setCycleDuration(Duration.millis(350.0)); + } + + @Override + protected void interpolate(double frac) { + Popup popup = popupWeakReference.get(); + if (popup != null) { + double newAnchorY = oldAnchorY + distance * frac; + popup.setAnchorY(newAnchorY); + } + } + + } + } + + private static Window getWindow(Object owner) throws IllegalArgumentException { + if (owner == null) { + Window window = null; + @SuppressWarnings("deprecation") + Iterator windows = Window.impl_getWindows(); + while (windows.hasNext()) { + window = windows.next(); + if (window.isFocused() && !(window instanceof PopupWindow)) { + break; + } + } + return window; + } else if (owner instanceof Window) { + return (Window) owner; + } else if (owner instanceof Node) { + return ((Node) owner).getScene().getWindow(); + } else { + throw new IllegalArgumentException("Unknown owner: " + owner.getClass()); + } + } +} diff --git a/jfoenix/src/main/java/com/jfoenix/notification/JFXAbstractNotificationTemplate.java b/jfoenix/src/main/java/com/jfoenix/notification/JFXAbstractNotificationTemplate.java new file mode 100644 index 000000000..2c896b15d --- /dev/null +++ b/jfoenix/src/main/java/com/jfoenix/notification/JFXAbstractNotificationTemplate.java @@ -0,0 +1,38 @@ +package com.jfoenix.notification; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.skins.JFXNotificationBar; +import javafx.scene.Node; +import javafx.scene.layout.VBox; + +public abstract class JFXAbstractNotificationTemplate extends VBox { + + private JFXNotificationBar notificationBar; + +// public abstract void setHeader(Node icon, String title); + + public void setNotificationPane(JFXNotificationBar abstractNotificationPane){ + this.notificationBar = abstractNotificationPane; + } + + public JFXNotificationBar getNotificationBar(){ + return this.notificationBar; + } + + public void hide(){ + this.notificationBar.hide(); + } +// +//// public abstract void setHeader(Node icon, String heading, boolean closeButton); +// +// public abstract void setHeader(Node nodeHeader); +// +//// public abstract void setBody(String title, String subTitle); +// public abstract void setBody(Node nodeBody); +// +// public abstract void setActions(Node nodeActions); +// +//// public abstract void setActions(JFXButton... actions); + +} + diff --git a/jfoenix/src/main/java/com/jfoenix/notification/template/JFXSimpleNotificationTemplate.java b/jfoenix/src/main/java/com/jfoenix/notification/template/JFXSimpleNotificationTemplate.java new file mode 100644 index 000000000..2540f7a2a --- /dev/null +++ b/jfoenix/src/main/java/com/jfoenix/notification/template/JFXSimpleNotificationTemplate.java @@ -0,0 +1,83 @@ +package com.jfoenix.notification.template; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXRippler; +import com.jfoenix.notification.JFXAbstractNotificationTemplate; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.*; + +import java.util.Arrays; + +public class JFXSimpleNotificationTemplate extends JFXAbstractNotificationTemplate { + + private HBox header = new HBox(); + private StackPane body = new StackPane(); + private FlowPane actions = new FlowPane(); + + public JFXSimpleNotificationTemplate() { + initialize(); + header.getStyleClass().addAll("jfx-notification-header"); + body.getStyleClass().addAll("jfx-notification-body"); + actions.getStyleClass().addAll("jfx-notification-action"); + getChildren().setAll(header, body, actions); + } + + public void setHeader(Node icon, String heading, boolean closeButton) { + Label labelTitle = new Label(heading); + labelTitle.getStyleClass().addAll("label-header"); + labelTitle.setMaxWidth(Double.MAX_VALUE); + header.getChildren().addAll(icon, labelTitle); + HBox.setHgrow(labelTitle, Priority.ALWAYS); + + if(closeButton){ + JFXRippler ripplerClose = new JFXRippler(); + ripplerClose.setOnMouseClicked(__ -> { ripplerClose.setDisable(true); hide(); } ); + StackPane boxClose = new StackPane(); + boxClose.getStyleClass().add("box-close"); + StackPane graphic = new StackPane(); + graphic.getStyleClass().setAll("graphic"); + boxClose.getChildren().add(graphic); + ripplerClose.setControl(boxClose); + header.getChildren().add(ripplerClose); + } + } + + public void setHeader(Node icon, String heading) { + setHeader(icon,heading,true); + } + + public void setBody(String subTitle, String message) { + Label labelSubTitle = new Label(subTitle); + Label labelMessage = new Label(message); + labelSubTitle.getStyleClass().addAll("label-sub-title"); + labelMessage.getStyleClass().addAll("label-message"); + + VBox bodyContent = new VBox(); + VBox.setVgrow(labelMessage, Priority.ALWAYS); + + bodyContent.getChildren().addAll(labelSubTitle, labelMessage); + bodyContent.getStyleClass().add("simple-body"); + body.getChildren().add(bodyContent); + } + + public void setActions(JFXButton... actions) { + Arrays.asList(actions).forEach(button -> { + button.getStyleClass().add("btn-action"); + button.setOnMouseClicked( __ -> hide() ); + }); + this.actions.getChildren().setAll(actions); + } + + @Override + public String getUserAgentStylesheet() { + return JFXSimpleNotificationTemplate.class.getResource("/css/controls/jfx-notification.css").toExternalForm(); + } + + private static final String DEFAULT_STYLE_CLASS = "jfx-notification-template"; + + private void initialize() { + this.getStyleClass().add(DEFAULT_STYLE_CLASS); + } + +} diff --git a/jfoenix/src/main/java/com/jfoenix/skins/JFXNotificationBar.java b/jfoenix/src/main/java/com/jfoenix/skins/JFXNotificationBar.java new file mode 100644 index 000000000..df5634c5a --- /dev/null +++ b/jfoenix/src/main/java/com/jfoenix/skins/JFXNotificationBar.java @@ -0,0 +1,130 @@ +package com.jfoenix.skins; + +import javafx.animation.*; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.event.Event; +import javafx.event.EventType; +import javafx.scene.Node; +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.Region; +import javafx.util.Duration; + +public abstract class JFXNotificationBar extends Region { + + private final ScrollPane pane; + + public abstract Node getContentPane(); + + private static final EventType ON_SHOWING = new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_SHOWING"); + + private static final EventType ON_SHOWN = new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_SHOWN"); + + private DoubleProperty transition = new SimpleDoubleProperty() { + @Override + protected void invalidated() { + layoutChildren(); + } + }; + + public abstract void hide(); + + public abstract boolean isShowing(); + + public abstract boolean isShowFromTop(); + + public abstract double getContainerHeight(); + + public abstract void relocateInParent(double x, double y); + + public JFXNotificationBar() { + getStyleClass().add("jfx-notification-bar"); + setVisible(isShowing()); + pane = new ScrollPane(); + pane.setFitToWidth(true); + pane.setFitToHeight(true); + pane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + pane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + pane.getStyleClass().add("pane"); + getChildren().setAll(pane); + pane.setContent(getContentPane()); + } + + @Override + public String getUserAgentStylesheet() { + return JFXNotificationBar.class.getResource("/css/controls/jfx-notification.css").toExternalForm(); + } + + @Override + protected void layoutChildren() { + final double w = getWidth(); + final double h = computePrefHeight(-1); + + final double notificationBarHeight = prefHeight(w); + final double notificationMinHeight = minHeight(w); + + if (isShowFromTop()) { + pane.resize(w, h); + relocateInParent(0, (transition.get() - 1) * notificationMinHeight); + } else { + pane.resize(w, notificationBarHeight); + relocateInParent(0, getContainerHeight() - notificationBarHeight); + } + } + + @Override + protected double computeMinHeight(double width) { + return Math.max(super.computePrefHeight(width), 0); + } + + @Override + protected double computePrefHeight(double width) { + return Math.max(pane.prefHeight(width), minHeight(width)) * transition.get(); + } + + public void doShow() { + transitionStartValue = 0; + doAnimationTransition(); + } + + private final Duration TRANSITION_DURATION = new Duration(350.0); + private Timeline timeline; + private double transitionStartValue; + + private void doAnimationTransition() { + Duration duration; + + if (timeline != null && (timeline.getStatus() != Animation.Status.STOPPED)) { + duration = timeline.getCurrentTime(); + duration = duration == Duration.ZERO ? TRANSITION_DURATION : duration; + transitionStartValue = transition.get(); + timeline.stop(); + } else { + duration = TRANSITION_DURATION; + } + + timeline = new Timeline(); + timeline.setCycleCount(1); + KeyFrame k1 = new KeyFrame( + Duration.ZERO, + event -> { + setCache(true); + setVisible(true); + pane.fireEvent(new Event(ON_SHOWING)); + }, + new KeyValue(transition, transitionStartValue) + ); + + KeyFrame k2 = new KeyFrame( + duration, + event -> { + pane.setCache(false); + pane.fireEvent(new Event(ON_SHOWN)); + }, + new KeyValue(transition, 1, Interpolator.EASE_OUT) + ); + + timeline.getKeyFrames().setAll(k1, k2); + timeline.play(); + } +} diff --git a/jfoenix/src/main/resources/css/controls/jfx-notification.css b/jfoenix/src/main/resources/css/controls/jfx-notification.css new file mode 100644 index 000000000..18828462b --- /dev/null +++ b/jfoenix/src/main/resources/css/controls/jfx-notification.css @@ -0,0 +1,70 @@ +.jfx-notification-bar { + -fx-background-color: TRANSPARENT; +} + +.jfx-notification-bar > .pane { + -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.5), 11, 0.0, 0, 3); + -fx-background-insets: 0; + -fx-padding: 0; + -fx-background-color: transparent; +} + +.jfx-notification-bar > .pane > .viewport { + -fx-background-color: TRANSPARENT; +} + +.jfx-notification-template { + -fx-background-color: WHITE; + -fx-background-radius: 5; + -fx-border-radius: 5; + -fx-padding: 18 20 10 20; + -fx-spacing: 15; + -fx-pref-width: 380; +} + +.jfx-notification-template .jfx-notification-header { + -fx-alignment: center-left; + -fx-spacing: 8; +} + +.jfx-notification-template .jfx-notification-header .label-header { + -fx-text-fill: #757575; + -fx-font-size: 15; + -fx-font-family: "Roboto Medium"; +} + +.jfx-notification-template .jfx-notification-header .jfx-rippler { + -jfx-rippler-fill: WHITE; + -fx-cursor: hand; +} + +.jfx-notification-template .jfx-notification-header .jfx-rippler .box-close { + -fx-alignment: center; +} + +.jfx-notification-template .jfx-notification-header .jfx-rippler .box-close > .graphic { + -fx-background-color: #424242; + -fx-scale-shape: false; + -fx-padding: 4.5 4.5 4.5 4.5; +} + +.jfx-notification-template .jfx-notification-header .jfx-rippler .box-close > .graphic { + -fx-shape: "M395.992,296.758l1.794-1.794l7.292,7.292l-1.795,1.794 L395.992,296.758z M403.256,294.992l1.794,1.794l-7.292,7.292l-1.794-1.795 L403.256,294.992z"; +} + +.jfx-notification-template .jfx-notification-body .simple-body { + -fx-spacing: 5; +} + +.jfx-notification-template .jfx-notification-body .label-sub-title { + -fx-text-fill: #424242; + -fx-font-size: 16; + -fx-font-family: "Roboto Bold"; + -fx-wrap-text: true; +} + +.jfx-notification-template .jfx-notification-body .label-message { + -fx-text-fill: #616161; + -fx-font-size: 14; + -fx-font-family: "Roboto Medium"; +}