From 2e899cc2a69ebce45da3d78f9442c5ccde98c42c Mon Sep 17 00:00:00 2001
From: agsantos <aline.gondimsantos@savoirfairelinux.com>
Date: Fri, 4 Dec 2020 11:01:49 -0500
Subject: [PATCH] plugins: add ChatHandler API

Change-Id: Ida2ce6ff25abc2bc171c5a3f84aae0ba4d8bd627
---
 src/api/pluginmodel.h               | 30 +++++++++---
 src/chatview.cpp                    |  1 +
 src/pluginmodel.cpp                 | 75 ++++++++++++++++++++++++-----
 src/qtwrapper/pluginmanager.cpp     | 47 +++++++++++++++---
 src/qtwrapper/pluginmanagerMock.cpp | 33 +++++++++++--
 src/qtwrapper/pluginmanager_wrap.h  | 19 ++++++--
 src/web-chatview/chatview.html      |  9 +++-
 src/web-chatview/chatview.js        | 25 ++++++++++
 8 files changed, 203 insertions(+), 36 deletions(-)

diff --git a/src/api/pluginmodel.h b/src/api/pluginmodel.h
index 0cc88535..89a76f79 100644
--- a/src/api/pluginmodel.h
+++ b/src/api/pluginmodel.h
@@ -44,7 +44,7 @@ struct PluginDetails
     bool loaded = false;
 };
 
-struct MediaHandlerDetails
+struct PluginHandlerDetails
 {
     QString id = "";
     QString name = "";
@@ -76,13 +76,13 @@ public:
      * Get list of installed plugins
      * @return plugins installed
      */
-    VectorString listAvailablePlugins() const;
+    VectorString getInstalledPlugins() const;
 
     /**
      * Get list of loaded plugins
      * @return plugins loaded
      */
-    VectorString listLoadedPlugins() const;
+    VectorString getLoadedPlugins() const;
 
     /**
      * Get details of installed plugin
@@ -118,7 +118,7 @@ public:
      * List all plugins Media Handlers
      * @return List of all plugins Media Handlers
      */
-    VectorString listCallMediaHandlers() const;
+    VectorString getCallMediaHandlers() const;
 
     /**
      * Toggle media handler
@@ -127,17 +127,31 @@ public:
                                             const QString& callId,
                                             bool toggle);
 
+    VectorString getChatHandlers() const;
+
+    /**
+     * Toggle chat handler
+     */
+    Q_INVOKABLE void toggleChatHandler(const QString& chatHandlerId,
+                                       const QString& accountId,
+                                       const QString& peerId,
+                                       bool toggle);
+
     /**
      * Verify if there is an active plugin media handler
      * @return Map with name and status
      */
-    MapStringVectorString getCallMediaHandlerStatus(const QString& callId);
+    VectorString getCallMediaHandlerStatus(const QString& callId);
 
     /**
      * Get details of installed plugins media handlers
      * @return Media Handler Details
      */
-    plugin::MediaHandlerDetails getCallMediaHandlerDetails(const QString& mediaHandlerId);
+    plugin::PluginHandlerDetails getCallMediaHandlerDetails(const QString& mediaHandlerId);
+
+    VectorString getChatHandlerStatus(const QString& accountId, const QString& peerId);
+
+    plugin::PluginHandlerDetails getChatHandlerDetails(const QString& chatHandlerId);
 
     /**
      * Get preferences map of installed plugin
@@ -164,7 +178,11 @@ public:
      * @return true if preference was succesfully reset
      */
     Q_INVOKABLE bool resetPluginPreferencesValues(const QString& path);
+
+Q_SIGNALS:
+    void chatHandlerStatusUpdated(bool isVisible);
 };
 
 } // namespace api
 } // namespace lrc
