summary refs log tree commit diff
diff options
context:
space:
mode:
authorLoren Burkholder <computersemiexpert@outlook.com>2020-12-25 09:14:00 -0500
committerLoren Burkholder <computersemiexpert@outlook.com>2021-09-11 19:35:31 -0400
commitd2e193ff78c491f7108476b00340aea97f4feed3 (patch)
tree18fe17ffd6f1ad667b54fbc09d424658b25fb54c
parentMerge pull request #722 from Thulinma/noHtmlFixes (diff)
downloadnheko-d2e193ff78c491f7108476b00340aea97f4feed3.tar.xz
Add jdenticon support
-rw-r--r--CMakeLists.txt2
-rw-r--r--resources/qml/Avatar.qml9
-rw-r--r--src/JdenticonProvider.cpp68
-rw-r--r--src/JdenticonProvider.h59
-rw-r--r--src/MainWindow.cpp28
-rw-r--r--src/MainWindow.h2
-rw-r--r--src/UserSettingsPage.cpp23
-rw-r--r--src/UserSettingsPage.h8
-rw-r--r--src/timeline/TimelineViewManager.cpp3
-rw-r--r--src/timeline/TimelineViewManager.h2
-rw-r--r--src/ui/Theme.h3
11 files changed, 176 insertions, 31 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 20ef5cab..1b6c08b7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -345,6 +345,7 @@ set(SRC_FILES
 	src/DeviceVerificationFlow.cpp
 	src/EventAccessors.cpp
 	src/InviteesModel.cpp
+	src/JdenticonProvider.cpp
 	src/Logging.cpp
 	src/LoginPage.cpp
 	src/MainWindow.cpp
@@ -557,6 +558,7 @@ qt5_wrap_cpp(MOC_HEADERS
 	src/DeviceVerificationFlow.h
 	src/ImagePackListModel.h
 	src/InviteesModel.h
+	src/JdenticonProvider.h
 	src/LoginPage.h
 	src/MainWindow.h
 	src/MemberList.h
diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml
index ab067eee..7bbdeba3 100644
--- a/resources/qml/Avatar.qml
+++ b/resources/qml/Avatar.qml
@@ -35,11 +35,18 @@ Rectangle {
         font.pixelSize: avatar.height / 2
         verticalAlignment: Text.AlignVCenter
         horizontalAlignment: Text.AlignHCenter
-        visible: img.status != Image.Ready
+        visible: img.status != Image.Ready && !Settings.useIdenticon
         color: Nheko.colors.text
     }
 
     Image {
+        id: identicon
+        anchors.fill: parent
+        visible: img.status != Image.Ready && Settings.useIdenticon
+        source: "image://jdenticon/" + userid
+    }
+
+    Image {
         id: img
 
         anchors.fill: parent
diff --git a/src/JdenticonProvider.cpp b/src/JdenticonProvider.cpp
new file mode 100644
index 00000000..4be972dc
--- /dev/null
+++ b/src/JdenticonProvider.cpp
@@ -0,0 +1,68 @@
+#include "JdenticonProvider.h"
+
+#include <QApplication>
+#include <QDir>
+#include <QPainter>
+#include <QPluginLoader>
+#include <QSvgRenderer>
+
+#include <mtxclient/crypto/client.hpp>
+
+#include "Cache.h"
+#include "Logging.h"
+#include "MatrixClient.h"
+#include "Utils.h"
+#include "jdenticoninterface.h"
+
+JdenticonResponse::JdenticonResponse(const QString &key, const QSize &requestedSize)
+  : m_key(key)
+  , m_requestedSize(requestedSize.isValid() ? requestedSize : QSize(100, 100))
+  , m_pixmap{m_requestedSize}
+  , jdenticonInterface_{Jdenticon::getJdenticonInterface()}
+{
+        setAutoDelete(false);
+}
+
+void
+JdenticonResponse::run()
+{
+        m_pixmap.fill(Qt::transparent);
+        QPainter painter{&m_pixmap};
+        QSvgRenderer renderer{
+          jdenticonInterface_->generate(m_key, m_requestedSize.width()).toUtf8()};
+        //        m_image = QImage::fromData(jdenticonInterface_->generate(m_key,
+        //        size->width()).toUtf8());
+        renderer.render(&painter);
+
+        emit finished();
+}
+
+namespace Jdenticon {
+JdenticonInterface *
+getJdenticonInterface()
+{
+        static JdenticonInterface *interface = nullptr;
+
+        if (interface == nullptr) {
+                QDir pluginsDir(qApp->applicationDirPath());
+
+                bool plugins = pluginsDir.cd("plugins");
+                if (plugins) {
+                        for (QString fileName : pluginsDir.entryList(QDir::Files)) {
+                                QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
+                                QObject *plugin = pluginLoader.instance();
+                                if (plugin) {
+                                        interface = qobject_cast<JdenticonInterface *>(plugin);
+                                        if (interface) {
+                                                nhlog::ui()->info("Loaded jdenticon plugin.");
+                                                break;
+                                        }
+                                }
+                        }
+                } else
+                        nhlog::ui()->info("jdenticon plugin not found.");
+        }
+
+        return interface;
+}
+}
diff --git a/src/JdenticonProvider.h b/src/JdenticonProvider.h
new file mode 100644
index 00000000..053842bb
--- /dev/null
+++ b/src/JdenticonProvider.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <QImage>
+#include <QQuickAsyncImageProvider>
+#include <QQuickImageResponse>
+#include <QThreadPool>
+
+#include <mtx/common.hpp>
+
+#include <boost/optional.hpp>
+
+#include "jdenticoninterface.h"
+
+namespace Jdenticon {
+JdenticonInterface *
+getJdenticonInterface();
+}
+
+class JdenticonResponse
+  : public QQuickImageResponse
+  , public QRunnable
+{
+public:
+        JdenticonResponse(const QString &key, const QSize &requestedSize);
+
+        QQuickTextureFactory *textureFactory() const override
+        {
+                return QQuickTextureFactory::textureFactoryForImage(m_pixmap.toImage());
+        }
+
+        void run() override;
+
+        QString m_key;
+        QSize m_requestedSize;
+        QPixmap m_pixmap;
+        JdenticonInterface *jdenticonInterface_ = nullptr;
+};
+
+class JdenticonProvider
+  : public QObject
+  , public QQuickAsyncImageProvider
+{
+        Q_OBJECT
+
+public:
+        static bool isAvailable() { return Jdenticon::getJdenticonInterface() != nullptr; }
+
+public slots:
+        QQuickImageResponse *requestImageResponse(const QString &key,
+                                                  const QSize &requestedSize) override
+        {
+                JdenticonResponse *response = new JdenticonResponse(key, requestedSize);
+                pool.start(response);
+                return response;
+        }
+
+private:
+        QThreadPool pool;
+};
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index 7eadc6df..b423304f 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -16,6 +16,7 @@
 #include "Cache_p.h"
 #include "ChatPage.h"
 #include "Config.h"
+#include "JdenticonProvider.h"
 #include "Logging.h"
 #include "LoginPage.h"
 #include "MainWindow.h"
@@ -152,10 +153,6 @@ MainWindow::MainWindow(QWidget *parent)
                         showChatPage();
                 }
         });
