Refactor input stuff
This is the start of a significant refactoring of everything related to sending messages, which is roughly:
- the chatbox
- action handling
- message sending on the c++ side
- autocompletion of users/rooms/emojis/commands/things i forgot
Notable changes so far include:
- ChatBox is now a ColumnLayout. As part of this, i removed the height animations for now. <del>as far as i can tell, they were broken anyway.</del> I'll readd them later
- Actions were refactored to live outside of the message sending function and are now each an object; it's mostly a wrapper around a function that is executed when the action is invoked
- Everything that used to live in ChatBoxHelper is now in NeoChatRoom; that means that the exact input status (text, message being replied to, message being edited, attachment) is now saved between room switching).
- To edit/reply an event, set `NeoChatRoom::chatBox{edit,reply}Id` to the desired event id, `NeoChatRoom::chatBox{reply,edit}{User,Message}` will then be updated automatically
- Attachments behave equivalently with `NeoChatRoom::chatBoxAttachmentPath`
- Error message reporting from ActionsHandler has been fixed (same fix as in !517) and moved to NeoChatRoom
Broken at the moment:
- [x] Any kind of autocompletion
- [x] Mentions
- [x] Fancy effects
- [x] sed-style edits
- [x] last-user-message edits and replies
- [x] Some of the actions, probably
- [x] Replies from notifications
- [x] Lots of keyboard shortcuts
- [x] Custom emojis
- [x] ChatBox height animations
TODO:
- [x] User / room mentions based on QTextCursors instead of the hack we currently use
- [x] Refactor autocompletion stuff
- [x] ???
- [x] Profit
This commit is contained in:
@@ -1,48 +1,39 @@
|
||||
// SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "customemojimodel_p.h"
|
||||
#include "customemojimodel.h"
|
||||
#include "controller.h"
|
||||
#include "emojimodel.h"
|
||||
|
||||
#include <connection.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
enum Roles {
|
||||
Name,
|
||||
ImageURL,
|
||||
ModelData, // for emulating the regular emoji model's usage, otherwise the UI code would get too complicated
|
||||
};
|
||||
|
||||
CustomEmojiModel::CustomEmojiModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
connect(this, &CustomEmojiModel::connectionChanged, this, &CustomEmojiModel::fetchEmojies);
|
||||
connect(this, &CustomEmojiModel::connectionChanged, this, [this]() {
|
||||
if (!d->conn)
|
||||
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this]() {
|
||||
if (!Controller::instance().activeConnection()) {
|
||||
return;
|
||||
|
||||
connect(d->conn, &Connection::accountDataChanged, this, [this](const QString &id) {
|
||||
}
|
||||
CustomEmojiModel::fetchEmojis();
|
||||
disconnect(nullptr, &Connection::accountDataChanged, this, nullptr);
|
||||
connect(Controller::instance().activeConnection(), &Connection::accountDataChanged, this, [this](const QString &id) {
|
||||
if (id != QStringLiteral("im.ponies.user_emotes")) {
|
||||
return;
|
||||
}
|
||||
fetchEmojies();
|
||||
fetchEmojis();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CustomEmojiModel::~CustomEmojiModel()
|
||||
{
|
||||
}
|
||||
|
||||
QVariant CustomEmojiModel::data(const QModelIndex &idx, int role) const
|
||||
{
|
||||
const auto row = idx.row();
|
||||
if (row >= d->emojies.length()) {
|
||||
if (row >= m_emojis.length()) {
|
||||
return QVariant();
|
||||
}
|
||||
const auto &data = d->emojies[row];
|
||||
const auto &data = m_emojis[row];
|
||||
|
||||
switch (Roles(role)) {
|
||||
case Roles::ModelData:
|
||||
@@ -51,6 +42,8 @@ QVariant CustomEmojiModel::data(const QModelIndex &idx, int role) const
|
||||
return data.name;
|
||||
case Roles::ImageURL:
|
||||
return QUrl(QStringLiteral("image://mxc/") + data.url.mid(6));
|
||||
case Roles::MxcUrl:
|
||||
return data.url.mid(6);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@@ -60,7 +53,7 @@ int CustomEmojiModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
return d->emojies.length();
|
||||
return m_emojis.length();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> CustomEmojiModel::roleNames() const
|
||||
@@ -69,41 +62,25 @@ QHash<int, QByteArray> CustomEmojiModel::roleNames() const
|
||||
{Name, "name"},
|
||||
{ImageURL, "imageURL"},
|
||||
{ModelData, "modelData"},
|
||||
{MxcUrl, "mxcUrl"},
|
||||
};
|
||||
}
|
||||
|
||||
Connection *CustomEmojiModel::connection() const
|
||||
QString CustomEmojiModel::preprocessText(const QString &text)
|
||||
{
|
||||
return d->conn;
|
||||
}
|
||||
|
||||
void CustomEmojiModel::setConnection(Connection *it)
|
||||
{
|
||||
if (d->conn == it) {
|
||||
return;
|
||||
}
|
||||
if (d->conn != nullptr) {
|
||||
disconnect(d->conn, nullptr, this, nullptr);
|
||||
}
|
||||
d->conn = it;
|
||||
Q_EMIT connectionChanged();
|
||||
}
|
||||
|
||||
QString CustomEmojiModel::preprocessText(const QString &it)
|
||||
{
|
||||
auto cp = it;
|
||||
for (const auto &emoji : std::as_const(d->emojies)) {
|
||||
cp.replace(
|
||||
auto handledText = text;
|
||||
for (const auto &emoji : std::as_const(m_emojis)) {
|
||||
handledText.replace(
|
||||
emoji.regexp,
|
||||
QStringLiteral(R"(<img data-mx-emoticon="" src="%1" alt="%2" title="%2" height="32" vertical-align="middle" />)").arg(emoji.url, emoji.name));
|
||||
}
|
||||
return cp;
|
||||
return handledText;
|
||||
}
|
||||
|
||||
QVariantList CustomEmojiModel::filterModel(const QString &filter)
|
||||
{
|
||||
QVariantList results;
|
||||
for (const auto &emoji : std::as_const(d->emojies)) {
|
||||
for (const auto &emoji : std::as_const(m_emojis)) {
|
||||
if (results.length() >= 10)
|
||||
break;
|
||||
if (!emoji.name.contains(filter, Qt::CaseInsensitive))
|
||||
|
||||
Reference in New Issue
Block a user