+Q_DECLARE_METATYPE(lrc::api::PluginModel*)
diff --git a/src/chatview.cpp b/src/chatview.cpp
index e1a4cfc7..ff7ac388 100644
--- a/src/chatview.cpp
+++ b/src/chatview.cpp
@@ -29,6 +29,7 @@ getTranslatedStrings(bool qwebview)
     return {
         {"Hide chat view", QObject::tr("Hide chat view")},
         {"Place video call", QObject::tr("Place video call")},
+        {"Show available plugins", QObject::tr("Show available plugins")},
         {"Place audio call", QObject::tr("Place audio call")},
         {"Add to conversations", QObject::tr("Add to conversations")},
         {"Unban contact", QObject::tr("Unban contact")},
diff --git a/src/pluginmodel.cpp b/src/pluginmodel.cpp
index 5de052e2..1bc38e9a 100644
--- a/src/pluginmodel.cpp
+++ b/src/pluginmodel.cpp
@@ -52,6 +52,10 @@ void
 PluginModel::setPluginsEnabled(bool enable)
 {
     PluginManager::instance().setPluginsEnabled(enable);
+    if (!enable)
+        emit chatHandlerStatusUpdated(false);
+    else
+        emit chatHandlerStatusUpdated(getChatHandlers().size() > 0);
 }
 
 bool
@@ -61,15 +65,15 @@ PluginModel::getPluginsEnabled() const
 }
 
 VectorString
-PluginModel::listAvailablePlugins() const
+PluginModel::getInstalledPlugins() const
 {
-    return VectorString::fromList(PluginManager::instance().listAvailablePlugins());
+    return VectorString::fromList(PluginManager::instance().getInstalledPlugins());
 }
 
 VectorString
-PluginModel::listLoadedPlugins() const
+PluginModel::getLoadedPlugins() const
 {
-    return VectorString::fromList(PluginManager::instance().listLoadedPlugins());
+    return VectorString::fromList(PluginManager::instance().getLoadedPlugins());
 }
 
 plugin::PluginDetails
@@ -86,7 +90,7 @@ PluginModel::getPluginDetails(const QString& path)
         result.iconPath = details["iconPath"];
     }
 
-    VectorString loadedPlugins = listLoadedPlugins();
+    VectorString loadedPlugins = getLoadedPlugins();
     if (std::find(loadedPlugins.begin(), loadedPlugins.end(), result.path) != loadedPlugins.end()) {
         result.loaded = true;
     }
@@ -113,19 +117,24 @@ bool
 PluginModel::loadPlugin(const QString& path)
 {
     bool status = PluginManager::instance().loadPlugin(path);
+    if (getChatHandlers().size() > 0)
+        emit chatHandlerStatusUpdated(getPluginsEnabled());
     return status;
 }
 
 bool
 PluginModel::unloadPlugin(const QString& path)
 {
-    return PluginManager::instance().unloadPlugin(path);
+    bool status = PluginManager::instance().unloadPlugin(path);
+    if (getChatHandlers().size() <= 0)
+        emit chatHandlerStatusUpdated(false);
+    return status;
 }
 
 VectorString
-PluginModel::listCallMediaHandlers() const
+PluginModel::getCallMediaHandlers() const
 {
-    return VectorString::fromList(PluginManager::instance().listCallMediaHandlers());
+    return VectorString::fromList(PluginManager::instance().getCallMediaHandlers());
 }
 
 void
@@ -136,21 +145,36 @@ PluginModel::toggleCallMediaHandler(const QString& mediaHandlerId,
     PluginManager::instance().toggleCallMediaHandler(mediaHandlerId, callId, toggle);
 }
 
-MapStringVectorString
+VectorString
+PluginModel::getChatHandlers() const
+{
+    return VectorString::fromList(PluginManager::instance().getChatHandlers());
+}
+
+void
+PluginModel::toggleChatHandler(const QString& chatHandlerId,
+                               const QString& accountId,
+                               const QString& peerId,
+                               bool toggle)
+{
+    PluginManager::instance().toggleChatHandler(chatHandlerId, accountId, peerId, toggle);
+}
+
+VectorString
 PluginModel::getCallMediaHandlerStatus(const QString& callId)
 {
-    return PluginManager::instance().getCallMediaHandlerStatus(callId);
+    return VectorString::fromList(PluginManager::instance().getCallMediaHandlerStatus(callId));
 }
 
