diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml
index 81ae2f0293..d8876570ee 100644
--- a/runelite-client/pom.xml
+++ b/runelite-client/pom.xml
@@ -267,6 +267,7 @@
ttf
png
gif
+ wav
diff --git a/runelite-client/src/main/java/net/runelite/client/Notifier.java b/runelite-client/src/main/java/net/runelite/client/Notifier.java
index 4f9653ed86..83cf8c0a3b 100644
--- a/runelite-client/src/main/java/net/runelite/client/Notifier.java
+++ b/runelite-client/src/main/java/net/runelite/client/Notifier.java
@@ -33,6 +33,9 @@ import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.TrayIcon;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
@@ -43,6 +46,13 @@ import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Singleton;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
@@ -61,6 +71,23 @@ import net.runelite.client.util.OSType;
@Slf4j
public class Notifier
{
+ @Getter
+ @RequiredArgsConstructor
+ public enum NativeCustomOff
+ {
+ NATIVE("Native"),
+ CUSTOM("Custom"),
+ OFF("Off");
+
+ private final String name;
+
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+ }
+
// Default timeout of notification in milliseconds
private static final int DEFAULT_TIMEOUT = 10000;
private static final String DOUBLE_QUOTE = "\"";
@@ -130,9 +157,13 @@ public class Notifier
sendNotification(appName, message, type);
}
- if (runeLiteConfig.enableNotificationSound())
+ switch (runeLiteConfig.notificationSound())
{
- Toolkit.getDefaultToolkit().beep();
+ case NATIVE:
+ Toolkit.getDefaultToolkit().beep();
+ break;
+ case CUSTOM:
+ executorService.submit(this::playCustomSound);
}
if (runeLiteConfig.enableGameMessageNotification() && client.getGameState() == GameState.LOGGED_IN)
@@ -369,4 +400,48 @@ public class Notifier
return "normal";
}
}
+
+ private void playCustomSound()
+ {
+ Clip clip = null;
+
+ // Try to load the user sound from ~/.runelite/notification.wav
+ File file = new File(RuneLite.RUNELITE_DIR, "notification.wav");
+ if (file.exists())
+ {
+ try
+ {
+ InputStream fileStream = new BufferedInputStream(new FileInputStream(file));
+ try (AudioInputStream sound = AudioSystem.getAudioInputStream(fileStream))
+ {
+ clip = AudioSystem.getClip();
+ clip.open(sound);
+ }
+ }
+ catch (UnsupportedAudioFileException | IOException | LineUnavailableException e)
+ {
+ clip = null;
+ log.warn("Unable to play notification sound", e);
+ }
+ }
+
+ if (clip == null)
+ {
+ // Otherwise load from the classpath
+ InputStream fileStream = new BufferedInputStream(Notifier.class.getResourceAsStream("notification.wav"));
+ try (AudioInputStream sound = AudioSystem.getAudioInputStream(fileStream))
+ {
+ clip = AudioSystem.getClip();
+ clip.open(sound);
+ }
+ catch (UnsupportedAudioFileException | IOException | LineUnavailableException e)
+ {
+ log.warn("Unable to play builtin notification sound", e);
+
+ Toolkit.getDefaultToolkit().beep();
+ return;
+ }
+ }
+ clip.start();
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java
index 2c4cf3597a..287e0468b2 100644
--- a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java
@@ -26,6 +26,7 @@ package net.runelite.client.config;
import java.awt.Dimension;
import net.runelite.api.Constants;
+import net.runelite.client.Notifier;
import net.runelite.client.ui.ContainableFrame;
@ConfigGroup("runelite")
@@ -155,13 +156,13 @@ public interface RuneLiteConfig extends Config
@ConfigItem(
keyName = "notificationSound",
- name = "Enable sound on notifications",
+ name = "Notification sound",
description = "Enables the playing of a beep sound when notifications are displayed",
position = 22
)
- default boolean enableNotificationSound()
+ default Notifier.NativeCustomOff notificationSound()
{
- return true;
+ return Notifier.NativeCustomOff.NATIVE;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java
index c33753d4a3..a888df3334 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java
@@ -26,28 +26,33 @@
package net.runelite.client.plugins.devtools;
import java.awt.GridLayout;
+import java.awt.TrayIcon;
import javax.inject.Inject;
+import javax.swing.JButton;
import javax.swing.JPanel;
import net.runelite.api.Client;
+import net.runelite.client.Notifier;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.PluginPanel;
class DevToolsPanel extends PluginPanel
{
private final Client client;
+ private final Notifier notifier;
private final DevToolsPlugin plugin;
private final WidgetInspector widgetInspector;
private final VarInspector varInspector;
@Inject
- private DevToolsPanel(Client client, DevToolsPlugin plugin, WidgetInspector widgetInspector, VarInspector varInspector)
+ private DevToolsPanel(Client client, DevToolsPlugin plugin, WidgetInspector widgetInspector, VarInspector varInspector, Notifier notifier)
{
super();
this.client = client;
this.plugin = plugin;
this.widgetInspector = widgetInspector;
this.varInspector = varInspector;
+ this.notifier = notifier;
setBackground(ColorScheme.DARK_GRAY_COLOR);
@@ -121,6 +126,13 @@ class DevToolsPanel extends PluginPanel
container.add(plugin.getSoundEffects());
+ final JButton notificationBtn = new JButton("Notification");
+ notificationBtn.addActionListener(e ->
+ {
+ notifier.notify("Wow!", TrayIcon.MessageType.ERROR);
+ });
+ container.add(notificationBtn);
+
return container;
}
}
diff --git a/runelite-client/src/main/resources/net/runelite/client/notification.txt b/runelite-client/src/main/resources/net/runelite/client/notification.txt
new file mode 100644
index 0000000000..e3a7245c61
--- /dev/null
+++ b/runelite-client/src/main/resources/net/runelite/client/notification.txt
@@ -0,0 +1,2 @@
+Notification is cloud from
+https://github.com/akx/Notifications
\ No newline at end of file
diff --git a/runelite-client/src/main/resources/net/runelite/client/notification.wav b/runelite-client/src/main/resources/net/runelite/client/notification.wav
new file mode 100644
index 0000000000..60321281c3
Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/notification.wav differ