From 51084748ee4db5f7faab996147a85132cbb80031 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 25 May 2023 21:50:54 +0200 Subject: [PATCH] Make default completer complete custom emoji --- CMakeLists.txt | 2 - man/nheko.1.adoc | 8 ++- resources/qml/Completer.qml | 56 ++++++++------------ resources/qml/MessageInput.qml | 2 - src/CombinedImagePackModel.cpp | 79 ++++++++++++++++++---------- src/CombinedImagePackModel.h | 17 +----- src/GridImagePackModel.cpp | 4 +- src/MainWindow.cpp | 4 -- src/emoji/EmojiModel.cpp | 78 --------------------------- src/emoji/EmojiModel.h | 40 -------------- src/emoji/Provider.h | 2 + src/timeline/TimelineViewManager.cpp | 18 +------ 12 files changed, 82 insertions(+), 228 deletions(-) delete mode 100644 src/emoji/EmojiModel.cpp delete mode 100644 src/emoji/EmojiModel.h 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,16 +199,35 @@ Control { spacing: rowSpacing Label { + visible: !!model.unicode text: model.unicode color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text font: Settings.emojiFont } + 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 + } + Label { - text: model.shortName + Layout.leftMargin: Nheko.paddingSmall + Layout.rightMargin: Nheko.paddingSmall + text: model.shortcode color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text } + Label { + text: "(" + model.packname + ")" + color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.buttonText + } + } } @@ -237,39 +256,6 @@ Control { } - DelegateChoice { - roleValue: "customEmoji" - - RowLayout { - id: del - - 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 - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text - } - - Label { - text: "(" + model.packname + ")" - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.buttonText - } - - } - - } - DelegateChoice { roleValue: "room" 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 @@ -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( - "\"%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(emoji::Provider::emoji.size()); + switch (role) { + case CompletionModel::CompletionRole: + return QStringLiteral( + "\"%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 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(row) >= images.size()) - return {}; - return images.at(static_cast(row)).image; - } - QString shortcodeAt(int row) - { - if (row < 0 || static_cast(row) >= images.size()) - return {}; - return images.at(static_cast(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) -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("im.nheko.EmojiModel", 1, 0, "EmojiModel"); - qmlRegisterUncreatableType( - "im.nheko.EmojiModel", 1, 0, "Emoji", QStringLiteral("Used by emoji models")); qmlRegisterUncreatableType( "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 -#include - -#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(category), - [](const struct Emoji &e, Emoji::Category c) { return e.category < c; })); - - return static_cast(dist); -} - -QHash -EmojiModel::roleNames() const -{ - static QHash roles; - - if (roles.isEmpty()) { - roles = QAbstractListModel::roleNames(); - roles[static_cast(EmojiModel::Roles::Unicode)] = QByteArrayLiteral("unicode"); - roles[static_cast(EmojiModel::Roles::ShortName)] = QByteArrayLiteral("shortName"); - roles[static_cast(EmojiModel::Roles::UnicodeName)] = QByteArrayLiteral("unicodeName"); - roles[static_cast(EmojiModel::Roles::Category)] = QByteArrayLiteral("category"); - roles[static_cast(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(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(EmojiModel::Roles::UnicodeName): - return Provider::emoji[index.row()].unicodeName(); - case CompletionModel::SearchRole: - case static_cast(EmojiModel::Roles::ShortName): - return Provider::emoji[index.row()].shortName(); - case static_cast(EmojiModel::Roles::Category): - return QVariant::fromValue(Provider::emoji[index.row()].category); - - case static_cast(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 -#include -#include -#include - -#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 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; }; +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(-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(-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);