-plugin::MediaHandlerDetails
+plugin::PluginHandlerDetails
 PluginModel::getCallMediaHandlerDetails(const QString& mediaHandlerId)
 {
     if (mediaHandlerId.isEmpty()) {
-        return plugin::MediaHandlerDetails();
+        return plugin::PluginHandlerDetails();
     }
     MapStringString mediaHandlerDetails = PluginManager::instance().getCallMediaHandlerDetails(
         mediaHandlerId);
-    plugin::MediaHandlerDetails result;
+    plugin::PluginHandlerDetails result;
     if (!mediaHandlerDetails.empty()) {
         result.id = mediaHandlerId;
         result.iconPath = mediaHandlerDetails["iconPath"];
@@ -161,6 +185,31 @@ PluginModel::getCallMediaHandlerDetails(const QString& mediaHandlerId)
     return result;
 }
 
+VectorString
+PluginModel::getChatHandlerStatus(const QString& accountId, const QString& peerId)
+{
+    return VectorString::fromList(PluginManager::instance().getChatHandlerStatus(accountId, peerId));
+}
+
+plugin::PluginHandlerDetails
+PluginModel::getChatHandlerDetails(const QString& chatHandlerId)
+{
+    if (chatHandlerId.isEmpty()) {
+        return plugin::PluginHandlerDetails();
+    }
+    MapStringString chatHandlerDetails = PluginManager::instance().getChatHandlerDetails(
+        chatHandlerId);
+    plugin::PluginHandlerDetails result;
+    if (!chatHandlerDetails.empty()) {
+        result.id = chatHandlerId;
+        result.iconPath = chatHandlerDetails["iconPath"];
+        result.name = chatHandlerDetails["name"];
+        result.pluginId = chatHandlerDetails["pluginId"];
+    }
+
+    return result;
+}
+
 VectorMapStringString
 PluginModel::getPluginPreferences(const QString& path)
 {
diff --git a/src/qtwrapper/pluginmanager.cpp b/src/qtwrapper/pluginmanager.cpp
index 668740c4..ba9f8f94 100644
--- a/src/qtwrapper/pluginmanager.cpp
+++ b/src/qtwrapper/pluginmanager.cpp
@@ -38,15 +38,15 @@ PluginManagerInterface::getPluginDetails(const QString& path)
 }
 
 QStringList
-PluginManagerInterface::listAvailablePlugins()
+PluginManagerInterface::getInstalledPlugins()
 {
-    return convertStringList(DRing::listAvailablePlugins());
+    return convertStringList(DRing::getInstalledPlugins());
 }
 
 QStringList
-PluginManagerInterface::listLoadedPlugins()
+PluginManagerInterface::getLoadedPlugins()
 {
-    return convertStringList(DRing::listLoadedPlugins());
+    return convertStringList(DRing::getLoadedPlugins());
 }
 
 int
@@ -62,9 +62,9 @@ PluginManagerInterface::uninstallPlugin(const QString& pluginRootPath)
 }
 
 QStringList
-PluginManagerInterface::listCallMediaHandlers()
+PluginManagerInterface::getCallMediaHandlers()
 {
-    return convertStringList(DRing::listCallMediaHandlers());
+    return convertStringList(DRing::getCallMediaHandlers());
 }
 
 void
@@ -75,10 +75,28 @@ PluginManagerInterface::toggleCallMediaHandler(const QString& mediaHandlerId,
     DRing::toggleCallMediaHandler(mediaHandlerId.toStdString(), callId.toStdString(), toggle);
 }
 
-MapStringVectorString
+QStringList
+PluginManagerInterface::getChatHandlers()
+{
+    return convertStringList(DRing::getChatHandlers());
+}
+
+void
+PluginManagerInterface::toggleChatHandler(const QString& chatHandlerId,
+                                          const QString& accountId,
+                                          const QString& peerId,
+                                          bool toggle)
+{
+    DRing::toggleChatHandler(chatHandlerId.toStdString(),
+                             accountId.toStdString(),
+                             peerId.toStdString(),
+                             toggle);
+}
+
+QStringList
 PluginManagerInterface::getCallMediaHandlerStatus(const QString& callId)
 {
-    return convertMap(DRing::getCallMediaHandlerStatus(callId.toStdString()));
+    return convertStringList(DRing::getCallMediaHandlerStatus(callId.toStdString()));
 }
 
 MapStringString
@@ -87,6 +105,19 @@ PluginManagerInterface::getCallMediaHandlerDetails(const QString& mediaHandlerId
     return convertMap(DRing::getCallMediaHandlerDetails(mediaHandlerId.toStdString()));
 }
 
