Reimplement normal emoji completion

BUG: 460632
This commit is contained in:
Tobias Fella
2022-11-26 02:41:50 +01:00
parent f27b64edef
commit dd0300d025
10 changed files with 40 additions and 13 deletions

View File

@@ -49,7 +49,7 @@ set_package_properties(Qt${QT_MAJOR_VERSION} PROPERTIES
TYPE REQUIRED TYPE REQUIRED
PURPOSE "Basic application components" PURPOSE "Basic application components"
) )
find_package(KF5 ${KF5_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet) find_package(KF5 ${KF5_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
set_package_properties(KF5 PROPERTIES set_package_properties(KF5 PROPERTIES
TYPE REQUIRED TYPE REQUIRED
PURPOSE "Basic application components" PURPOSE "Basic application components"

View File

@@ -90,7 +90,7 @@ else()
endif() endif()
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR}) target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR})
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF5::I18n KF5::Kirigami2 KF5::Notifications KF5::ConfigCore KF5::ConfigGui KF5::CoreAddons KF5::SonnetCore Quotient cmark::cmark ${QTKEYCHAIN_LIBRARIES}) target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF5::I18n KF5::Kirigami2 KF5::Notifications KF5::ConfigCore KF5::ConfigGui KF5::CoreAddons KF5::SonnetCore KF5::ItemModels Quotient cmark::cmark ${QTKEYCHAIN_LIBRARIES})
if(TARGET QCoro5::Coro) if(TARGET QCoro5::Coro)
target_link_libraries(neochat PUBLIC QCoro5::Coro) target_link_libraries(neochat PUBLIC QCoro5::Coro)
else() else()

View File

@@ -235,7 +235,7 @@ void ChatDocumentHandler::complete(int index)
m_room->mentions()->push_back({cursor, alias, 0, 0, alias}); m_room->mentions()->push_back({cursor, alias, 0, 0, alias});
m_highlighter->rehighlight(); m_highlighter->rehighlight();
} else if (m_completionModel->autoCompletionType() == ChatDocumentHandler::Emoji) { } else if (m_completionModel->autoCompletionType() == ChatDocumentHandler::Emoji) {
auto shortcode = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Text).toString(); auto shortcode = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
auto text = m_room->chatBoxText(); auto text = m_room->chatBoxText();
auto at = text.lastIndexOf(QLatin1Char(':')); auto at = text.lastIndexOf(QLatin1Char(':'));
QTextCursor cursor(document()->textDocument()); QTextCursor cursor(document()->textDocument());

View File

@@ -8,6 +8,7 @@
#include "chatdocumenthandler.h" #include "chatdocumenthandler.h"
#include "completionproxymodel.h" #include "completionproxymodel.h"
#include "customemojimodel.h" #include "customemojimodel.h"
#include "emojimodel.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "roomlistmodel.h" #include "roomlistmodel.h"
#include "userlistmodel.h" #include "userlistmodel.h"
@@ -16,11 +17,14 @@ CompletionModel::CompletionModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_filterModel(new CompletionProxyModel()) , m_filterModel(new CompletionProxyModel())
, m_userListModel(new UserListModel(this)) , m_userListModel(new UserListModel(this))
, m_emojiModel(new KConcatenateRowsProxyModel(this))
{ {
connect(this, &CompletionModel::textChanged, this, &CompletionModel::updateCompletion); connect(this, &CompletionModel::textChanged, this, &CompletionModel::updateCompletion);
connect(this, &CompletionModel::roomChanged, this, [this]() { connect(this, &CompletionModel::roomChanged, this, [this]() {
m_userListModel->setRoom(m_room); m_userListModel->setRoom(m_room);
}); });
m_emojiModel->addSourceModel(&CustomEmojiModel::instance());
m_emojiModel->addSourceModel(&EmojiModel::instance());
} }
QString CompletionModel::text() const QString CompletionModel::text() const
@@ -90,11 +94,14 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
} }
if (m_autoCompletionType == ChatDocumentHandler::Emoji) { if (m_autoCompletionType == ChatDocumentHandler::Emoji) {
if (role == Text) { if (role == Text) {
return m_filterModel->data(filterIndex, CustomEmojiModel::Name); return m_filterModel->data(filterIndex, CustomEmojiModel::DisplayRole);
} }
if (role == Icon) { if (role == Icon) {
return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl); return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl);
} }
if (role == ReplacedText) {
return m_filterModel->data(filterIndex, CustomEmojiModel::ReplacedTextRole);
}
} }
return {}; return {};
@@ -140,7 +147,7 @@ void CompletionModel::updateCompletion()
&& (m_fullText.indexOf(QLatin1Char(':'), 1) == -1 && (m_fullText.indexOf(QLatin1Char(':'), 1) == -1
|| (m_fullText.indexOf(QLatin1Char(' ')) != -1 && m_fullText.indexOf(QLatin1Char(':'), 1) > m_fullText.indexOf(QLatin1Char(' '), 1)))) { || (m_fullText.indexOf(QLatin1Char(' ')) != -1 && m_fullText.indexOf(QLatin1Char(':'), 1) > m_fullText.indexOf(QLatin1Char(' '), 1)))) {
m_autoCompletionType = ChatDocumentHandler::Emoji; m_autoCompletionType = ChatDocumentHandler::Emoji;
m_filterModel->setSourceModel(&CustomEmojiModel::instance()); m_filterModel->setSourceModel(m_emojiModel);
m_filterModel->setFilterRole(CustomEmojiModel::Name); m_filterModel->setFilterRole(CustomEmojiModel::Name);
m_filterModel->setSecondaryFilterRole(-1); m_filterModel->setSecondaryFilterRole(-1);
m_filterModel->setFullText(m_fullText); m_filterModel->setFullText(m_fullText);

View File

@@ -5,6 +5,8 @@
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <KConcatenateRowsProxyModel>
#include "chatdocumenthandler.h" #include "chatdocumenthandler.h"
class CompletionProxyModel; class CompletionProxyModel;
@@ -64,4 +66,5 @@ private:
UserListModel *m_userListModel; UserListModel *m_userListModel;
RoomListModel *m_roomListModel; RoomListModel *m_roomListModel;
KConcatenateRowsProxyModel *m_emojiModel;
}; };

