diff --git a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java index cf0fcb0..aac73db 100644 --- a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -2,37 +2,58 @@ package envoy.client.ui; import java.awt.*; import java.awt.TrayIcon.MessageType; +import java.awt.image.BufferedImage; import javafx.application.Platform; import javafx.stage.Stage; -import envoy.client.event.OwnStatusChange; -import envoy.client.helper.ShutdownHelper; -import envoy.client.util.*; -import envoy.data.Message; -import envoy.data.User.UserStatus; - import dev.kske.eventbus.*; import dev.kske.eventbus.Event; +import envoy.data.Message; +import envoy.data.User.UserStatus; + +import envoy.client.data.Context; +import envoy.client.event.OwnStatusChange; +import envoy.client.helper.ShutdownHelper; +import envoy.client.util.*; + /** + * A tray icon with the Envoy logo, a "Envoy" tool tip and a pop-up menu with menu items for + * + * * @author Kai S. K. Engelbart * @since Envoy Client v0.2-alpha */ public final class StatusTrayIcon implements EventListener { /** - * The {@link TrayIcon} provided by the System Tray API for controlling the - * system tray. This includes displaying the icon, but also creating - * notifications when new messages are received. + * The {@link TrayIcon} provided by the System Tray API for controlling the system tray. This + * includes displaying the icon, but also creating notifications when new messages are received. */ private final TrayIcon trayIcon; /** - * A received {@link Message} is only displayed as a system tray notification if - * this variable is set to {@code true}. + * A received {@link Message} is only displayed as a system tray notification if this variable + * is set to {@code true}. */ - private boolean displayMessages; + private boolean displayMessageNotification; + + /** + * The Envoy logo on which the current user status and unread message count will be drawn to + * compose the tray icon. + */ + private final Image logo = IconUtil.loadAWTCompatible("/icons/envoy_logo.png") + .getScaledInstance(size, size, BufferedImage.SCALE_SMOOTH); + + /** + * The size of the tray icon, as defined by the system tray. + */ + private static final int size = (int) SystemTray.getSystemTray().getTrayIconSize().getWidth(); /** * @return {@code true} if the status tray icon is supported on this platform @@ -41,18 +62,12 @@ public final class StatusTrayIcon implements EventListener { public static boolean isSupported() { return SystemTray.isSupported(); } /** - * Creates a {@link StatusTrayIcon} with the Envoy logo, a tool tip and a pop-up - * menu. + * Creates a {@link StatusTrayIcon} with the Envoy logo, a tool tip and a pop-up menu. * - * @param stage the stage whose focus determines if message - * notifications are displayed + * @param stage the stage whose focus determines if message notifications are displayed * @since Envoy Client v0.2-beta */ public StatusTrayIcon(Stage stage) { - trayIcon = new TrayIcon(IconUtil.loadAWTCompatible("/icons/envoy_logo.png"), "Envoy"); - trayIcon.setImageAutoSize(true); - trayIcon.setToolTip("You are notified if you have unread messages."); - final var popup = new PopupMenu(); // Adding the exit menu item @@ -62,26 +77,37 @@ public final class StatusTrayIcon implements EventListener { // Adding the logout menu item final var logoutMenuItem = new MenuItem("Logout"); - logoutMenuItem.addActionListener(evt -> { hide(); Platform.runLater(UserUtil::logout); }); + logoutMenuItem.addActionListener(evt -> { + hide(); + Platform.runLater(UserUtil::logout); + }); popup.add(logoutMenuItem); // Adding the status change items final var statusSubMenu = new Menu("Change status"); for (final var status : UserStatus.values()) { final var statusMenuItem = new MenuItem(status.toString().toLowerCase()); - statusMenuItem.addActionListener(evt -> Platform.runLater(() -> UserUtil.changeStatus(status))); + statusMenuItem + .addActionListener(evt -> Platform.runLater(() -> UserUtil.changeStatus(status))); statusSubMenu.add(statusMenuItem); } popup.add(statusSubMenu); - trayIcon.setPopupMenu(popup); + // Initialize the icon + trayIcon = new TrayIcon(createImage(), "Envoy", popup); // Only display messages if the stage is not focused and the current user status - // is not BUSY (if BUSY, displayMessages will be false) - stage.focusedProperty().addListener((ov, wasFocused, isFocused) -> displayMessages = !displayMessages && wasFocused ? false : !isFocused); + // is not BUSY (if BUSY, displayMessageNotification will be false) + stage.focusedProperty() + .addListener((ov, wasFocused, isFocused) -> displayMessageNotification = + !displayMessageNotification && wasFocused ? false : !isFocused); // Show the window if the user clicks on the icon - trayIcon.addActionListener(evt -> Platform.runLater(() -> { stage.setIconified(false); stage.toFront(); stage.requestFocus(); })); + trayIcon.addActionListener(evt -> Platform.runLater(() -> { + stage.setIconified(false); + stage.toFront(); + stage.requestFocus(); + })); // Start processing message events EventBus.getInstance().registerListener(this); @@ -95,7 +121,7 @@ public final class StatusTrayIcon implements EventListener { public void show() { try { SystemTray.getSystemTray().add(trayIcon); - } catch (final AWTException e) {} + } catch (AWTException e) {} } /** @@ -103,15 +129,60 @@ public final class StatusTrayIcon implements EventListener { * * @since Envoy Client v0.2-beta */ - public void hide() { SystemTray.getSystemTray().remove(trayIcon); } + public void hide() { + SystemTray.getSystemTray().remove(trayIcon); + } @Event - private void onOwnStatusChange(OwnStatusChange statusChange) { displayMessages = !statusChange.get().equals(UserStatus.BUSY); } + private void onOwnStatusChange(OwnStatusChange statusChange) { + displayMessageNotification = !statusChange.get().equals(UserStatus.BUSY); + trayIcon.getImage().flush(); + trayIcon.setImage(createImage()); + } @Event private void onMessage(Message message) { - if (displayMessages) trayIcon - .displayMessage(message.hasAttachment() ? "New " + message.getAttachment().getType().toString().toLowerCase() + " message received" + if (displayMessageNotification) + trayIcon + .displayMessage(message.hasAttachment() + ? "New " + message.getAttachment().getType().toString().toLowerCase() + + " message received" : "New message received", message.getText(), MessageType.INFO); } + + /** + * Composes an icon that displays the current user status and the amount of unread messages, if + * any are present. + * + * @since Envoy Client v0.3-beta + */ + private BufferedImage createImage() { + + // Create a new image with the dimensions of the logo + var img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + + // Obtain the draw graphics of the image and copy the logo + var g = img.createGraphics(); + g.drawImage(logo, 0, 0, null); + + // Draw the current user status + switch (Context.getInstance().getLocalDB().getUser().getStatus()) { + case ONLINE: + g.setColor(Color.GREEN); + break; + case AWAY: + g.setColor(Color.YELLOW); + break; + case BUSY: + g.setColor(Color.RED); + break; + case OFFLINE: + g.setColor(Color.GRAY); + } + g.fillOval(size / 2, size / 2, size / 2, size / 2); + + // Finish drawing + g.dispose(); + return img; + } }