-
-        if (loadJdenticonPlugin()) {
-                nhlog::ui()->info("loaded jdenticon.");
-        }
 }
 
 void
@@ -428,29 +425,6 @@ MainWindow::showDialog(QWidget *dialog)
         dialog->show();
 }
 
-bool
-MainWindow::loadJdenticonPlugin()
-{
-        QDir pluginsDir(qApp->applicationDirPath());
-
-        bool plugins = pluginsDir.cd("plugins");
-        if (plugins) {
-                foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
-                        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
-                        QObject *plugin = pluginLoader.instance();
-                        if (plugin) {
-                                jdenticonInteface_ = qobject_cast<JdenticonInterface *>(plugin);
-                                if (jdenticonInteface_) {
-                                        nhlog::ui()->info("Found jdenticon plugin.");
-                                        return true;
-                                }
-                        }
-                }
-        }
-
-        nhlog::ui()->info("jdenticon plugin not found.");
-        return false;
-}
 void
 MainWindow::showWelcomePage()
 {
diff --git a/src/MainWindow.h b/src/MainWindow.h
index d423af9f..18bcfe3d 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -137,6 +137,4 @@ private:
         //! Overlay modal used to project other widgets.
         OverlayModal *modal_       = nullptr;
         LoadingIndicator *spinner_ = nullptr;
-
-        JdenticonInterface *jdenticonInteface_ = nullptr;
 };
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index af32344c..bfe5232b 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -86,6 +86,7 @@ UserSettings::load(std::optional<QString> profile)
         theme_                = settings.value("user/theme", defaultTheme_).toString();
         font_                 = settings.value("user/font_family", "default").toString();
         avatarCircles_        = settings.value("user/avatar_circles", true).toBool();
