From 890a8927a537fb595a8d71e2885ee7b89ad08d06 Mon Sep 17 00:00:00 2001 From: zzz <zzz@i2pmail.org> Date: Wed, 1 Dec 2021 08:37:51 -0500 Subject: [PATCH] DTG: Add notification service to display popup messages unused for now --- .../src/net/i2p/desktopgui/Main.java | 43 ++++++++++- .../src/net/i2p/desktopgui/TrayManager.java | 72 +++++++++++++++++++ .../src/net/i2p/app/NotificationService.java | 54 ++++++++++++++ 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 core/java/src/net/i2p/app/NotificationService.java diff --git a/apps/desktopgui/src/net/i2p/desktopgui/Main.java b/apps/desktopgui/src/net/i2p/desktopgui/Main.java index 557563b318..aad835cf5e 100644 --- a/apps/desktopgui/src/net/i2p/desktopgui/Main.java +++ b/apps/desktopgui/src/net/i2p/desktopgui/Main.java @@ -17,6 +17,7 @@ import net.i2p.I2PAppContext; import net.i2p.app.ClientAppManager; import net.i2p.app.ClientAppState; import static net.i2p.app.ClientAppState.*; +import net.i2p.app.NotificationService; import net.i2p.desktopgui.router.RouterManager; import net.i2p.router.RouterContext; import net.i2p.router.app.RouterApp; @@ -28,7 +29,7 @@ import net.i2p.util.I2PProperties.I2PPropertyCallback; /** * The main class of the application. */ -public class Main implements RouterApp { +public class Main implements RouterApp, NotificationService { // non-null private final I2PAppContext _appContext; @@ -204,6 +205,46 @@ public class Main implements RouterApp { t.start(); } + /////// NotificationService methods + + /** + * Send a notification to the user. + * + * @param source unsupported + * @param category unsupported + * @param priority unsupported + * @param title for the popup, translated + * @param message translated + * @param path unsupported + * @return 0, or -1 on failure + */ + public int notify(String source, String category, int priority, String title, String message, String path) { + TrayManager tm = _trayManager; + if (tm == null) + return -1; + return tm.displayMessage(priority, title, message, path); + } + + /** + * Cancel a notification if possible. + * Unsupported. + * + * @return false always + */ + public boolean cancel(int id) { + return false; + } + + /** + * Update the text of a notification if possible. + * Unsupported. + * + * @return false always + */ + public boolean update(int id, String title, String message, String path) { + return false; + } + /////// ClientApp methods /** @since 0.9.26 */ diff --git a/apps/desktopgui/src/net/i2p/desktopgui/TrayManager.java b/apps/desktopgui/src/net/i2p/desktopgui/TrayManager.java index fc2c7b59ed..03f304f05b 100644 --- a/apps/desktopgui/src/net/i2p/desktopgui/TrayManager.java +++ b/apps/desktopgui/src/net/i2p/desktopgui/TrayManager.java @@ -8,21 +8,27 @@ import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.io.IOException; import java.net.URL; import javax.swing.JFrame; import javax.swing.JPopupMenu; +import javax.swing.SwingWorker; import javax.swing.event.MenuKeyEvent; import javax.swing.event.MenuKeyListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import net.i2p.I2PAppContext; +import net.i2p.apps.systray.UrlLauncher; import net.i2p.desktopgui.i18n.DesktopguiTranslator; +import net.i2p.util.Log; import net.i2p.util.SystemVersion; /** @@ -204,6 +210,72 @@ abstract class TrayManager { return image; } + /** + * Send a notification to the user. + * + * @param title for the popup, translated + * @param message translated + * @param path unsupported + * @return 0, or -1 on failure + */ + public int displayMessage(int priority, String title, String message, String path) { + final TrayIcon ti = trayIcon; + if (ti == null) + return -1; + TrayIcon.MessageType type; + if (priority <= Log.DEBUG) + type = TrayIcon.MessageType.NONE; + else if (priority <= Log.INFO) + type = TrayIcon.MessageType.INFO; + else if (priority <= Log.WARN) + type = TrayIcon.MessageType.WARNING; + else + type = TrayIcon.MessageType.ERROR; + ti.displayMessage(title, message, type); +/* + * There's apparently no way to bind a particular message to an action + that comes back. We can't keep a queue because we don't get + an action back when the message is removed via timeout or user x-out. + On OSX, new messages dismiss previous ones. + On LXDE (and Gnome?), new messages go under previous ones. Timeout is only 10 seconds. + Message timeout is platform-dependent. + So the order of events is unknowable. + This only works if there is only one message ever. + + if (path != null && path.length() > 0) { + if (path.charAt(0) == '/'); + path = path.substring(1); + final String url = _appContext.portMapper().getConsoleURL() + path; + ti.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + ti.removeActionListener(this); + new SwingWorker<Object, Object>() { + @Override + protected Object doInBackground() throws Exception { + System.out.println("DIB " + arg0); + UrlLauncher launcher = new UrlLauncher(_appContext, null, null); + try { + launcher.openUrl(url); + System.out.println("DIB success " + url); + } catch (IOException e1) { + System.out.println("DIB fail " + url); + } + return null; + } + + @Override + protected void done() { + System.out.println("done " + arg0); + } + }.execute(); + } + }); + } +*/ + return 0; + } + protected String _t(String s) { return DesktopguiTranslator._t(_appContext, s); } diff --git a/core/java/src/net/i2p/app/NotificationService.java b/core/java/src/net/i2p/app/NotificationService.java new file mode 100644 index 0000000000..2614e7c27c --- /dev/null +++ b/core/java/src/net/i2p/app/NotificationService.java @@ -0,0 +1,54 @@ +package net.i2p.app; + +/** + * A service to send messages to users. + * This service is currently provided by desktopgui (when supported and enabled). + * Other applications may support this interface in the future. + * + * Example usage: + * + * <pre> + * ClientAppManager cmgr = _context.clientAppManager(); + * if (cmgr != null) { + * NotificationService ns = (NotificationService) cmgr.getRegisteredApp("desktopgui"); + * if (ns != null) + * ns.notify("foo", null, Log.INFO, _t("foo"), _t("message"), "/foo/bar"); + * } + * <pre> + * + * @since 0.9.53 + */ +public interface NotificationService { + + /** + * Send a (possibly delayed) notification to the user. + * + * @param source e.g. "i2psnark" + * @param category may be null, probably unused + * @param priority higher is higher, Log.INFO etc. recommended, probably unused + * @param title for the popup, translated + * @param message translated + * @param path in console for more information, starting with /, must be URL-escaped, or null + * @return an ID to use with cancel() or update(), or -1 on failure + */ + public int notify(String source, String category, int priority, String title, String message, String path); + + /** + * Cancel a notification if possible. + * + * @param id as received from notify() + * @return success + */ + public boolean cancel(int id); + + /** + * Update the text of a notification if possible. + * + * @param id as received from notify() + * @param title for the popup, translated + * @param message translated + * @param path in console starting with /, must be URL-escaped, or null + * @return success + */ + public boolean update(int id, String title, String message, String path); +} -- GitLab