From a53d887c59bee8f79a6cdfb49f5045033204465e Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 18 Jan 2022 14:14:55 +0100 Subject: [PATCH 1/3] move creation of tray icon to integrations-api this will allow non-awt based tray icons --- src/main/java/module-info.java | 7 +++ .../integrations/tray/ActionItem.java | 4 ++ .../tray/AwtTrayMenuController.java | 45 +++++++++++++++++++ .../integrations/tray/SeparatorItem.java | 4 ++ .../integrations/tray/SubMenuItem.java | 6 +++ .../integrations/tray/TrayMenuController.java | 25 +++++++++++ .../integrations/tray/TrayMenuItem.java | 4 ++ 7 files changed, 95 insertions(+) create mode 100644 src/main/java/org/cryptomator/integrations/tray/ActionItem.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/SeparatorItem.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/SubMenuItem.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/TrayMenuItem.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 4cadffc..f3381f4 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,6 +1,13 @@ +import org.cryptomator.integrations.tray.AwtTrayMenuController; +import org.cryptomator.integrations.tray.TrayMenuController; + module org.cryptomator.integrations.api { + requires java.desktop; + exports org.cryptomator.integrations.autostart; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.tray; exports org.cryptomator.integrations.uiappearance; + + provides TrayMenuController with AwtTrayMenuController; } \ No newline at end of file diff --git a/src/main/java/org/cryptomator/integrations/tray/ActionItem.java b/src/main/java/org/cryptomator/integrations/tray/ActionItem.java new file mode 100644 index 0000000..383618b --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/ActionItem.java @@ -0,0 +1,4 @@ +package org.cryptomator.integrations.tray; + +public record ActionItem(String title, Runnable action) implements TrayMenuItem { +} diff --git a/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java new file mode 100644 index 0000000..85325ff --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java @@ -0,0 +1,45 @@ +package org.cryptomator.integrations.tray; + + +import java.awt.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public class AwtTrayMenuController implements TrayMenuController { + + private TrayIcon trayIcon; + + @Override + public void showTrayIcon(InputStream iconData, String tooltip) throws IOException { + var image = Toolkit.getDefaultToolkit().createImage(iconData.readAllBytes()); + trayIcon = new TrayIcon(image, tooltip); + } + + @Override + public void setTrayMenu(List items) { + if (trayIcon != null) { + var menu = new PopupMenu(); + addChildren(menu, items); + trayIcon.setPopupMenu(menu); + } + } + + private void addChildren(Menu menu, List items) { + for (var item : items) { + // TODO: use Pattern Matching for switch, once available + if (item instanceof ActionItem a) { + var menuItem = new MenuItem(a.title()); + menuItem.addActionListener(evt -> a.action().run()); + menu.add(menuItem); + } else if (item instanceof SeparatorItem) { + menu.addSeparator(); + } else if (item instanceof SubMenuItem s) { + var submenu = new Menu(s.title()); + addChildren(submenu, s.items()); + menu.add(submenu); + } + } + } + +} diff --git a/src/main/java/org/cryptomator/integrations/tray/SeparatorItem.java b/src/main/java/org/cryptomator/integrations/tray/SeparatorItem.java new file mode 100644 index 0000000..7a4eab2 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/SeparatorItem.java @@ -0,0 +1,4 @@ +package org.cryptomator.integrations.tray; + +public record SeparatorItem() implements TrayMenuItem { +} diff --git a/src/main/java/org/cryptomator/integrations/tray/SubMenuItem.java b/src/main/java/org/cryptomator/integrations/tray/SubMenuItem.java new file mode 100644 index 0000000..82a65bf --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/SubMenuItem.java @@ -0,0 +1,6 @@ +package org.cryptomator.integrations.tray; + +import java.util.List; + +public record SubMenuItem(String title, List items) implements TrayMenuItem { +} diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java new file mode 100644 index 0000000..b840f53 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java @@ -0,0 +1,25 @@ +package org.cryptomator.integrations.tray; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public interface TrayMenuController { + + /** + * Adds an icon to the system tray. + * + * @param iconData What image to show + * @param tooltip Text shown when hovering + * @throws IOException thrown when interacting with the given iconData + */ + void showTrayIcon(InputStream iconData, String tooltip) throws IOException; + + /** + * Show the given options in the tray menu. + * + * @param items Menu items + */ + void setTrayMenu(List items); + +} diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuItem.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuItem.java new file mode 100644 index 0000000..a174c15 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuItem.java @@ -0,0 +1,4 @@ +package org.cryptomator.integrations.tray; + +public sealed interface TrayMenuItem permits ActionItem, SubMenuItem, SeparatorItem { +} From 96e3251a9e8b7c3184fa2c47b1edf637ac1c3211 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 7 Mar 2022 09:11:56 +0100 Subject: [PATCH 2/3] removed fallback implementation (will be part of the main app) --- src/main/java/module-info.java | 5 -- .../tray/AwtTrayMenuController.java | 48 ------------------- 2 files changed, 53 deletions(-) delete mode 100644 src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 529e1fb..2ac9eaf 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,4 +1,3 @@ -import org.cryptomator.integrations.tray.AwtTrayMenuController; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -7,8 +6,6 @@ module org.cryptomator.integrations.api { - requires java.desktop; - exports org.cryptomator.integrations.autostart; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.tray; @@ -19,6 +16,4 @@ uses TrayIntegrationProvider; uses TrayMenuController; uses UiAppearanceProvider; - - provides TrayMenuController with AwtTrayMenuController; } \ No newline at end of file diff --git a/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java deleted file mode 100644 index 0038dd3..0000000 --- a/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.cryptomator.integrations.tray; - - -import org.cryptomator.integrations.common.Priority; - -import java.awt.*; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -@Priority(Priority.FALLBACK) -public class AwtTrayMenuController implements TrayMenuController { - - private TrayIcon trayIcon; - - @Override - public void showTrayIcon(InputStream iconData, String tooltip) throws IOException { - var image = Toolkit.getDefaultToolkit().createImage(iconData.readAllBytes()); - trayIcon = new TrayIcon(image, tooltip); - } - - @Override - public void setTrayMenu(List items) { - if (trayIcon != null) { - var menu = new PopupMenu(); - addChildren(menu, items); - trayIcon.setPopupMenu(menu); - } - } - - private void addChildren(Menu menu, List items) { - for (var item : items) { - // TODO: use Pattern Matching for switch, once available - if (item instanceof ActionItem a) { - var menuItem = new MenuItem(a.title()); - menuItem.addActionListener(evt -> a.action().run()); - menu.add(menuItem); - } else if (item instanceof SeparatorItem) { - menu.addSeparator(); - } else if (item instanceof SubMenuItem s) { - var submenu = new Menu(s.title()); - addChildren(submenu, s.items()); - menu.add(submenu); - } - } - } - -} From e4137ffb4d6506bcd1d968fe1b05962882e09a81 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 7 Mar 2022 09:33:43 +0100 Subject: [PATCH 3/3] api fine tuning and documentation --- .../tray/TrayIntegrationProvider.java | 9 +++++++++ .../integrations/tray/TrayMenuController.java | 20 +++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java b/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java index 0c330e5..8650a2f 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java @@ -4,8 +4,17 @@ import java.util.Optional; +/** + * Allows to perform OS-specific tasks when the app gets minimized to or restored from a tray icon. + */ public interface TrayIntegrationProvider { + /** + * Loads the best-suited TrayIntegrationProvider. + * + * @return preferred TrayIntegrationProvider (if any) + * @since 1.1.0 + */ static Optional get() { return IntegrationsLoader.load(TrayIntegrationProvider.class); } diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java index 199be1b..48833af 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java @@ -7,6 +7,11 @@ import java.util.List; import java.util.Optional; +/** + * Displays a tray icon and menu + * + * @since 1.1.0 + */ public interface TrayMenuController { static Optional get() { @@ -14,19 +19,22 @@ static Optional get() { } /** - * Adds an icon to the system tray. + * Displays an icon on the system tray. * - * @param iconData What image to show - * @param tooltip Text shown when hovering - * @throws IOException thrown when interacting with the given iconData + * @param rawImageData What image to show + * @param defaultAction Action to perform when interacting with the icon directly instead of its menu + * @param tooltip Text shown when hovering + * @throws IOException thrown when interacting with the given rawImageData */ - void showTrayIcon(InputStream iconData, String tooltip) throws IOException; + void showTrayIcon(InputStream rawImageData, Runnable defaultAction, String tooltip) throws IOException; /** * Show the given options in the tray menu. + *

+ * This method may be called multiple times, e.g. when the vault list changes. * * @param items Menu items */ - void setTrayMenu(List items); + void updateTrayMenu(List items); }