mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-24 12:08:50 +03:00
Make default completer complete custom emoji
This commit is contained in:
parent
dd74bdc697
commit
51084748ee
12 changed files with 82 additions and 228 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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,37 +45,61 @@ 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())) {
|
||||
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[index.row()].image.url).toHtmlEscaped(),
|
||||
!images[index.row()].image.body.empty()
|
||||
? QString::fromStdString(images[index.row()].image.body)
|
||||
: images[index.row()].shortcode);
|
||||
.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[index.row()].image.url);
|
||||
return QString::fromStdString(images[row].image.url);
|
||||
case CompletionModel::SearchRole:
|
||||
case Roles::ShortCode:
|
||||
return images[index.row()].shortcode;
|
||||
return images[row].shortcode;
|
||||
case CompletionModel::SearchRole2:
|
||||
case Roles::Body:
|
||||
return QString::fromStdString(images[index.row()].image.body);
|
||||
return QString::fromStdString(images[row].image.body);
|
||||
case Roles::PackName:
|
||||
return images[index.row()].packname;
|
||||
case Roles::OriginalRow:
|
||||
return index.row();
|
||||
return images[row].packname;
|
||||
case Roles::Unicode:
|
||||
return QString();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue