WIP - changed name to Notify. Moved package out of util. Added Notify.getVersion().

This commit is contained in:
nathan 2016-02-11 01:14:23 +01:00
parent 70411c4440
commit 1ecd9316e7
22 changed files with 164 additions and 128 deletions

View File

@ -1,9 +1,9 @@
Growl
=====
Notify
======
Cross platform notification popups, similar to "Growl" on OSX, "Toasts" on Windows, and Notifications on Ubuntu.
Cross platform notification popups, similar to "Growl" on OSX, "Toasts" on Windows, and "Notifications" on Ubuntu.
This small library is displays notifications on any screen, in any corner, using swing.
This small library is displays notifications on any screen, in any corner.
Primary Features:
@ -11,12 +11,12 @@ Primary Features:
2. Can specify which corner, center is also possible
3. If no location is specified, it will show on whatever screen the mouse is on.
4. Duration timeouts, with progress indicator on notification
5. Light or Dark styles
5. Light or Dark themes
6. Can close via close button or clicking on notification body
7. Can show/hide the close button
8. Can register a callback for when a user clicks on the notification body
9. Animates to a collated position if multiple notifications are in the same position
10. Bypasses the EDT, and now renders at a beautiful 30 frames-per-second.
10. Bypasses the swing EDT, and now renders at a beautiful 30 frames-per-second.
- This is for cross-platform use, specifically - linux 32/64, mac 32/64, and windows 32/64. Java 6+
@ -32,13 +32,31 @@ Customization parameters:
- By default, the timer resolution in some operating systems are not particularly high-resolution (ie: 'Thread.sleep(1)' will not really
sleep for 1ms, but will really sleep for 16ms). This forces the JVM to use high resolution timers.
Growl.IMAGE_PATH (type String, default value 'resources')
Notify.IMAGE_PATH (type String, default value 'resources')
- Location of the dialog image resources. By default they must be in the 'resources' directory relative to the application
```
![growl-light image](https://raw.githubusercontent.com/dorkbox/Growl/master/growl-light.png)
![light theme](https://raw.githubusercontent.com/dorkbox/Notify/master/notify-light.png)
![growl-dark image](https://raw.githubusercontent.com/dorkbox/Growl/master/growl-dark.png)
![dark theme](https://raw.githubusercontent.com/dorkbox/Notify/master/notify-dark.png)
<h4>We now release to maven!</h4>
There is a hard dependency in the POM file for the utilities library, which is an extremely small subset of a much larger library; including only what is *necessary* for this particular project to function.
This project is **kept in sync** with the utilities library, so "jar hell" is not an issue. Please note that the util library (in it's entirety) is not added since there are **many** dependencies that are not *necessary* for this project. No reason to require a massive amount of dependencies for one or two classes/methods.
```
<dependency>
<groupId>com.dorkbox</groupId>
<artifactId>Notify</artifactId>
<version>2.0</version>
</dependency>
```
Or if you don't want to use Maven, you can access the files directly here:
https://oss.sonatype.org/content/repositories/releases/com/dorkbox/Notify/
https://oss.sonatype.org/content/repositories/releases/com/dorkbox/Notify-Dorkbox-Util/
<h2>License</h2>

BIN
dist/Growl_v1.1.jar vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.growl;
package dorkbox.notify;
import dorkbox.util.ActionHandler;
import dorkbox.util.LocationResolver;
@ -37,7 +37,7 @@ import java.util.Map;
* <p>
* <pre>
* {@code
* Growl.create()
* Notify.create()
* .title("Title Text")
* .text("Hello World 0!")
* .useDarkStyle()
@ -45,9 +45,8 @@ import java.util.Map;
* }
* </pre>
*/
@SuppressWarnings("unused")
public final
class Growl {
class Notify {
/**
* Location of the dialog image resources. By default they must be in the 'resources' directory relative to the application
@ -57,12 +56,20 @@ class Growl {
private static Map<String, BufferedImage> imageCache = new HashMap<String, BufferedImage>(4);
private static Map<String, ImageIcon> imageIconCache = new HashMap<String, ImageIcon>(4);
/**
* Gets the version number.
*/
public static
String getVersion() {
return "1.1";
}
/**
* Builder pattern to create the growl notification.
*/
public static
Growl create() {
return new Growl();
Notify create() {
return new Notify();
}
/**
@ -122,21 +129,21 @@ class Growl {
boolean isDark = false;
int screenNumber = Short.MIN_VALUE;
private Image graphic;
private ActionHandler<Growl> onAction;
private GrowlPopup growlPopup;
private ActionHandler<Notify> onAction;
private NotifyPopup notifyPopup;
private String name;
private int shakeDurationInMillis = 0;
private int shakeAmplitude = 0;
private
Growl() {
Notify() {
}
/**
* Specifies the main text
*/
public
Growl text(String text) {
Notify text(String text) {
this.text = text;
return this;
}
@ -145,7 +152,7 @@ class Growl {
* Specifies the title
*/
public
Growl title(String title) {
Notify title(String title) {
this.title = title;
return this;
}
@ -154,7 +161,7 @@ class Growl {
* Specifies the graphic
*/
public
Growl graphic(Image graphic) {
Notify graphic(Image graphic) {
this.graphic = graphic;
return this;
}
@ -163,7 +170,7 @@ class Growl {
* Specifies the position of the notification on screen, by default it is {@link Pos#BOTTOM_RIGHT bottom-right}.
*/
public
Growl position(Pos position) {
Notify position(Pos position) {
this.position = position;
return this;
}
@ -173,7 +180,7 @@ class Growl {
* will show forever
*/
public
Growl hideAfter(int durationInMillis) {
Notify hideAfter(int durationInMillis) {
if (durationInMillis < 0) {
durationInMillis = 0;
}
@ -186,7 +193,7 @@ class Growl {
* notification is clicked on). This does not apply when clicking on the "close" button
*/
public
Growl onAction(ActionHandler<Growl> onAction) {
Notify onAction(ActionHandler<Notify> onAction) {
this.onAction = onAction;
return this;
}
@ -195,7 +202,7 @@ class Growl {
* Specifies that the notification should use the built-in dark styling, rather than the default, light-gray notification style.
*/
public
Growl darkStyle() {
Notify darkStyle() {
isDark = true;
return this;
}
@ -204,7 +211,7 @@ class Growl {
* Specify that the close button in the top-right corner of the notification should not be shown.
*/
public
Growl hideCloseButton() {
Notify hideCloseButton() {
this.hideCloseButton = true;
return this;
}
@ -260,11 +267,11 @@ class Growl {
@Override
public
void run() {
final Growl growl = Growl.this;
final Image graphic = growl.graphic;
final Notify notify = Notify.this;
final Image graphic = notify.graphic;
if (graphic == null) {
growlPopup = new GrowlPopup(growl, null, null);
notifyPopup = new NotifyPopup(notify, null, null);
}
else {
// we ONLY cache our own icons
@ -280,13 +287,13 @@ class Growl {
imageIcon = new ImageIcon(graphic);
}
growlPopup = new GrowlPopup(growl, graphic, imageIcon);
notifyPopup = new NotifyPopup(notify, graphic, imageIcon);
}
growlPopup.setVisible(true);
notifyPopup.setVisible(true);
if (shakeDurationInMillis > 0) {
growlPopup.shake(growl.shakeDurationInMillis, growl.shakeAmplitude);
notifyPopup.shake(notify.shakeDurationInMillis, notify.shakeAmplitude);
}
}
});
@ -299,18 +306,18 @@ class Growl {
* @param amplitude a measure of how much it needs to shake. 4 is a small amount of shaking, 10 is a lot.
*/
public
Growl shake(final int durationInMillis, final int amplitude) {
Notify shake(final int durationInMillis, final int amplitude) {
this.shakeDurationInMillis = durationInMillis;
this.shakeAmplitude = amplitude;
if (growlPopup != null) {
if (notifyPopup != null) {
// must be done in the swing EDT
//noinspection Convert2Lambda
SwingUtil.invokeLater(new Runnable() {
@Override
public
void run() {
growlPopup.shake(durationInMillis, amplitude);
notifyPopup.shake(durationInMillis, amplitude);
}
});
}
@ -323,8 +330,8 @@ class Growl {
*/
public
void close() {
if (growlPopup == null) {
throw new NullPointerException("GrowlPopup");
if (notifyPopup == null) {
throw new NullPointerException("NotifyPopup");
}
// must be done in the swing EDT
@ -333,7 +340,7 @@ class Growl {
@Override
public
void run() {
growlPopup.close();
notifyPopup.close();
}
});
}
@ -342,7 +349,7 @@ class Growl {
* Specifies which screen to display on. If <0, it will show on screen 0. If > max-screens, it will show on the last screen.
*/
public
Growl setScreen(final int screenNumber) {
Notify setScreen(final int screenNumber) {
this.screenNumber = screenNumber;
return this;
}
@ -352,7 +359,7 @@ class Growl {
}
void onClose() {
growlPopup = null;
notifyPopup = null;
graphic = null;
}
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.growl;
package dorkbox.notify;
import dorkbox.util.ActionHandlerLong;
import dorkbox.util.OS;
@ -21,11 +21,11 @@ import dorkbox.util.Property;
import dorkbox.util.ScreenUtil;
import dorkbox.util.SwingUtil;
import dorkbox.util.swing.SwingActiveRender;
import dorkbox.util.tweenengine.BaseTween;
import dorkbox.util.tweenengine.Tween;
import dorkbox.util.tweenengine.TweenCallback;
import dorkbox.util.tweenengine.TweenEquations;
import dorkbox.util.tweenengine.TweenManager;
import dorkbox.tweenengine.BaseTween;
import dorkbox.tweenengine.Tween;
import dorkbox.tweenengine.TweenCallback;
import dorkbox.tweenengine.TweenEquations;
import dorkbox.tweenengine.TweenManager;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
@ -44,14 +44,15 @@ import java.util.Random;
// instead, we just create a JFrame and use it to hold our content
@SuppressWarnings({"Duplicates", "FieldCanBeLocal"})
public
class GrowlPopup extends JFrame {
class NotifyPopup extends JFrame {
private static final long serialVersionUID = 1L;
@Property
/** title font used by growl */
/** title font used by Notify */
public static String TITLE_TEXT_FONT = "Source Code Pro BOLD 16";
@Property
/** main text font used by growl */
/** main text font used by Notify */
public static String MAIN_TEXT_FONT = "Source Code Pro BOLD 12";
@Property
@ -60,9 +61,9 @@ class GrowlPopup extends JFrame {
private static final int padding = 40;
private static final Map<String, ArrayList<GrowlPopup>> popups = new HashMap<String, ArrayList<GrowlPopup>>();
private static final Map<String, ArrayList<NotifyPopup>> popups = new HashMap<String, ArrayList<NotifyPopup>>();
private static final GrowlPopupAccessor accessor = new GrowlPopupAccessor();
private static final NotifyPopupAccessor accessor = new NotifyPopupAccessor();
private static final TweenManager tweenManager = new TweenManager();
private static ActionHandlerLong frameStartHandler;
@ -74,7 +75,7 @@ class GrowlPopup extends JFrame {
@Override
public
void handle(final long deltaInNanos) {
GrowlPopup.tweenManager.update(deltaInNanos);
NotifyPopup.tweenManager.update(deltaInNanos);
}
};
@ -111,7 +112,7 @@ class GrowlPopup extends JFrame {
private final WindowAdapter windowListener;
private final MouseAdapter mouseListener;
private final Growl notification;
private final Notify notification;
private final ImageIcon imageIcon;
// this is used in combination with position, so that we can track which screen and what position a popup is in
@ -134,12 +135,12 @@ class GrowlPopup extends JFrame {
// this is on the swing EDT
@SuppressWarnings("NumericCastThatLosesPrecision")
GrowlPopup(Growl notification, Image image, ImageIcon imageIcon) {
NotifyPopup(Notify notification, Image image, ImageIcon imageIcon) {
this.notification = notification;
this.imageIcon = imageIcon;
windowListener = new GrowlPopupWindowAdapter();
mouseListener = new GrowlPopupClickAdapter();
windowListener = new NotifyPopupWindowAdapter();
mouseListener = new NotifyPopupClickAdapter();
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setUndecorated(true);
@ -433,12 +434,12 @@ class GrowlPopup extends JFrame {
Pos position = notification.position;
synchronized (popups) {
ArrayList<GrowlPopup> growlPopups = popups.get(idAndPosition);
if (growlPopups == null) {
growlPopups = new ArrayList<GrowlPopup>(4);
popups.put(idAndPosition, growlPopups);
ArrayList<NotifyPopup> notifyPopups = popups.get(idAndPosition);
if (notifyPopups == null) {
notifyPopups = new ArrayList<NotifyPopup>(4);
popups.put(idAndPosition, notifyPopups);
}
final int popupIndex = growlPopups.size();
final int popupIndex = notifyPopups.size();
this.popupIndex = popupIndex;
// the popups are ALL the same size!
@ -452,14 +453,14 @@ class GrowlPopup extends JFrame {
targetY = anchorY - (popupIndex * (HEIGHT + 10));
}
growlPopups.add(this);
notifyPopups.add(this);
setLocation(anchorX, targetY);
if (notification.hideAfterDurationInMillis > 0 && hideTween == null) {
// begin a timeline to get rid of the popup (default is 5 seconds)
final float durationInSeconds = notification.hideAfterDurationInMillis / 1000.0F;
hideTween = Tween.to(this, GrowlPopupAccessor.PROGRESS, accessor, durationInSeconds)
hideTween = Tween.to(this, NotifyPopupAccessor.PROGRESS, accessor, durationInSeconds)
.target(WIDTH)
.ease(TweenEquations.Linear)
.addCallback(new TweenCallback() {
@ -488,14 +489,14 @@ class GrowlPopup extends JFrame {
synchronized (popups) {
final int popupIndex = this.popupIndex;
final ArrayList<GrowlPopup> growlPopups = popups.get(idAndPosition);
int length = growlPopups.size();
final ArrayList<NotifyPopup> notifyPopups = popups.get(idAndPosition);
int length = notifyPopups.size();
final ArrayList<GrowlPopup> copies = new ArrayList<GrowlPopup>(length);
final ArrayList<NotifyPopup> copies = new ArrayList<NotifyPopup>(length);
// if we are the LAST tween, don't adjust anything (since nothing will move anyways)
if (popupIndex == length - 1) {
growlPopups.remove(popupIndex);
notifyPopups.remove(popupIndex);
if (tween != null) {
tween.kill();
@ -514,7 +515,7 @@ class GrowlPopup extends JFrame {
int adjustedI = 0;
for (int i = 0; i < length; i++) {
final GrowlPopup popup = growlPopups.get(i);
final NotifyPopup popup = notifyPopups.get(i);
if (popup.tween != null) {
popup.tween.kill();
@ -537,7 +538,7 @@ class GrowlPopup extends JFrame {
copies.add(popup);
// now animate that popup to it's new location
Tween tween = Tween.to(popup, GrowlPopupAccessor.Y_POS, accessor, MOVE_DURATION)
Tween tween = Tween.to(popup, NotifyPopupAccessor.Y_POS, accessor, MOVE_DURATION)
.target((float) changedY)
.ease(TweenEquations.Linear);
@ -551,7 +552,7 @@ class GrowlPopup extends JFrame {
}
}
growlPopups.clear();
notifyPopups.clear();
popups.put(idAndPosition, copies);
// if there's nothing left, stop the timer.
@ -615,7 +616,7 @@ class GrowlPopup extends JFrame {
count++;
}
Tween tween = Tween.to(this, GrowlPopupAccessor.X_Y_POS, accessor, 0.05F)
Tween tween = Tween.to(this, NotifyPopupAccessor.X_Y_POS, accessor, 0.05F)
.targetRelative(i1, i2)
.repeatAutoReverse(count, 0)
.ease(TweenEquations.Linear);

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.growl;
package dorkbox.notify;
import dorkbox.util.tweenengine.TweenAccessor;
import dorkbox.tweenengine.TweenAccessor;
class GrowlPopupAccessor implements TweenAccessor<GrowlPopup> {
class NotifyPopupAccessor implements TweenAccessor<NotifyPopup> {
static final int OPACITY = 0;
static final int Y_POS = 1;
@ -25,12 +25,12 @@ class GrowlPopupAccessor implements TweenAccessor<GrowlPopup> {
static final int PROGRESS = 3;
GrowlPopupAccessor() {
NotifyPopupAccessor() {
}
@Override
public
int getValues(final GrowlPopup target, final int tweenType, final float[] returnValues) {
int getValues(final NotifyPopup target, final int tweenType, final float[] returnValues) {
switch (tweenType) {
case OPACITY:
returnValues[0] = target.getOpacity_Compat();
@ -52,7 +52,7 @@ class GrowlPopupAccessor implements TweenAccessor<GrowlPopup> {
@SuppressWarnings({"NumericCastThatLosesPrecision", "UnnecessaryReturnStatement"})
@Override
public
void setValues(final GrowlPopup target, final int tweenType, final float[] newValues) {
void setValues(final NotifyPopup target, final int tweenType, final float[] newValues) {
switch (tweenType) {
case OPACITY:
target.setOpacity_Compat(newValues[0]);

View File

@ -13,21 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.growl;
package dorkbox.notify;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
class GrowlPopupClickAdapter extends MouseAdapter {
class NotifyPopupClickAdapter extends MouseAdapter {
public
GrowlPopupClickAdapter() {
NotifyPopupClickAdapter() {
}
@Override
public
void mouseReleased(final MouseEvent e) {
GrowlPopup source = (GrowlPopup) e.getSource();
NotifyPopup source = (NotifyPopup) e.getSource();
source.onClick(e.getX(), e.getY());
}
}

View File

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.growl;
package dorkbox.notify;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
class GrowlPopupWindowAdapter extends WindowAdapter {
class NotifyPopupWindowAdapter extends WindowAdapter {
public
void windowLostFocus(WindowEvent e) {
if (e.getNewState() != WindowEvent.WINDOW_CLOSED) {
GrowlPopup source = (GrowlPopup) e.getSource();
NotifyPopup source = (NotifyPopup) e.getSource();
//toFront();
//requestFocus();
source.setAlwaysOnTop(false);

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.growl;
package dorkbox.notify;
public
enum Pos {

View File

@ -1,4 +1,4 @@
package dorkbox.util.growl;
package dorkbox.notify;
import java.awt.Window;

View File

@ -1,4 +1,4 @@
package dorkbox.util.growl;
package dorkbox.notify;
import com.sun.awt.AWTUtilities;

View File

@ -1,4 +1,4 @@
package dorkbox.util.growl;
package dorkbox.notify;
import java.awt.Window;

View File

@ -1,40 +0,0 @@
import dorkbox.util.ActionHandler;
import dorkbox.util.growl.Growl;
import dorkbox.util.growl.Pos;
/**
*
*/
public
class GrowlTest {
public static
void main(String[] args) {
Growl growl;
int count = 3;
for (int i = 0; i < count; i++) {
growl = Growl.create()
.title("Growl title " + i)
.text("This is a growl notification popup message This is a growl notification popup message This is a growl notification popup message")
.hideAfter(50000)
.position(Pos.TOP_RIGHT)
// .setScreen(0)
.darkStyle()
.shake(1300, 4)
// .shake(1300, 10)
// .hideCloseButton()
.onAction(new ActionHandler<Growl>() {
@Override
public
void handle(final Growl arg0) {
System.out.println("Notification clicked on!");
}
});
growl.showWarning();
// growl.show();
}
}
}

50
test/NotifyTest.java Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright 2015 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import dorkbox.util.ActionHandler;
import dorkbox.notify.Notify;
import dorkbox.notify.Pos;
public
class NotifyTest {
public static
void main(String[] args) {
Notify notify;
int count = 3;
for (int i = 0; i < count; i++) {
notify = Notify.create()
.title("Notify title " + i)
.text("This is a notification popup message This is a notification popup message This is a notification popup message")
.hideAfter(50000)
.position(Pos.TOP_RIGHT)
// .setScreen(0)
.darkStyle()
.shake(1300, 4)
// .shake(1300, 10)
// .hideCloseButton()
.onAction(new ActionHandler<Notify>() {
@Override
public
void handle(final Notify arg0) {
System.out.println("Notification clicked on!");
}
});
notify.showWarning();
}
}
}