+        useIdenticon_         = settings.value("user/use_identicon", true).toBool();
         decryptSidebar_       = settings.value("user/decrypt_sidebar", true).toBool();
         privacyScreen_        = settings.value("user/privacy_screen", false).toBool();
         privacyScreenTimeout_ = settings.value("user/privacy_screen_timeout", 0).toInt();
@@ -596,6 +597,15 @@ UserSettings::setDisableCertificateValidation(bool disabled)
         disableCertificateValidation_ = disabled;
         http::client()->verify_certificates(!disabled);
         emit disableCertificateValidationChanged(disabled);
+}
+
+void
+UserSettings::setUseIdenticon(bool state)
+{
+        if (state == useIdenticon_)
+                return;
+        useIdenticon_ = state;
+        emit useIdenticonChanged(useIdenticon_);
         save();
 }
 
@@ -674,6 +684,7 @@ UserSettings::save()
         settings.setValue("screen_share_hide_cursor", screenShareHideCursor_);
         settings.setValue("use_stun_server", useStunServer_);
         settings.setValue("currentProfile", profile_);
+        settings.setValue("use_identicon", useIdenticon_);
 
         settings.endGroup(); // user
 
@@ -746,6 +757,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
         trayToggle_                     = new Toggle{this};
         startInTrayToggle_              = new Toggle{this};
         avatarCircles_                  = new Toggle{this};
+        useIdenticon_                   = new Toggle{this};
         decryptSidebar_                 = new Toggle(this);
         privacyScreen_                  = new Toggle{this};
         onlyShareKeysWithVerifiedUsers_ = new Toggle(this);
@@ -779,6 +791,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
         trayToggle_->setChecked(settings_->tray());
         startInTrayToggle_->setChecked(settings_->startInTray());
         avatarCircles_->setChecked(settings_->avatarCircles());
+        useIdenticon_->setChecked(settings_->useIdenticon());
         decryptSidebar_->setChecked(settings_->decryptSidebar());
         privacyScreen_->setChecked(settings_->privacyScreen());
         onlyShareKeysWithVerifiedUsers_->setChecked(settings_->onlyShareKeysWithVerifiedUsers());
@@ -941,6 +954,12 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
         boxWrap(tr("Circular Avatars"),
                 avatarCircles_,
                 tr("Change the appearance of user avatars in chats.\nOFF - square, ON - Circle."));
+        if (JdenticonProvider::isAvailable())
+                boxWrap(
+                  tr("Use identicons"),
+                  useIdenticon_,
+                  tr(
+                    "Display an identicon instead of a letter when a user has not set an avatar."));
         boxWrap(tr("Group's sidebar"),
                 groupViewToggle_,
                 tr("Show a column containing groups and tags next to the room list."));
@@ -1263,6 +1282,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
                 settings_->setAvatarCircles(enabled);
         });
 
+        connect(useIdenticon_, &Toggle::toggled, this, [this](bool enabled) {
+                settings_->setUseIdenticon(enabled);
+        });
+
         connect(markdown_, &Toggle::toggled, this, [this](bool enabled) {
                 settings_->setMarkdown(enabled);
         });
diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h
index 93b53211..bcd9439b 100644
--- a/src/UserSettingsPage.h
+++ b/src/UserSettingsPage.h
@@ -12,6 +12,7 @@
 #include <QSharedPointer>
 #include <QWidget>
 
+#include "JdenticonProvider.h"
 #include <optional>
 
 class Toggle;
@@ -105,6 +106,8 @@ class UserSettings : public QObject
         Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
         Q_PROPERTY(bool disableCertificateValidation READ disableCertificateValidation WRITE
                      setDisableCertificateValidation NOTIFY disableCertificateValidationChanged)
+        Q_PROPERTY(
+          bool useIdenticon READ useIdenticon WRITE setUseIdenticon NOTIFY useIdenticonChanged)
 
         UserSettings();
 
@@ -172,6 +175,7 @@ public:
         void setHomeserver(QString homeserver);
         void setDisableCertificateValidation(bool disabled);
         void setHiddenTags(QStringList hiddenTags);
+        void setUseIdenticon(bool state);
 
         QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; }
         bool messageHoverHighlight() const { return messageHoverHighlight_; }
@@ -230,6 +234,7 @@ public:
         QString homeserver() const { return homeserver_; }
         bool disableCertificateValidation() const { return disableCertificateValidation_; }
         QStringList hiddenTags() const { return hiddenTags_; }
+        bool useIdenticon() const { return useIdenticon_ && JdenticonProvider::isAvailable(); }
 
 signals:
         void groupViewStateChanged(bool state);
@@ -277,6 +282,7 @@ signals:
         void deviceIdChanged(QString deviceId);
         void homeserverChanged(QString homeserver);
         void disableCertificateValidationChanged(bool disabled);
+        void useIdenticonChanged(bool state);
 
 private:
         // Default to system theme if QT_QPA_PLATFORMTHEME var is set.
@@ -330,6 +336,7 @@ private:
         QString deviceId_;
         QString homeserver_;
         QStringList hiddenTags_;
+        bool useIdenticon_;
 
         QSettings settings;
 
@@ -391,6 +398,7 @@ private:
         Toggle *desktopNotifications_;
         Toggle *alertOnNotification_;
         Toggle *avatarCircles_;
+        Toggle *useIdenticon_;
         Toggle *useStunServer_;
         Toggle *decryptSidebar_;
         Toggle *privacyScreen_;
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 681cbe09..ea231b03 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -141,6 +141,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
   , imgProvider(new MxcImageProvider())
   , colorImgProvider(new ColorImageProvider())
   , blurhashProvider(new BlurhashProvider())
+  , jdenticonProvider(new JdenticonProvider())
   , callManager_(callManager)
   , rooms_(new RoomlistModel(this))
   , communities_(new CommunitiesModel(this))
@@ -310,6 +311,8 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
         view->engine()->addImageProvider("MxcImage", imgProvider);
         view->engine()->addImageProvider("colorimage", colorImgProvider);
         view->engine()->addImageProvider("blurhash", blurhashProvider);
+        if (JdenticonProvider::isAvailable())
+                view->engine()->addImageProvider("jdenticon", jdenticonProvider);
         view->setSource(QUrl("qrc:///qml/Root.qml"));
 
         connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette);
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 4dd5e996..8991de55 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -18,6 +18,7 @@
 
 #include "Cache.h"
 #include "CallManager.h"
+#include "JdenticonProvider.h"
 #include "Logging.h"
 #include "TimelineModel.h"
 #include "Utils.h"
@@ -141,6 +142,7 @@ private:
         MxcImageProvider *imgProvider;
         ColorImageProvider *colorImgProvider;
         BlurhashProvider *blurhashProvider;
+        JdenticonProvider *jdenticonProvider;
 
         CallManager *callManager_ = nullptr;
 
diff --git a/src/ui/Theme.h b/src/ui/Theme.h
index b5bcd4dd..254fbadf 100644
--- a/src/ui/Theme.h
+++ b/src/ui/Theme.h
@@ -11,7 +11,8 @@ namespace ui {
 enum class AvatarType
 {
         Image,
-        Letter
+        Letter,
+        Jdenticon
 };
 
 // Default font size.