package envoy.client.ui; import java.awt.*; import java.awt.TrayIcon.MessageType; 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; /** * @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. */ private final TrayIcon trayIcon; /** * A received {@link Message} is only displayed as a system tray notification if * this variable is set to {@code true}. */ private boolean displayMessages; /** * @return {@code true} if the status tray icon is supported on this platform * @since Envoy Client v0.2-beta */ public static boolean isSupported() { return SystemTray.isSupported(); } /** * 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 * @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 final var exitMenuItem = new MenuItem("Exit"); exitMenuItem.addActionListener(evt -> ShutdownHelper.exit(true)); popup.add(exitMenuItem); // Adding the logout menu item final var logoutMenuItem = new MenuItem("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))); statusSubMenu.add(statusMenuItem); } popup.add(statusSubMenu); trayIcon.setPopupMenu(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); // Show the window if the user clicks on the icon trayIcon.addActionListener(evt -> Platform.runLater(() -> { stage.setIconified(false); stage.toFront(); stage.requestFocus(); })); // Start processing message events EventBus.getInstance().registerListener(this); } /** * Makes the icon appear in the system tray. * * @since Envoy Client v0.2-alpha */ public void show() { try { SystemTray.getSystemTray().add(trayIcon); } catch (final AWTException e) {} } /** * Removes the icon from the system tray. * * @since Envoy Client v0.2-beta */ public void hide() { SystemTray.getSystemTray().remove(trayIcon); } @Event private void onOwnStatusChange(OwnStatusChange statusChange) { displayMessages = !statusChange.get().equals(UserStatus.BUSY); } @Event private void onMessage(Message message) { if (displayMessages) trayIcon .displayMessage(message.hasAttachment() ? "New " + message.getAttachment().getType().toString().toLowerCase() + " message received" : "New message received", message.getText(), MessageType.INFO); } }