Display current user status in status tray icon
This commit is contained in:
		@@ -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
 | 
			
		||||
 * <ul>
 | 
			
		||||
 * <li>Changing the user status</li>
 | 
			
		||||
 * <li>Logging out</li>
 | 
			
		||||
 * <li>Quitting Envoy</li>
 | 
			
		||||
 * </ul>
 | 
			
		||||
 *
 | 
			
		||||
 * @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;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user