+QStringList
+PluginManagerInterface::getChatHandlerStatus(const QString& accountId, const QString& peerId)
+{
+    return convertStringList(
+        DRing::getChatHandlerStatus(accountId.toStdString(), peerId.toStdString()));
+}
+
+MapStringString
+PluginManagerInterface::getChatHandlerDetails(const QString& chatHandlerId)
+{
+    return convertMap(DRing::getChatHandlerDetails(chatHandlerId.toStdString()));
+}
+
 void
 PluginManagerInterface::setPluginsEnabled(bool enable)
 {
diff --git a/src/qtwrapper/pluginmanagerMock.cpp b/src/qtwrapper/pluginmanagerMock.cpp
index 7363c0af..6a2277d6 100644
--- a/src/qtwrapper/pluginmanagerMock.cpp
+++ b/src/qtwrapper/pluginmanagerMock.cpp
@@ -38,13 +38,13 @@ PluginManagerInterface::getPluginDetails(const QString& path)
 }
 
 QStringList
-PluginManagerInterface::listAvailablePlugins()
+PluginManagerInterface::getInstalledPlugins()
 {
     return {};
 }
 
 QStringList
-PluginManagerInterface::listLoadedPlugins()
+PluginManagerInterface::getLoadedPlugins()
 {
     return {};
 }
@@ -62,7 +62,7 @@ PluginManagerInterface::uninstallPlugin(const QString& pluginRootPath)
 }
 
 QStringList
-PluginManagerInterface::listCallMediaHandlers()
+PluginManagerInterface::getCallMediaHandlers()
 {
     return {};
 }
@@ -73,7 +73,20 @@ PluginManagerInterface::toggleCallMediaHandler(const QString& mediaHandlerId,
                                                bool toggle)
 {}
 