View File

@@ -134,6 +134,8 @@ QVariant CustomEmojiModel::data(const QModelIndex &idx, int role) const
case Roles::ModelData: case Roles::ModelData:
return QVariant::fromValue(Emoji(QStringLiteral("image://mxc/") + data.url.mid(6), data.name, true)); return QVariant::fromValue(Emoji(QStringLiteral("image://mxc/") + data.url.mid(6), data.name, true));
case Roles::Name: case Roles::Name:
case Roles::DisplayRole:
case Roles::ReplacedTextRole:
return data.name; return data.name;
case Roles::ImageURL: case Roles::ImageURL:
return QUrl(QStringLiteral("image://mxc/") + data.url.mid(6)); return QUrl(QStringLiteral("image://mxc/") + data.url.mid(6));

View File

@@ -19,10 +19,12 @@ class CustomEmojiModel : public QAbstractListModel
public: public:
enum Roles { enum Roles {
Name, Name = Qt::DisplayRole,
ImageURL, ImageURL,
ModelData, // for emulating the regular emoji model's usage, otherwise the UI code would get too complicated ModelData, // for emulating the regular emoji model's usage, otherwise the UI code would get too complicated
MxcUrl, MxcUrl = 50,
DisplayRole = 51,
ReplacedTextRole = 52,
}; };
Q_ENUM(Roles); Q_ENUM(Roles);

View File

@@ -39,10 +39,15 @@ QVariant EmojiModel::data(const QModelIndex &index, int role) const
} }
auto emoji = category[row].value<Emoji>(); auto emoji = category[row].value<Emoji>();
switch (role) { switch (role) {
case TextRole: case ShortNameRole:
return emoji.shortName; return QStringLiteral(":%1:").arg(emoji.shortName);
case UnicodeRole: case UnicodeRole:
case ReplacedTextRole:
return emoji.unicode; return emoji.unicode;
case InvalidRole:
return QStringLiteral("invalid");
case DisplayRole:
return QStringLiteral("%2 :%1:").arg(emoji.shortName, emoji.unicode);
} }
} }
return {}; return {};
@@ -50,7 +55,7 @@ QVariant EmojiModel::data(const QModelIndex &index, int role) const
QHash<int, QByteArray> EmojiModel::roleNames() const QHash<int, QByteArray> EmojiModel::roleNames() const
{ {
return {{TextRole, "text"}, {UnicodeRole, "unicode"}}; return {{ShortNameRole, "shortName"}, {UnicodeRole, "unicode"}};
} }
QMultiHash<QString, QVariant> EmojiModel::_tones = { QMultiHash<QString, QVariant> EmojiModel::_tones = {

View File

@@ -51,11 +51,18 @@ class EmojiModel : public QAbstractListModel
Q_PROPERTY(QVariantList categories READ categories CONSTANT) Q_PROPERTY(QVariantList categories READ categories CONSTANT)
public: public:
explicit EmojiModel(QObject *parent = nullptr); static EmojiModel &instance()
{
static EmojiModel _instance;
return _instance;
}
enum RoleNames { enum RoleNames {
TextRole = Qt::DisplayRole, ShortNameRole = Qt::DisplayRole,
UnicodeRole, UnicodeRole,
InvalidRole = 50,
DisplayRole = 51,
ReplacedTextRole = 52,
}; };
Q_ENUM(RoleNames); Q_ENUM(RoleNames);
@@ -100,4 +107,5 @@ private:
// TODO: Port away from QSettings // TODO: Port away from QSettings
QSettings m_settings; QSettings m_settings;
EmojiModel(QObject *parent = nullptr);
}; };

View File

@@ -203,7 +203,7 @@ int main(int argc, char *argv[])
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "FileType", &fileTypeSingleton); qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "FileType", &fileTypeSingleton);
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "LoginHelper", login); qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "LoginHelper", login);
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "UrlHelper", &urlHelper); qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "UrlHelper", &urlHelper);
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "EmojiModel", new EmojiModel(&app)); qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "EmojiModel", &EmojiModel::instance());
#ifdef QUOTIENT_07 #ifdef QUOTIENT_07
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "AccountRegistry", &Quotient::Accounts); qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "AccountRegistry", &Quotient::Accounts);
#else #else