summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--man/nheko.1.adoc8
-rw-r--r--resources/qml/Completer.qml52
-rw-r--r--resources/qml/MessageInput.qml2
-rw-r--r--src/CombinedImagePackModel.cpp79
-rw-r--r--src/CombinedImagePackModel.h17
-rw-r--r--src/GridImagePackModel.cpp4
-rw-r--r--src/MainWindow.cpp4
-rw-r--r--src/emoji/EmojiModel.cpp78
-rw-r--r--src/emoji/EmojiModel.h40
-rw-r--r--src/emoji/Provider.h2
-rw-r--r--src/timeline/TimelineViewManager.cpp18
12 files changed, 80 insertions, 226 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dad4fb16..b7c02ffb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -356,8 +356,6 @@ set(SRC_FILES
 	src/dialogs/ReCaptcha.h
 
 	# Emoji
-	src/emoji/EmojiModel.cpp
-	src/emoji/EmojiModel.h
 	src/emoji/Provider.cpp
 	src/emoji/Provider.h
 
diff --git a/man/nheko.1.adoc b/man/nheko.1.adoc
index 690ed568..8327a061 100644
--- a/man/nheko.1.adoc
+++ b/man/nheko.1.adoc
@@ -91,11 +91,9 @@ Open username completer.
 Open room completer.
 
 *:*::
-Open unicode emoji picker.
-
-*~*::
-Open custom emoji picker. Requires an image pack with custom emojis. Selecting
-an emoji will add HTML code for the inline image into the input line.
+Open the emoji picker. Unicode emoji are inserted directly. Custom emoji will
+insert the HTML code for them into the input line. You can configure custom
+emoji in the room settings.
 
 == KEYBOARD SHORTCUTS
 
diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml
index cc1047a0..0a9c41ed 100644
--- a/resources/qml/Completer.qml
+++ b/resources/qml/Completer.qml
@@ -21,7 +21,7 @@ Control {
     property int avatarHeight: 24
     property int avatarWidth: 24
     property int rowMargin: 0
-    property int rowSpacing: 5
+    property int rowSpacing: Nheko.paddingSmall
     property alias count: listView.count
 
     signal completionClicked(string completion)
@@ -199,37 +199,32 @@ Control {
                         spacing: rowSpacing
 
                         Label {
+                            visible: !!model.unicode
                             text: model.unicode
                             color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text
                             font: Settings.emojiFont
                         }
 
-                        Label {
-                            text: model.shortName
-                            color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text
+                        Avatar {
+                            visible: !model.unicode
+                            height: popup.avatarHeight
+                            width: popup.avatarWidth
+                            displayName: model.shortcode
+                            //userid: model.shortcode
+                            url: (model.url ? model.url : "").replace("mxc://", "image://MxcImage/")
+                            enabled: false
+                            crop: false
                         }
 
-                    }
-
-                }
-
-                DelegateChoice {
-                    roleValue: "command"
-
-                    RowLayout {
-                        id: del
-
-                        anchors.centerIn: parent
-                        spacing: rowSpacing
-
                         Label {
-                            text: model.name
+                            Layout.leftMargin: Nheko.paddingSmall
+                            Layout.rightMargin: Nheko.paddingSmall
+                            text: model.shortcode
                             color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text
-                            font.bold: true
                         }
 
                         Label {
-                            text: model.description
+                            text: "(" + model.packname + ")"
                             color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.buttonText
                         }
 
@@ -238,7 +233,7 @@ Control {
                 }
 
                 DelegateChoice {
-                    roleValue: "customEmoji"
+                    roleValue: "command"
 
                     RowLayout {
                         id: del
@@ -246,23 +241,14 @@ Control {
                         anchors.centerIn: parent
                         spacing: rowSpacing
 
-                        Avatar {
-                            height: popup.avatarHeight
-                            width: popup.avatarWidth
-                            displayName: model.shortcode
-                            //userid: model.shortcode
-                            url: model.url.replace("mxc://", "image://MxcImage/")
-                            enabled: false
-                            crop: false
-                        }
-
                         Label {
-                            text: model.shortcode
+                            text: model.name
                             color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text
+                            font.bold: true
                         }
 
                         Label {
-                            text: "(" + model.packname + ")"
+                            text: model.description
                             color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.buttonText
                         }
 
diff --git a/resources/qml/MessageInput.qml b/resources/qml/MessageInput.qml
index b810b9f0..8e72f458 100644
--- a/resources/qml/MessageInput.qml
+++ b/resources/qml/MessageInput.qml
@@ -169,8 +169,6 @@ Rectangle {
                         messageInput.openCompleter(selectionStart-1, "emoji");
                     } else if (lastChar == '#') {
                         messageInput.openCompleter(selectionStart-1, "roomAliases");
-                    } else if (lastChar == "~") {
-                        messageInput.openCompleter(selectionStart-1, "customEmoji");
                     } else if (lastChar == "/" && cursorPosition == 1) {
                         messageInput.openCompleter(selectionStart-1, "command");
                     }
diff --git a/src/CombinedImagePackModel.cpp b/src/CombinedImagePackModel.cpp
index 64deaeb9..23fb50f1 100644
--- a/src/CombinedImagePackModel.cpp
+++ b/src/CombinedImagePackModel.cpp
@@ -6,14 +6,13 @@
 
 #include "Cache_p.h"
 #include "CompletionModelRoles.h"
+#include "emoji/Provider.h"
 
-CombinedImagePackModel::CombinedImagePackModel(const std::string &roomId,
-                                               bool stickers,
-                                               QObject *parent)
+CombinedImagePackModel::CombinedImagePackModel(const std::string &roomId, QObject *parent)
   : QAbstractListModel(parent)
   , room_id(roomId)
 {
-    auto packs = cache::client()->getImagePacks(room_id, stickers);
+    auto packs = cache::client()->getImagePacks(room_id, false);
 
     for (const auto &pack : packs) {
         QString packname =
@@ -32,7 +31,7 @@ CombinedImagePackModel::CombinedImagePackModel(const std::string &roomId,
 int
 CombinedImagePackModel::rowCount(const QModelIndex &) const
 {
-    return (int)images.size();
+    return (int)(emoji::Provider::emoji.size() + images.size());
 }
 
 QHash<int, QByteArray>
@@ -46,36 +45,60 @@ CombinedImagePackModel::roleNames() const
       {Roles::ShortCode, "shortcode"},
       {Roles::Body, "body"},
       {Roles::PackName, "packname"},
-      {Roles::OriginalRow, "originalRow"},
+      {Roles::Unicode, "unicode"},
     };
 }
 
 QVariant
 CombinedImagePackModel::data(const QModelIndex &index, int role) const
 {
+    using emoji::Provider;
     if (hasIndex(index.row(), index.column(), index.parent())) {
-        switch (role) {
-        case CompletionModel::CompletionRole:
-            return QStringLiteral(
-                     "<img data-mx-emoticon height=\"32\" src=\"%1\" alt=\"%2\" title=\"%2\">")
-              .arg(QString::fromStdString(images[index.row()].image.url).toHtmlEscaped(),
-                   !images[index.row()].image.body.empty()
-                     ? QString::fromStdString(images[index.row()].image.body)
-                     : images[index.row()].shortcode);
-        case Roles::Url:
-            return QString::fromStdString(images[index.row()].image.url);
-        case CompletionModel::SearchRole:
-        case Roles::ShortCode:
-            return images[index.row()].shortcode;
-        case CompletionModel::SearchRole2:
-        case Roles::Body:
-            return QString::fromStdString(images[index.row()].image.body);
-        case Roles::PackName:
-            return images[index.row()].packname;
-        case Roles::OriginalRow:
-            return index.row();
-        default:
-            return {};
+        if (index.row() < (int)emoji::Provider::emoji.size()) {
+            switch (role) {
+            case CompletionModel::CompletionRole:
+            case Roles::Unicode:
+                return emoji::Provider::emoji[index.row()].unicode();
+
+            case Qt::ToolTipRole:
+                return Provider::emoji[index.row()].shortName() + ", " +
+                       Provider::emoji[index.row()].unicodeName();
+            case CompletionModel::SearchRole2:
+            case Roles::Body:
+                return Provider::emoji[index.row()].unicodeName();
+            case CompletionModel::SearchRole:
+            case Roles::ShortCode:
+                return Provider::emoji[index.row()].shortName();
+            case Roles::PackName:
+                return emoji::categoryToName(Provider::emoji[index.row()].category);
+            default:
+                return {};
+            }
+        } else {
+            int row = index.row() - static_cast<int>(emoji::Provider::emoji.size());
+            switch (role) {
+            case CompletionModel::CompletionRole:
+                return QStringLiteral(
+                         "<img data-mx-emoticon height=\"32\" src=\"%1\" alt=\"%2\" title=\"%2\">")
+                  .arg(QString::fromStdString(images[row].image.url).toHtmlEscaped(),
+                       !images[row].image.body.empty()
+                         ? QString::fromStdString(images[row].image.body)
+                         : images[row].shortcode);
+            case Roles::Url:
+                return QString::fromStdString(images[row].image.url);
+            case CompletionModel::SearchRole:
+            case Roles::ShortCode:
+                return images[row].shortcode;
+            case CompletionModel::SearchRole2:
+            case Roles::Body:
+                return QString::fromStdString(images[row].image.body);
+            case Roles::PackName:
+                return images[row].packname;
+            case Roles::Unicode:
+                return QString();
+            default:
+                return {};
+            }
         }
     }
     return {};
diff --git a/src/CombinedImagePackModel.h b/src/CombinedImagePackModel.h
index 7e89da50..64387390 100644
--- a/src/CombinedImagePackModel.h
+++ b/src/CombinedImagePackModel.h
@@ -18,27 +18,14 @@ public:
         ShortCode,
         Body,
         PackName,
-        OriginalRow,
+        Unicode,
     };
 
-    CombinedImagePackModel(const std::string &roomId, bool stickers, QObject *parent = nullptr);
+    CombinedImagePackModel(const std::string &roomId, QObject *parent = nullptr);
     QHash<int, QByteArray> roleNames() const override;
     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
     QVariant data(const QModelIndex &index, int role) const override;
 
-    mtx::events::msc2545::PackImage imageAt(int row)
-    {
-        if (row < 0 || static_cast<size_t>(row) >= images.size())
-            return {};
-        return images.at(static_cast<size_t>(row)).image;
-    }
-    QString shortcodeAt(int row)
-    {
-        if (row < 0 || static_cast<size_t>(row) >= images.size())
-            return {};
-        return images.at(static_cast<size_t>(row)).shortcode;
-    }
-
 private:
     std::string room_id;
 
diff --git a/src/GridImagePackModel.cpp b/src/GridImagePackModel.cpp
index 469858a1..95cbd265 100644
--- a/src/GridImagePackModel.cpp
+++ b/src/GridImagePackModel.cpp
@@ -18,8 +18,8 @@ Q_DECLARE_METATYPE(TextEmoji)
 Q_DECLARE_METATYPE(SectionDescription)
 Q_DECLARE_METATYPE(QList<SectionDescription>)
 
-static QString
-categoryToName(emoji::Emoji::Category cat)
+QString
+emoji::categoryToName(emoji::Emoji::Category cat)
 {
     switch (cat) {
     case emoji::Emoji::Category::People:
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index d9a03346..a8cc66b7 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -41,7 +41,6 @@
 #include "UsersModel.h"
 #include "Utils.h"
 #include "dock/Dock.h"
-#include "emoji/EmojiModel.h"
 #include "emoji/Provider.h"
 #include "encryption/DeviceVerificationFlow.h"
 #include "encryption/SelfVerificationStatus.h"
@@ -289,9 +288,6 @@ MainWindow::registerQmlTypes()
       "FilteredCommunitiesModel",
       QStringLiteral("Use Communities.filtered() to create a FilteredCommunitiesModel"));
 
-    qmlRegisterType<emoji::EmojiModel>("im.nheko.EmojiModel", 1, 0, "EmojiModel");
-    qmlRegisterUncreatableType<emoji::Emoji>(
-      "im.nheko.EmojiModel", 1, 0, "Emoji", QStringLiteral("Used by emoji models"));
     qmlRegisterUncreatableType<MediaUpload>(
       "im.nheko", 1, 0, "MediaUpload", QStringLiteral("MediaUploads can not be created in Qml"));
     qmlRegisterUncreatableMetaObject(emoji::staticMetaObject,
diff --git a/src/emoji/EmojiModel.cpp b/src/emoji/EmojiModel.cpp
deleted file mode 100644
index 814d17bb..00000000
--- a/src/emoji/EmojiModel.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-// SPDX-FileCopyrightText: Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "EmojiModel.h"
-
-#include <Cache.h>
-#include <MatrixClient.h>
-
-#include "CompletionModelRoles.h"
-
-using namespace emoji;
-
-int
-EmojiModel::categoryToIndex(int category)
-{
-    auto dist = std::distance(
-      Provider::emoji.begin(),
-      std::lower_bound(Provider::emoji.begin(),
-                       Provider::emoji.end(),
-                       static_cast<Emoji::Category>(category),
-                       [](const struct Emoji &e, Emoji::Category c) { return e.category < c; }));
-
-    return static_cast<int>(dist);
-}
-
-QHash<int, QByteArray>
-EmojiModel::roleNames() const
-{
-    static QHash<int, QByteArray> roles;
-
-    if (roles.isEmpty()) {
-        roles                                                   = QAbstractListModel::roleNames();
-        roles[static_cast<int>(EmojiModel::Roles::Unicode)]     = QByteArrayLiteral("unicode");
-        roles[static_cast<int>(EmojiModel::Roles::ShortName)]   = QByteArrayLiteral("shortName");
-        roles[static_cast<int>(EmojiModel::Roles::UnicodeName)] = QByteArrayLiteral("unicodeName");
-        roles[static_cast<int>(EmojiModel::Roles::Category)]    = QByteArrayLiteral("category");
-        roles[static_cast<int>(EmojiModel::Roles::Emoji)]       = QByteArrayLiteral("emoji");
-    }
-
-    return roles;
-}
-
-int
-EmojiModel::rowCount(const QModelIndex &parent) const
-{
-    return parent == QModelIndex() ? (int)Provider::emoji.size() : 0;
-}
-
-QVariant
-EmojiModel::data(const QModelIndex &index, int role) const
-{
-    if (hasIndex(index.row(), index.column(), index.parent())) {
-        switch (role) {
-        case Qt::DisplayRole:
-        case CompletionModel::CompletionRole:
-        case static_cast<int>(EmojiModel::Roles::Unicode):
-            return Provider::emoji[index.row()].unicode();
-
-        case Qt::ToolTipRole:
-            return Provider::emoji[index.row()].shortName() + ", " +
-                   Provider::emoji[index.row()].unicodeName();
-        case CompletionModel::SearchRole2:
-        case static_cast<int>(EmojiModel::Roles::UnicodeName):
-            return Provider::emoji[index.row()].unicodeName();
-        case CompletionModel::SearchRole:
-        case static_cast<int>(EmojiModel::Roles::ShortName):
-            return Provider::emoji[index.row()].shortName();
-        case static_cast<int>(EmojiModel::Roles::Category):
-            return QVariant::fromValue(Provider::emoji[index.row()].category);
-
-        case static_cast<int>(EmojiModel::Roles::Emoji):
-            return QVariant::fromValue(Provider::emoji[index.row()]);
-        }
-    }
-
-    return {};
-}
diff --git a/src/emoji/EmojiModel.h b/src/emoji/EmojiModel.h
deleted file mode 100644
index cb63cbf7..00000000
--- a/src/emoji/EmojiModel.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// SPDX-FileCopyrightText: Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QAbstractListModel>
-#include <QSet>
-#include <QSortFilterProxyModel>
-#include <QVector>
-
-#include "Provider.h"
-
-namespace emoji {
-
-/*
- * Provides access to the emojis in Provider.h to QML
- */
-class EmojiModel : public QAbstractListModel
-{
-    Q_OBJECT
-public:
-    enum Roles
-    {
-        Unicode = Qt::UserRole, // unicode of emoji
-        Category,               // category of emoji
-        ShortName,              // shortext of the emoji
-        UnicodeName,            // true unicode name of the emoji
-        Emoji,                  // Contains everything from the Emoji
-    };
-
-    using QAbstractListModel::QAbstractListModel;
-
-    Q_INVOKABLE int categoryToIndex(int category);
-
-    QHash<int, QByteArray> roleNames() const override;
-    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
-};
-}
diff --git a/src/emoji/Provider.h b/src/emoji/Provider.h
index f8c74b08..5d8000a4 100644
--- a/src/emoji/Provider.h
+++ b/src/emoji/Provider.h
@@ -91,5 +91,7 @@ public:
     static const std::array<Emoji, 3681> emoji;
 };
 
+QString
+categoryToName(emoji::Emoji::Category cat);
 } // namespace emoji
 Q_DECLARE_METATYPE(emoji::Emoji)
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 4b6a791f..e062dde2 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -27,7 +27,6 @@
 #include "UserSettingsPage.h"
 #include "UsersModel.h"
 #include "Utils.h"
-#include "emoji/EmojiModel.h"
 #include "encryption/VerificationManager.h"
 #include "voip/CallManager.h"
 #include "voip/WebRTCSession.h"
@@ -454,15 +453,10 @@ TimelineViewManager::completerFor(const QString &completerName, const QString &r
         userModel->setParent(proxy);
         return proxy;
     } else if (completerName == QLatin1String("emoji")) {
-        auto emojiModel = new emoji::EmojiModel();
+        auto emojiModel = new CombinedImagePackModel(roomId.toStdString());
         auto proxy      = new CompletionProxyModel(emojiModel);
         emojiModel->setParent(proxy);
         return proxy;
-    } else if (completerName == QLatin1String("allemoji")) {
-        auto emojiModel = new emoji::EmojiModel();
-        auto proxy      = new CompletionProxyModel(emojiModel, 1, static_cast<size_t>(-1) / 4);
-        emojiModel->setParent(proxy);
-        return proxy;
     } else if (completerName == QLatin1String("room")) {
         auto roomModel = new RoomsModel(false);
         auto proxy     = new CompletionProxyModel(roomModel, 4);
@@ -473,22 +467,12 @@ TimelineViewManager::completerFor(const QString &completerName, const QString &r
         auto proxy     = new CompletionProxyModel(roomModel);
         roomModel->setParent(proxy);
         return proxy;
-    } else if (completerName == QLatin1String("stickers")) {
-        auto stickerModel = new CombinedImagePackModel(roomId.toStdString(), true);
-        auto proxy        = new CompletionProxyModel(stickerModel, 1, static_cast<size_t>(-1) / 4);
-        stickerModel->setParent(proxy);
-        return proxy;
     } else if (completerName == QLatin1String("emojigrid")) {
         auto stickerModel = new GridImagePackModel(roomId.toStdString(), false);
         return stickerModel;
     } else if (completerName == QLatin1String("stickergrid")) {
         auto stickerModel = new GridImagePackModel(roomId.toStdString(), true);
         return stickerModel;
-    } else if (completerName == QLatin1String("customEmoji")) {
-        auto stickerModel = new CombinedImagePackModel(roomId.toStdString(), false);
-        auto proxy        = new CompletionProxyModel(stickerModel);
-        stickerModel->setParent(proxy);
-        return proxy;
     } else if (completerName == QLatin1String("command")) {
         auto commandCompleter = new CommandCompleter();
         auto proxy            = new CompletionProxyModel(commandCompleter);