From 44f4d8f1e0fc903d58d87a210fd75622bbcaf39c Mon Sep 17 00:00:00 2001 From: kske Date: Fri, 16 Oct 2020 21:39:17 +0200 Subject: [PATCH 1/7] Display current user status in status tray icon --- .../java/envoy/client/ui/StatusTrayIcon.java | 133 ++++++++++++++---- 1 file changed, 102 insertions(+), 31 deletions(-) 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; + } } From 2e17caea4d832072d732699d0db6bc4389cd5b11 Mon Sep 17 00:00:00 2001 From: kske Date: Sun, 18 Oct 2020 16:45:36 +0200 Subject: [PATCH 2/7] Keep track of total unread messages and display them in the status tray --- .../src/main/java/envoy/client/data/Chat.java | 85 +++++++++++++------ .../java/envoy/client/ui/StatusTrayIcon.java | 50 ++++++++--- 2 files changed, 96 insertions(+), 39 deletions(-) diff --git a/client/src/main/java/envoy/client/data/Chat.java b/client/src/main/java/envoy/client/data/Chat.java index 80b2a97..0683d2d 100644 --- a/client/src/main/java/envoy/client/data/Chat.java +++ b/client/src/main/java/envoy/client/data/Chat.java @@ -3,16 +3,17 @@ package envoy.client.data; import java.io.*; import java.util.*; +import javafx.beans.property.*; import javafx.collections.*; -import envoy.client.net.WriteProxy; import envoy.data.*; import envoy.data.Message.MessageStatus; import envoy.event.MessageStatusChange; +import envoy.client.net.WriteProxy; + /** - * Represents a chat between two {@link User}s - * as a list of {@link Message} objects. + * Represents a chat between two {@link User}s as a list of {@link Message} objects. * * @author Maximilian Käfer * @author Leon Hofmeister @@ -25,13 +26,14 @@ public class Chat implements Serializable { protected transient ObservableList messages = FXCollections.observableArrayList(); - protected int unreadAmount; - /** * Stores the last time an {@link envoy.event.IsTyping} event has been sent. */ protected transient long lastWritingEvent; + protected int unreadAmount; + protected static IntegerProperty totalUnreadAmount = new SimpleIntegerProperty(0); + private static final long serialVersionUID = 2L; /** @@ -42,11 +44,14 @@ public class Chat implements Serializable { * @param recipient the user who receives the messages * @since Envoy Client v0.1-alpha */ - public Chat(Contact recipient) { this.recipient = recipient; } + public Chat(Contact recipient) { + this.recipient = recipient; + } private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { stream.defaultReadObject(); messages = FXCollections.observableList((List) stream.readObject()); + totalUnreadAmount.set(totalUnreadAmount.get() + unreadAmount); } private void writeObject(ObjectOutputStream stream) throws IOException { @@ -55,7 +60,10 @@ public class Chat implements Serializable { } @Override - public String toString() { return String.format("%s[recipient=%s,messages=%d]", getClass().getSimpleName(), recipient, messages.size()); } + public String toString() { + return String.format("%s[recipient=%s,messages=%d]", getClass().getSimpleName(), recipient, + messages.size()); + } /** * Generates a hash code based on the recipient. @@ -63,7 +71,9 @@ public class Chat implements Serializable { * @since Envoy Client v0.1-beta */ @Override - public int hashCode() { return Objects.hash(recipient); } + public int hashCode() { + return Objects.hash(recipient); + } /** * Tests equality to another object based on the recipient. @@ -72,39 +82,46 @@ public class Chat implements Serializable { */ @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof Chat)) return false; + if (this == obj) + return true; + if (!(obj instanceof Chat)) + return false; final var other = (Chat) obj; return Objects.equals(recipient, other.recipient); } /** - * Sets the status of all chat messages received from the recipient to - * {@code READ} starting from the bottom and stopping once a read message is - * found. + * Sets the status of all chat messages received from the recipient to {@code READ} starting + * from the bottom and stopping once a read message is found. * - * @param writeProxy the write proxy instance used to notify the server about - * the message status changes + * @param writeProxy the write proxy instance used to notify the server about the message status + * changes * @since Envoy Client v0.3-alpha */ public void read(WriteProxy writeProxy) { for (int i = messages.size() - 1; i >= 0; --i) { final var m = messages.get(i); - if (m.getSenderID() == recipient.getID()) if (m.getStatus() == MessageStatus.READ) break; - else { - m.setStatus(MessageStatus.READ); - writeProxy.writeMessageStatusChange(new MessageStatusChange(m)); - } + if (m.getSenderID() == recipient.getID()) + if (m.getStatus() == MessageStatus.READ) + break; + else { + m.setStatus(MessageStatus.READ); + writeProxy.writeMessageStatusChange(new MessageStatusChange(m)); + } } + totalUnreadAmount.set(totalUnreadAmount.get() - unreadAmount); unreadAmount = 0; } /** - * @return {@code true} if the newest message received in the chat doesn't have - * the status {@code READ} + * @return {@code true} if the newest message received in the chat doesn't have the status + * {@code READ} * @since Envoy Client v0.3-alpha */ - public boolean isUnread() { return !messages.isEmpty() && messages.get(messages.size() - 1).getStatus() != MessageStatus.READ; } + public boolean isUnread() { + return !messages.isEmpty() + && messages.get(messages.size() - 1).getStatus() != MessageStatus.READ; + } /** * Inserts a message at the correct place according to its creation date. @@ -128,14 +145,25 @@ public class Chat implements Serializable { * @return whether the message has been found and removed * @since Envoy Client v0.3-beta */ - public boolean remove(long messageID) { return messages.removeIf(m -> m.getID() == messageID); } + public boolean remove(long messageID) { + return messages.removeIf(m -> m.getID() == messageID); + } + + /** + * @return an integer property storing the total amount of unread messages + * @since Envoy Client v0.3-beta + */ + public static IntegerProperty getTotalUnreadAmount() { return totalUnreadAmount; } /** * Increments the amount of unread messages. * * @since Envoy Client v0.1-beta */ - public void incrementUnreadAmount() { ++unreadAmount; } + public void incrementUnreadAmount() { + ++unreadAmount; + totalUnreadAmount.set(totalUnreadAmount.get() + 1); + } /** * @return the amount of unread messages in this chat @@ -156,8 +184,7 @@ public class Chat implements Serializable { public Contact getRecipient() { return recipient; } /** - * @return the last known time a {@link envoy.event.IsTyping} event has been - * sent + * @return the last known time a {@link envoy.event.IsTyping} event has been sent * @since Envoy Client v0.2-beta */ public long getLastWritingEvent() { return lastWritingEvent; } @@ -167,5 +194,7 @@ public class Chat implements Serializable { * * @since Envoy Client v0.2-beta */ - public void lastWritingEventWasNow() { lastWritingEvent = System.currentTimeMillis(); } + public void lastWritingEventWasNow() { + lastWritingEvent = System.currentTimeMillis(); + } } diff --git a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java index aac73db..7fac539 100644 --- a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -1,5 +1,7 @@ package envoy.client.ui; +import static java.awt.Image.SCALE_SMOOTH; + import java.awt.*; import java.awt.TrayIcon.MessageType; import java.awt.image.BufferedImage; @@ -13,13 +15,13 @@ import dev.kske.eventbus.Event; import envoy.data.Message; import envoy.data.User.UserStatus; -import envoy.client.data.Context; +import envoy.client.data.*; 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 + * A tray icon with the Envoy logo, an "Envoy" tool tip and a pop-up menu with menu items for *
    *
  • Changing the user status
  • *
  • Logging out
  • @@ -43,17 +45,16 @@ public final class StatusTrayIcon implements EventListener { */ private boolean displayMessageNotification; + /** + * The size of the tray icon's image. + */ + private final Dimension size; + /** * 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(); + private final Image logo; /** * @return {@code true} if the status tray icon is supported on this platform @@ -68,6 +69,10 @@ public final class StatusTrayIcon implements EventListener { * @since Envoy Client v0.2-beta */ public StatusTrayIcon(Stage stage) { + size = SystemTray.getSystemTray().getTrayIconSize(); + logo = IconUtil.loadAWTCompatible("/icons/envoy_logo.png").getScaledInstance(size.width, + size.height, SCALE_SMOOTH); + final var popup = new PopupMenu(); // Adding the exit menu item @@ -102,6 +107,9 @@ public final class StatusTrayIcon implements EventListener { .addListener((ov, wasFocused, isFocused) -> displayMessageNotification = !displayMessageNotification && wasFocused ? false : !isFocused); + // Listen to changes in the total unread message amount + Chat.getTotalUnreadAmount().addListener((ov, oldValue, newValue) -> updateImage()); + // Show the window if the user clicks on the icon trayIcon.addActionListener(evt -> Platform.runLater(() -> { stage.setIconified(false); @@ -150,6 +158,17 @@ public final class StatusTrayIcon implements EventListener { : "New message received", message.getText(), MessageType.INFO); } + /** + * Updates the tray icon's image by first releasing the resources held by the current image and + * then setting a new one generated by the {@link StatusTrayIcon#createImage()} method. + * + * @since Envoy Client v0.3-beta + */ + private void updateImage() { + trayIcon.getImage().flush(); + trayIcon.setImage(createImage()); + } + /** * Composes an icon that displays the current user status and the amount of unread messages, if * any are present. @@ -159,7 +178,7 @@ public final class StatusTrayIcon implements EventListener { private BufferedImage createImage() { // Create a new image with the dimensions of the logo - var img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + var img = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB); // Obtain the draw graphics of the image and copy the logo var g = img.createGraphics(); @@ -179,7 +198,16 @@ public final class StatusTrayIcon implements EventListener { case OFFLINE: g.setColor(Color.GRAY); } - g.fillOval(size / 2, size / 2, size / 2, size / 2); + g.fillOval(size.width / 2, size.height / 2, size.width / 2, size.height / 2); + + // Draw total amount of unread messages, if any are present + if (Chat.getTotalUnreadAmount().get() > 0) { + g.setColor(Color.RED); + g.fillOval(size.width / 2, 0, size.width / 2, size.height / 2); + g.setColor(Color.BLACK); + g.drawString(String.valueOf(Chat.getTotalUnreadAmount().get()), size.width / 2, + size.height / 2); + } // Finish drawing g.dispose(); From 98f59c1383f95e266fd9f0f86d5dbee920ec599b Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 21 Oct 2020 22:14:04 +0200 Subject: [PATCH 3/7] Fix bug displaying the double amount of unread messages Additionally remove ChangeHandlers in SettingsItem and show StatusTrayIcon whenever supported --- .../main/java/envoy/client/data/LocalDB.java | 1 + .../java/envoy/client/data/SettingsItem.java | 17 ----------------- .../src/main/java/envoy/client/ui/Startup.java | 14 +++----------- .../java/envoy/client/ui/StatusTrayIcon.java | 8 +++----- .../ui/settings/GeneralSettingsPane.java | 18 +++++++++--------- 5 files changed, 16 insertions(+), 42 deletions(-) diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index e3c4ac7..2ae3570 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -147,6 +147,7 @@ public final class LocalDB implements EventListener { throw new IllegalStateException("Client user is null, cannot initialize user storage"); userFile = new File(dbDir, user.getID() + ".db"); try (var in = new ObjectInputStream(new FileInputStream(userFile))) { + Chat.getTotalUnreadAmount().set(0); chats = FXCollections.observableList((List) in.readObject()); // Some chats have changed and should not be overwritten by the saved values diff --git a/client/src/main/java/envoy/client/data/SettingsItem.java b/client/src/main/java/envoy/client/data/SettingsItem.java index 590f965..b2c9199 100644 --- a/client/src/main/java/envoy/client/data/SettingsItem.java +++ b/client/src/main/java/envoy/client/data/SettingsItem.java @@ -1,7 +1,6 @@ package envoy.client.data; import java.io.Serializable; -import java.util.function.Consumer; import javax.swing.JComponent; @@ -17,8 +16,6 @@ public final class SettingsItem implements Serializable { private T value; private String userFriendlyName, description; - private transient Consumer changeHandler; - private static final long serialVersionUID = 1L; /** @@ -52,8 +49,6 @@ public final class SettingsItem implements Serializable { * @since Envoy Client v0.3-alpha */ public void set(T value) { - if (changeHandler != null && value != this.value) - changeHandler.accept(value); this.value = value; } @@ -82,16 +77,4 @@ public final class SettingsItem implements Serializable { * @since Envoy Client v0.3-alpha */ public void setDescription(String description) { this.description = description; } - - /** - * Sets a {@code ChangeHandler} for this {@link SettingsItem}. It will be invoked with the - * current value once during the registration and every time when the value changes. - * - * @param changeHandler the changeHandler to set - * @since Envoy Client v0.3-alpha - */ - public void setChangeHandler(Consumer changeHandler) { - this.changeHandler = changeHandler; - changeHandler.accept(value); - } } diff --git a/client/src/main/java/envoy/client/ui/Startup.java b/client/src/main/java/envoy/client/ui/Startup.java index 76fa54b..18468e3 100644 --- a/client/src/main/java/envoy/client/ui/Startup.java +++ b/client/src/main/java/envoy/client/ui/Startup.java @@ -237,17 +237,9 @@ public final class Startup extends Application { e.consume(); }); - if (StatusTrayIcon.isSupported()) { - - // Initialize status tray icon - final var trayIcon = new StatusTrayIcon(stage); - Settings.getInstance().getItems().get("hideOnClose").setChangeHandler(c -> { - if ((Boolean) c) - trayIcon.show(); - else - trayIcon.hide(); - }); - } + // Initialize status tray icon + if (StatusTrayIcon.isSupported()) + new StatusTrayIcon(stage).show(); // Start auto save thread localDB.initAutoSave(); diff --git a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java index 7fac539..46a03b0 100644 --- a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -16,7 +16,7 @@ import envoy.data.Message; import envoy.data.User.UserStatus; import envoy.client.data.*; -import envoy.client.event.OwnStatusChange; +import envoy.client.event.*; import envoy.client.helper.ShutdownHelper; import envoy.client.util.*; @@ -82,10 +82,7 @@ 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 -> Platform.runLater(UserUtil::logout)); popup.add(logoutMenuItem); // Adding the status change items @@ -137,6 +134,7 @@ public final class StatusTrayIcon implements EventListener { * * @since Envoy Client v0.2-beta */ + @Event(eventType = Logout.class) public void hide() { SystemTray.getSystemTray().remove(trayIcon); } diff --git a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java index 3f773fc..16b6f01 100644 --- a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java @@ -27,15 +27,15 @@ public final class GeneralSettingsPane extends SettingsPane { final var settingsItems = settings.getItems(); // Add hide on close if supported - if (StatusTrayIcon.isSupported()) { - final var hideOnCloseCheckbox = - new SettingsCheckbox((SettingsItem) settingsItems.get("hideOnClose")); - final var hideOnCloseTooltip = new Tooltip( - "If selected, Envoy will still be present in the task bar when closed."); - hideOnCloseTooltip.setWrapText(true); - hideOnCloseCheckbox.setTooltip(hideOnCloseTooltip); - getChildren().add(hideOnCloseCheckbox); - } + final var hideOnCloseCheckbox = + new SettingsCheckbox((SettingsItem) settingsItems.get("hideOnClose")); + final var hideOnCloseTooltip = new Tooltip(StatusTrayIcon.isSupported() + ? "If selected, Envoy will still be present in the task bar when closed." + : "status tray icon is not supported on your system."); + hideOnCloseTooltip.setWrapText(true); + hideOnCloseCheckbox.setTooltip(hideOnCloseTooltip); + hideOnCloseCheckbox.setDisable(!StatusTrayIcon.isSupported()); + getChildren().add(hideOnCloseCheckbox); final var enterToSendCheckbox = new SettingsCheckbox((SettingsItem) settingsItems.get("enterToSend")); From aaaf5ef7be0100db88d41b24b700a94eea7527b7 Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 22 Oct 2020 12:17:44 +0200 Subject: [PATCH 4/7] Fix TrayIcon colors --- client/src/main/java/envoy/client/ui/StatusTrayIcon.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java index 46a03b0..36b8522 100644 --- a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -188,7 +188,7 @@ public final class StatusTrayIcon implements EventListener { g.setColor(Color.GREEN); break; case AWAY: - g.setColor(Color.YELLOW); + g.setColor(Color.ORANGE); break; case BUSY: g.setColor(Color.RED); @@ -200,9 +200,9 @@ public final class StatusTrayIcon implements EventListener { // Draw total amount of unread messages, if any are present if (Chat.getTotalUnreadAmount().get() > 0) { - g.setColor(Color.RED); - g.fillOval(size.width / 2, 0, size.width / 2, size.height / 2); g.setColor(Color.BLACK); + g.fillOval(size.width / 2, 0, size.width / 2, size.height / 2); + g.setColor(Color.WHITE); g.drawString(String.valueOf(Chat.getTotalUnreadAmount().get()), size.width / 2, size.height / 2); } From e79f60e95e209525758f165325925d1275f0fda5 Mon Sep 17 00:00:00 2001 From: kske Date: Thu, 22 Oct 2020 15:32:06 +0200 Subject: [PATCH 5/7] Properly display unread message count (>9) --- .../main/java/envoy/client/ui/StatusTrayIcon.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java index 36b8522..8cde432 100644 --- a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -56,6 +56,8 @@ public final class StatusTrayIcon implements EventListener { */ private final Image logo; + private static final Font unreadMessageFont = new Font("sans-serif", Font.PLAIN, 8); + /** * @return {@code true} if the status tray icon is supported on this platform * @since Envoy Client v0.2-beta @@ -200,10 +202,18 @@ public final class StatusTrayIcon implements EventListener { // Draw total amount of unread messages, if any are present if (Chat.getTotalUnreadAmount().get() > 0) { + + // Draw black background circle g.setColor(Color.BLACK); g.fillOval(size.width / 2, 0, size.width / 2, size.height / 2); + + // Unread amount in white + String unreadAmount = Chat.getTotalUnreadAmount().get() > 9 ? "9+" + : String.valueOf(Chat.getTotalUnreadAmount().get()); g.setColor(Color.WHITE); - g.drawString(String.valueOf(Chat.getTotalUnreadAmount().get()), size.width / 2, + g.setFont(unreadMessageFont); + g.drawString(unreadAmount, + 3 * size.width / 4 - g.getFontMetrics().stringWidth(unreadAmount) / 2, size.height / 2); } From cd8971b6b4b461d867fb152896927985245f908b Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 22 Oct 2020 16:09:09 +0200 Subject: [PATCH 6/7] Fix settings button placement Fixes #94 --- .../envoy/client/ui/controller/ChatScene.java | 15 +++------ client/src/main/resources/fxml/ChatScene.fxml | 33 +++++++++---------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index c7d6034..b118f8c 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -107,9 +107,6 @@ public final class ChatScene implements EventListener, Restorable { @FXML private TextArea contactSearch; - @FXML - private VBox contactOperations; - @FXML private TabPane tabPane; @@ -125,9 +122,6 @@ public final class ChatScene implements EventListener, Restorable { @FXML private HBox ownContactControl; - @FXML - private Region spaceBetweenUserAndSettingsButton; - private Chat currentChat; private FilteredList chats; private Attachment pendingAttachment; @@ -175,7 +169,7 @@ public final class ChatScene implements EventListener, Restorable { // Set the icons of buttons and image views settingsButton.setGraphic( - new ImageView(IconUtil.loadIconThemeSensitive("settings", DEFAULT_ICON_SIZE))); + new ImageView(IconUtil.loadIconThemeSensitive("settings", 22))); voiceButton.setGraphic( new ImageView(IconUtil.loadIconThemeSensitive("microphone", DEFAULT_ICON_SIZE))); attachmentButton.setGraphic( @@ -195,7 +189,6 @@ public final class ChatScene implements EventListener, Restorable { chatList.setItems(chats = new FilteredList<>(localDB.getChats())); // Set the design of the box in the upper-left corner - settingsButton.setAlignment(Pos.BOTTOM_RIGHT); generateOwnStatusControl(); Platform.runLater(() -> { @@ -797,15 +790,15 @@ public final class ChatScene implements EventListener, Restorable { private void generateOwnStatusControl() { // Update the own user status if present - if (ownContactControl.getChildren().get(0) instanceof ContactControl) - ((ContactControl) ownContactControl.getChildren().get(0)).replaceInfoLabel(); + if (ownContactControl.getChildren().get(1) instanceof ContactControl) + ((ContactControl) ownContactControl.getChildren().get(1)).replaceInfoLabel(); else { // Else prepend it to the HBox children final var ownUserControl = new ContactControl(localDB.getUser()); ownUserControl.setAlignment(Pos.CENTER_LEFT); HBox.setHgrow(ownUserControl, Priority.NEVER); - ownContactControl.getChildren().add(0, ownUserControl); + ownContactControl.getChildren().add(1, ownUserControl); } } diff --git a/client/src/main/resources/fxml/ChatScene.fxml b/client/src/main/resources/fxml/ChatScene.fxml index d61325c..f293d3e 100644 --- a/client/src/main/resources/fxml/ChatScene.fxml +++ b/client/src/main/resources/fxml/ChatScene.fxml @@ -57,7 +57,7 @@ - - + - - - - - - + + From 241e5def03cc7881af33870849516a07dde467d6 Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 22 Oct 2020 16:15:34 +0200 Subject: [PATCH 7/7] Fix "infinite" amount of messages being displayed Fixes #105 --- .../envoy/client/ui/control/ChatControl.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/client/src/main/java/envoy/client/ui/control/ChatControl.java b/client/src/main/java/envoy/client/ui/control/ChatControl.java index de50085..6c45d44 100644 --- a/client/src/main/java/envoy/client/ui/control/ChatControl.java +++ b/client/src/main/java/envoy/client/ui/control/ChatControl.java @@ -32,12 +32,12 @@ public final class ChatControl extends HBox { setPadding(new Insets(0, 0, 3, 0)); // Profile picture - final var contactProfilePic = + var contactProfilePic = new ProfilePicImageView(chat instanceof GroupChat ? groupIcon : userIcon, 32); getChildren().add(contactProfilePic); // Spacing - final var leftSpacing = new Region(); + var leftSpacing = new Region(); leftSpacing.setPrefSize(8, 0); leftSpacing.setMinSize(8, 0); leftSpacing.setMaxSize(8, 0); @@ -48,17 +48,15 @@ public final class ChatControl extends HBox { // Unread messages if (chat.getUnreadAmount() != 0) { - final var spacing = new Region(); + var spacing = new Region(); setHgrow(spacing, Priority.ALWAYS); getChildren().add(spacing); - final var unreadMessagesLabel = new Label(Integer.toString(chat.getUnreadAmount())); + var unreadMessagesLabel = new Label( + chat.getUnreadAmount() > 99 ? "99+" : String.valueOf(chat.getUnreadAmount())); unreadMessagesLabel.setMinSize(15, 15); - final var vbox = new VBox(); - vbox.setAlignment(Pos.CENTER_RIGHT); - unreadMessagesLabel.setAlignment(Pos.CENTER); + unreadMessagesLabel.setAlignment(Pos.CENTER_RIGHT); unreadMessagesLabel.getStyleClass().add("unread-messages-amount"); - vbox.getChildren().add(unreadMessagesLabel); - getChildren().add(vbox); + getChildren().add(unreadMessagesLabel); } getStyleClass().add("list-element"); }