From 5904f3d9242f069f9015419bf11a28d4253ecc75 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Mon, 30 Apr 2018 15:02:15 +0200 Subject: [PATCH] Add 2 new notifications modes (message, flash) - Change the notification mode selection to be dropdown - Add chat message notification mode that will send game message on notificiation - Add screen flash notification that will flash screen for few ticks Signed-off-by: Tomas Slusny --- .../java/net/runelite/client/Notifier.java | 89 +++++++++++++++++-- .../net/runelite/client/callback/Hooks.java | 4 + .../client/config/RuneLiteConfig.java | 36 +++----- 3 files changed, 98 insertions(+), 31 deletions(-) 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 5fa9ca3516..bd2ed482a4 100644 --- a/runelite-client/src/main/java/net/runelite/client/Notifier.java +++ b/runelite-client/src/main/java/net/runelite/client/Notifier.java @@ -27,19 +27,28 @@ package net.runelite.client; import com.google.common.escape.Escaper; import com.google.common.escape.Escapers; import com.google.inject.Inject; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.TrayIcon; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.ScheduledExecutorService; import javax.inject.Provider; import javax.inject.Singleton; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameState; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.ui.ClientUI; import net.runelite.client.util.OSType; @@ -48,6 +57,25 @@ import net.runelite.client.util.OSType; @Slf4j public class Notifier { + @Getter + @RequiredArgsConstructor + public enum NotificationMode + { + TRAY("System tray"), + BEEP("System beep"), + MESSAGE("Game message"), + FLASH("Screen flash"), + 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 = "\""; @@ -55,24 +83,32 @@ public class Notifier .addEscape('"', "'") .build(); + // Notifier properties + private static final Color FLASH_COLOR = new Color(255, 0, 0, 70); + private static final int FLASH_DURATION = 2000; + private static final String MESSAGE_COLOR = "FF0000"; + + private final Provider client; private final String appName; private final RuneLiteConfig runeLiteConfig; private final Provider clientUI; private final ScheduledExecutorService executorService; private final Path notifyIconPath; + private Instant flashStart; @Inject private Notifier( final Provider clientUI, + final Provider client, final RuneLiteConfig runeliteConfig, final RuneLiteProperties runeLiteProperties, final ScheduledExecutorService executorService) { + this.client = client; this.appName = runeLiteProperties.getTitle(); this.clientUI = clientUI; this.runeLiteConfig = runeliteConfig; this.executorService = executorService; - this.notifyIconPath = RuneLite.RUNELITE_DIR.toPath().resolve("icon.png"); storeIcon(); } @@ -101,26 +137,63 @@ public class Notifier clientUI.requestFocus(); } - if (runeLiteConfig.enableTrayNotifications()) + switch (runeLiteConfig.notificationMode()) { - sendNotification(appName, message, type, null); + case TRAY: + sendNotification(appName, message, type); + break; + case BEEP: + Toolkit.getDefaultToolkit().beep(); + break; + case MESSAGE: + final Client client = this.client.get(); + + if (client != null && client.getGameState() == GameState.LOGGED_IN) + { + client.addChatMessage(ChatMessageType.GAME, appName, + "" + message + "", ""); + } + + break; + case FLASH: + flashStart = Instant.now(); + break; + } + } + + public void processFlash(final Graphics2D graphics) + { + if (flashStart == null) + { + return; } - if (runeLiteConfig.enableNotificationSound()) + final Client client = this.client.get(); + + if (client == null || client.getGameCycle() % 40 >= 20) { - Toolkit.getDefaultToolkit().beep(); + return; + } + + final Color color = graphics.getColor(); + graphics.setColor(FLASH_COLOR); + graphics.fill(new Rectangle(client.getCanvas().getSize())); + graphics.setColor(color); + + if (Instant.now().minusMillis(FLASH_DURATION).isAfter(flashStart)) + { + flashStart = null; } } private void sendNotification( final String title, final String message, - final TrayIcon.MessageType type, - final String subtitle) + final TrayIcon.MessageType type) { final String escapedTitle = SHELL_ESCAPE.escape(title); final String escapedMessage = SHELL_ESCAPE.escape(message); - final String escapedSubtitle = subtitle != null ? SHELL_ESCAPE.escape(subtitle) : null; + final String escapedSubtitle = null; switch (OSType.getOSType()) { diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java index 292cbc2826..18952cde20 100644 --- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java +++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java @@ -64,6 +64,7 @@ import net.runelite.api.events.ProjectileMoved; import net.runelite.api.events.SetMessage; import net.runelite.api.widgets.Widget; import static net.runelite.api.widgets.WidgetID.WORLD_MAP; +import net.runelite.client.Notifier; import net.runelite.client.RuneLite; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.input.KeyManager; @@ -98,6 +99,7 @@ public class Hooks private static final ClientThread clientThread = injector.getInstance(ClientThread.class); private static final GameTick tick = new GameTick(); private static final DrawManager renderHooks = injector.getInstance(DrawManager.class); + private static final Notifier notifier = injector.getInstance(Notifier.class); private static Dimension lastStretchedDimensions; private static BufferedImage stretchedImage; @@ -267,6 +269,8 @@ public class Hooks log.warn("Error during overlay rendering", ex); } + notifier.processFlash(graphics2d); + // Stretch the game image if the user has that enabled if (!client.isResized() && client.isStretchedEnabled()) { 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 97b2964f24..52c66f295d 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; @ConfigGroup( keyName = "runelite", @@ -80,32 +81,21 @@ public interface RuneLiteConfig extends Config } @ConfigItem( - keyName = "notificationTray", - name = "Enable tray notifications", - description = "Enables tray notifications", + keyName = "notificationMode", + name = "Notification mode", + description = "Determines mode of notifications", position = 5 ) - default boolean enableTrayNotifications() + default Notifier.NotificationMode notificationMode() { - return true; - } - - @ConfigItem( - keyName = "notificationSound", - name = "Enable sound on notifications", - description = "Enables the playing of a beep sound when notifications are displayed", - position = 6 - ) - default boolean enableNotificationSound() - { - return true; + return Notifier.NotificationMode.TRAY; } @ConfigItem( keyName = "notificationFocused", name = "Send notifications when focused", description = "Toggles idle notifications for when the client is focused", - position = 7 + position = 6 ) default boolean sendNotificationsWhenFocused() { @@ -116,7 +106,7 @@ public interface RuneLiteConfig extends Config keyName = "notificationRequestFocus", name = "Request focus on notification", description = "Toggles window focus request", - position = 8 + position = 7 ) default boolean requestFocusOnNotification() { @@ -127,7 +117,7 @@ public interface RuneLiteConfig extends Config keyName = "fontType", name = "Dynamic Overlay Font", description = "Configures what font type is used for in-game overlays such as player name, ground items, etc.", - position = 9 + position = 8 ) default FontType fontType() { @@ -138,7 +128,7 @@ public interface RuneLiteConfig extends Config keyName = "infoBoxVertical", name = "Display infoboxes vertically", description = "Toggles the infoboxes to display vertically", - position = 10 + position = 9 ) default boolean infoBoxVertical() { @@ -149,7 +139,7 @@ public interface RuneLiteConfig extends Config keyName = "infoBoxWrap", name = "Infobox wrap count", description = "Configures the amount of infoboxes shown before wrapping", - position = 11 + position = 10 ) default int infoBoxWrap() { @@ -160,7 +150,7 @@ public interface RuneLiteConfig extends Config keyName = "containInScreen", name = "Contain in screen", description = "Makes the client stay contained in the screen when attempted to move out of it.
Note: Only works if custom chrome is enabled.", - position = 12 + position = 11 ) default boolean containInScreen() { @@ -171,7 +161,7 @@ public interface RuneLiteConfig extends Config keyName = "rememberScreenBounds", name = "Remember client position", description = "Save the position and size of the client after exiting", - position = 13 + position = 12 ) default boolean rememberScreenBounds() {