Skip to content

Commit

Permalink
Add Notify notifier
Browse files Browse the repository at this point in the history
https://github.com/dorkbox/Notify

Use:
    notifier.implementation = notify
    notifier.notify.position = CENTER (TOP_RIGHT by default)
    notifier.notify.darkstyle = true (false by default)
  • Loading branch information
jcgay committed May 7, 2017
1 parent 82bcb55 commit f6c190d
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Go to [Wiki](https://github.com/jcgay/send-notification/wiki) to read full confi
| **[notifu](http://www.paralint.com/projects/notifu/index.html)** for Windows | ![notifu](http://jeanchristophegay.com/images/notifier.notifu.png) |
| **AnyBar** for [OS X](https://github.com/tonsky/AnyBar) and [Linux](https://github.com/limpbrains/somebar) | ![anybar](http://jeanchristophegay.com/images/notifier.anybar_maven.png) |
| **[Toaster](https://github.com/nels-o/toaster)** for Windows 8 | ![toaster](http://jeanchristophegay.com/images/notifier.toaster.png) |
| **[Notify](https://github.com/dorkbox/Notify)** since Java 6 | ![Notify](http://jeanchristophegay.com/images/notifier.notify.png) |

# Build status

Expand Down
5 changes: 5 additions & 0 deletions send-notification/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>com.dorkbox</groupId>
<artifactId>Notify</artifactId>
<version>2.20</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.google.common.io.Closeables;

import javax.imageio.ImageIO;
import java.awt.image.RenderedImage;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -33,7 +33,7 @@ public abstract class Icon {
*/
public abstract URL content();

public RenderedImage toRenderedImage() {
public BufferedImage toImage() {
try {
return ImageIO.read(content());
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import fr.jcgay.notification.notifier.notificationcenter.TerminalNotifierConfiguration;
import fr.jcgay.notification.notifier.notifu.NotifuConfiguration;
import fr.jcgay.notification.notifier.notifu.NotifuNotifier;
import fr.jcgay.notification.notifier.notify.NotifyConfiguration;
import fr.jcgay.notification.notifier.notify.NotifyNotifier;
import fr.jcgay.notification.notifier.notifysend.NotifySendConfiguration;
import fr.jcgay.notification.notifier.notifysend.NotifySendNotifier;
import fr.jcgay.notification.notifier.pushbullet.PushbulletConfiguration;
Expand Down Expand Up @@ -47,6 +49,7 @@ class NotifierProvider {
private static final ChosenNotifiers ANYBAR = ChosenNotifiers.from("anybar");
private static final ChosenNotifiers SIMPLE_NOTIFICATION_CENTER = ChosenNotifiers.from("simplenc");
private static final ChosenNotifiers TOASTER = ChosenNotifiers.from("toaster");
private static final ChosenNotifiers NOTIFY = ChosenNotifiers.from("notify");

private final RuntimeExecutor executor = new RuntimeExecutor();
private final OperatingSystem os;
Expand Down Expand Up @@ -102,6 +105,9 @@ public DiscoverableNotifier byName(ChosenNotifiers notifier, Properties properti
if (TOASTER.equals(notifier)) {
return new ToasterNotifier(ToasterConfiguration.create(properties), executor);
}
if (NOTIFY.equals(notifier)) {
return new NotifyNotifier(application, NotifyConfiguration.create(properties));
}

return DoNothingNotifier.doNothing();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public Notifier init() {

GntpApplicationInfo gApplication = Gntp.appInfo(application.name()).build();
gNotification = Gntp.notificationInfo(gApplication, application.id())
.icon(application.icon().toRenderedImage())
.icon(application.icon().toImage())
.build();
Gntp clientBuilder = Gntp.client(gApplication)
.onPort(configuration.port())
Expand All @@ -72,7 +72,7 @@ public void send(Notification notification) {
if (isClientRegistered()) {
GntpNotification success = Gntp.notification(gNotification, notification.title())
.text(notification.message())
.icon(notification.icon().toRenderedImage())
.icon(notification.icon().toImage())
.priority(toPriority(notification.level()))
.build();
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package fr.jcgay.notification.notifier.notify;

import com.google.auto.value.AutoValue;
import dorkbox.notify.Pos;

import java.util.Properties;

@AutoValue
public abstract class NotifyConfiguration {

private static final NotifyConfiguration DEFAULT = new AutoValue_NotifyConfiguration(Pos.TOP_RIGHT, false);

public abstract Pos position();

public abstract boolean withDarkStyle();

NotifyConfiguration() {
// prevent external subclasses
}

public static NotifyConfiguration byDefault() {
return DEFAULT;
}

public static NotifyConfiguration create(Properties properties) {
if (properties == null) {
return byDefault();
}

return new AutoValue_NotifyConfiguration(
Pos.valueOf(properties.getProperty("notifier.notify.position", DEFAULT.position().name())),
Boolean.valueOf(properties.getProperty("notifier.notify.darkstyle", String.valueOf(DEFAULT.withDarkStyle())))
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package fr.jcgay.notification.notifier.notify;

import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import dorkbox.notify.Notify;
import fr.jcgay.notification.Application;
import fr.jcgay.notification.DiscoverableNotifier;
import fr.jcgay.notification.Notification;
import fr.jcgay.notification.Notifier;
import org.slf4j.Logger;

import static java.util.concurrent.TimeUnit.SECONDS;
import static org.slf4j.LoggerFactory.getLogger;

public class NotifyNotifier implements DiscoverableNotifier {

private static final Logger LOGGER = getLogger(NotifyNotifier.class);

private final Application application;
private final NotifyConfiguration configuration;

private boolean skipNotifications;

public NotifyNotifier(Application application, NotifyConfiguration configuration) {
LOGGER.debug("Configuring notify: {}.", configuration);
this.configuration = configuration;
this.application = application;
}

@Override
public Notifier init() {
if (isHeadless()) {
skipNotifications = true;
}
return this;
}

@Override
public boolean tryInit() {
init();
return !skipNotifications;
}

@Override
public void send(Notification notification) {
Notify notify = Notify.create()
.title(notification.title())
.text(notification.message())
.graphic(notification.icon().toImage())
.position(configuration.position())
.hideAfter((int) (application.timeout() == -1 ? SECONDS.toMillis(3) : application.timeout()));

if (configuration.withDarkStyle()) {
notify.darkStyle();
}

notify.show();
}

@Override
public void close() {
if (!skipNotifications) {
try {
Thread.sleep(application.timeout() == -1 ? SECONDS.toMillis(3) : application.timeout());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}

private static boolean isHeadless() {
return "true".equals(System.getProperty("java.awt.headless"));
}

@Override
public boolean isPersistent() {
return false;
}

@Override
public int hashCode() {
return Objects.hashCode(application, configuration, skipNotifications);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final NotifyNotifier other = (NotifyNotifier) obj;
return Objects.equal(this.application, other.application)
&& Objects.equal(this.configuration, other.configuration)
&& Objects.equal(this.skipNotifications, other.skipNotifications);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("application", application)
.add("configuration", configuration)
.add("skipNotifications", skipNotifications)
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package fr.jcgay.notification.notifier.notify

import spock.lang.Specification
import spock.lang.Unroll

import static dorkbox.notify.Pos.*

class NotifyConfigurationSpec extends Specification {

@Unroll
def "should build default configuration when properties are [#empty]"() {
when:
def result = NotifyConfiguration.create(empty)

then:
result == NotifyConfiguration.byDefault()

where:
empty << [null, new Properties()]
}

@Unroll
def "should build user configuration with position [#position]"() {
when:
def result = NotifyConfiguration.create(
['notifier.notify.position': position.name()] as Properties
)

then:
result.position() == position
result.withDarkStyle() == NotifyConfiguration.byDefault().withDarkStyle()

where:
position << [TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, CENTER]
}

@Unroll
def "should build user configuration with dark style ? [#style]"() {
when:
def result = NotifyConfiguration.create(
['notifier.notify.darkstyle': style as String] as Properties
)

then:
result.position() == NotifyConfiguration.byDefault().position()
result.withDarkStyle() == style

where:
style << [true, false]
}

def "fail when position is not valid"() {
when:
NotifyConfiguration.create(
['notifier.notify.position': 'unknown'] as Properties
)

then:
thrown(IllegalArgumentException)
}

def "get lighter style when darkstyle is not a boolean"() {
when:
def result = NotifyConfiguration.create(
['notifier.notify.darkstyle': 'maybe'] as Properties
)

then:
!result.withDarkStyle()
}
}
34 changes: 34 additions & 0 deletions send-notification/src/test/java/NotifyExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fr.jcgay.notification.Application;
import fr.jcgay.notification.Icon;
import fr.jcgay.notification.Notification;
import fr.jcgay.notification.Notifier;
import fr.jcgay.notification.SendNotification;

import java.net.URL;

public class NotifyExample {

public static void main(String[] args) {
URL icon = SystemTrayExample.class.getResource("/image/dialog-clean.png");

Application application = Application.builder()
.id("notify-example")
.name("Notify Example")
.icon(Icon.create(icon, "app"))
.build();

Notifier notifier = new SendNotification()
.setApplication(application)
.setChosenNotifier("notify")
.initNotifier();

Notification notification = Notification.builder()
.title("Notify Notification")
.message("Hello !")
.icon(Icon.create(icon, "ok"))
.build();

notifier.send(notification);
notifier.close();
}
}

0 comments on commit f6c190d

Please sign in to comment.