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