-MapStringVectorString
+QStringList
+PluginManagerInterface::getChatHandlers()
+{
+    return {};
+}
+
+void
+PluginManagerInterface::toggleChatHandler(const QString& chatHandlerId,
+                                          const QString& accountId,
+                                          const QString& peerId,
+                                          bool toggle)
+{}
+
+QStringList
 PluginManagerInterface::getCallMediaHandlerStatus(const QString& callId)
 {
     return {};
@@ -85,6 +98,18 @@ PluginManagerInterface::getCallMediaHandlerDetails(const QString& mediaHandlerId
     return {};
 }
 
+QStringList
+PluginManagerInterface::getChatHandlerStatus(const QString& accountId, const QString& peerId)
+{
+    return {};
+}
+
+MapStringString
+PluginManagerInterface::getChatHandlerDetails(const QString& chatHandlerId)
+{
+    return {};
+}
+
 void
 PluginManagerInterface::setPluginsEnabled(bool enable)
 {}
diff --git a/src/qtwrapper/pluginmanager_wrap.h b/src/qtwrapper/pluginmanager_wrap.h
index e85fb9fc..244cbc1c 100644
--- a/src/qtwrapper/pluginmanager_wrap.h
+++ b/src/qtwrapper/pluginmanager_wrap.h
@@ -50,22 +50,33 @@ public Q_SLOTS: // METHODS
 
     MapStringString getPluginDetails(const QString& path);
 
-    QStringList listAvailablePlugins();
+    QStringList getInstalledPlugins();
 
-    QStringList listLoadedPlugins();
+    QStringList getLoadedPlugins();
 
     int installPlugin(const QString& jplPath, bool force);
 
     int uninstallPlugin(const QString& pluginRootPath);
 
-    QStringList listCallMediaHandlers();
+    QStringList getCallMediaHandlers();
 
     void toggleCallMediaHandler(const QString& mediaHandlerId, const QString& callId, bool toggle);
 
-    MapStringVectorString getCallMediaHandlerStatus(const QString& callId);
+    QStringList getChatHandlers();
+
+    void toggleChatHandler(const QString& chatHandlerId,
+                           const QString& accountId,
+                           const QString& peerId,
+                           bool toggle);
+
+    QStringList getCallMediaHandlerStatus(const QString& callId);
 
     MapStringString getCallMediaHandlerDetails(const QString& mediaHandlerId);
 
+    QStringList getChatHandlerStatus(const QString& accountId, const QString& peerId);
+
+    MapStringString getChatHandlerDetails(const QString& chatHandlerId);
+
     void setPluginsEnabled(bool enable);
 
     bool getPluginsEnabled();
diff --git a/src/web-chatview/chatview.html b/src/web-chatview/chatview.html
index 1bd4d905..e2df4fac 100644
--- a/src/web-chatview/chatview.html
+++ b/src/web-chatview/chatview.html
@@ -43,6 +43,12 @@
                     </svg>
                 </div>
             </div>
+            <div id="pluginsButton" style="display:none" class="nav-button action-button nav-right" onclick="openPluginHandlersList()">
+                <svg class="svgicon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+                    <path d="M0 0h24v24H0V0z" fill="none" />
+                    <path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7s2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/>
+                </svg>
+            </div>
             <div id="addToConversationsButton" class="nav-button action-button nav-right" onclick="addToConversations()">
                 <svg class="svgicon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
                     <path d="M0 0h24v24H0z" fill="none" />
@@ -90,7 +96,8 @@
         <div id="typing_indicator_container"></div>
 
         <div id="back_to_bottom_button_container">
-            <div id="back_to_bottom_button" onclick="back_to_bottom()">Jump to latest &#9660;</div>
+            <div id="back_to_bottom_button" onclick="back_to_bottom()">Jump to latest &#9660;
+</div>
         </div>
         <div id="send_inteface_container" onresize="updateBackToBottomContainer()">
             <div id="sendMessage">
diff --git a/src/web-chatview/chatview.js b/src/web-chatview/chatview.js
index d13ee9bd..3df38f6a 100644
--- a/src/web-chatview/chatview.js
+++ b/src/web-chatview/chatview.js
@@ -34,6 +34,7 @@ const addToConversationsButton = document.getElementById("addToConversationsButt
 const placeAudioCallButton = document.getElementById("placeAudioCallButton")
 const backButton = document.getElementById("backButton")
 const placeCallButton = document.getElementById("placeCallButton")
+const pluginsButton = document.getElementById("pluginsButton")
 const unbanButton = document.getElementById("unbanButton")
 const acceptButton = document.getElementById("acceptButton")
 const refuseButton = document.getElementById("refuseButton")
@@ -165,6 +166,7 @@ function set_titles() {
     if (use_qt){
         backButton.title = i18nStringData["Hide chat view"]
         placeCallButton.title = i18nStringData["Place video call"]
+        pluginsButton.title = i18nStringData["Show available plugins"]
         placeAudioCallButton.title = i18nStringData["Place audio call"]
         addToConversationsButton.title = i18nStringData["Add to conversations"]
         unbanButton.title = i18nStringData["Unban contact"]
@@ -180,6 +182,7 @@ function set_titles() {
     } else {
         backButton.title = i18n.gettext("Hide chat view")
         placeCallButton.title = i18n.gettext("Place video call")
+        pluginsButton.title = i18n.gettext("Show available plugins")
         placeAudioCallButton.title = i18n.gettext("Place audio call")
         addToConversationsButton.title = i18n.gettext("Add to conversations")
         unbanButton.title = i18n.gettext("Unban contact")
@@ -412,6 +415,21 @@ function displayRecordControls(isVisible) {
     }
 }
 
+/**
+ * Hide or show plugin controls, and update body top padding accordingly.
+ *
+ * @param isVisible whether navbar should be displayed or not
+ */
+/* exported displayPluginControl */
+function displayPluginControl(isVisible) {
+    if (isVisible) {
+        pluginsButton.style.removeProperty("display")
+    } else {
+        pluginsButton.style.setProperty("display", "none")
+    }
+}
+
+
 /**
  * Hide or show message bar, and update body bottom padding accordingly.
  *
@@ -579,6 +597,13 @@ function backToWelcomeView() {
     window.prompt("CLOSE_CHATVIEW")
 }
 
+function openPluginHandlersList() {
+    var rect = pluginsButton.getBoundingClientRect()
+    if (!use_qt) {
+        window.prompt(`LIST_PLUGIN_HANDLERS:${rect.left + rect.width / 2}x${rect.bottom}`)
+    }
+}
+
 /**
  * Transform a date to a string group like "1 hour ago".
  *
-- 
GitLab