diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index b0747a7c..56d0d1ce 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -21,6 +21,7 @@
#include "ChatPage.h"
#include "CompletionProxyModel.h"
#include "Config.h"
+#include "ImagePackModel.h"
#include "Logging.h"
#include "MainWindow.h"
#include "MatrixClient.h"
@@ -502,6 +503,31 @@ InputBar::video(const QString &filename,
}
void
+InputBar::sticker(ImagePackModel *model, int row)
+{
+ if (!model || row < 0)
+ return;
+
+ auto img = model->imageAt(row);
+
+ mtx::events::msg::StickerImage sticker{};
+ sticker.info = img.info.value_or(mtx::common::ImageInfo{});
+ sticker.url = img.url;
+ sticker.body = img.body;
+
+ if (!room->reply().isEmpty()) {
+ sticker.relations.relations.push_back(
+ {mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
+ }
+ if (!room->edit().isEmpty()) {
+ sticker.relations.relations.push_back(
+ {mtx::common::RelationType::Replace, room->edit().toStdString()});
+ }
+
+ room->sendMessageEvent(sticker, mtx::events::EventType::Sticker);
+}
+
+void
InputBar::command(QString command, QString args)
{
if (command == "me") {
diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h
index c9728379..acedceb7 100644
--- a/src/timeline/InputBar.h
+++ b/src/timeline/InputBar.h
@@ -12,6 +12,7 @@
#include <mtx/responses/messages.hpp>
class TimelineModel;
+class ImagePackModel;
class QMimeData;
class QDropEvent;
class QStringList;
@@ -57,6 +58,7 @@ public slots:
MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED,
bool rainbowify = false);
void reaction(const QString &reactedEvent, const QString &reactionKey);
+ void sticker(ImagePackModel *model, int row);
private slots:
void startTyping();
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index ab11f99b..abfe28a9 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -710,6 +710,14 @@ TimelineModel::data(const QModelIndex &index, int role) const
return data(*event, role);
}
+QVariant
+TimelineModel::dataById(QString id, int role, QString relatedTo)
+{
+ if (auto event = events.get(id.toStdString(), relatedTo.toStdString()))
+ return data(*event, role);
+ return QVariant();
+}
+
bool
TimelineModel::canFetchMore(const QModelIndex &) const
{
@@ -1292,6 +1300,14 @@ struct SendMessageVisitor
sendRoomEvent<mtx::events::msg::KeyVerificationCancel,
mtx::events::EventType::KeyVerificationCancel>(msg);
}
+ void operator()(mtx::events::Sticker msg)
+ {
+ msg.type = mtx::events::EventType::Sticker;
+ if (cache::isRoomEncrypted(model_->room_id_.toStdString())) {
+ model_->sendEncryptedMessage(msg, mtx::events::EventType::Sticker);
+ } else
+ emit model_->addPendingMessageToStore(msg);
+ }
TimelineModel *model_;
};
@@ -1301,6 +1317,7 @@ TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event)
{
std::visit(
[](auto &msg) {
+ // gets overwritten for reactions and stickers in SendMessageVisitor
msg.type = mtx::events::EventType::RoomMessage;
msg.event_id = "m" + http::client()->generate_txn_id();
msg.sender = http::client()->user_id().to_string();
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index a3c973d6..0e2895d4 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -215,10 +215,7 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant data(const mtx::events::collections::TimelineEvents &event, int role) const;
- Q_INVOKABLE QVariant dataById(QString id, int role)
- {
- return data(index(idToIndex(id)), role);
- }
+ Q_INVOKABLE QVariant dataById(QString id, int role, QString relatedTo);
bool canFetchMore(const QModelIndex &) const override;
void fetchMore(const QModelIndex &) override;
@@ -413,10 +410,17 @@ template<class T>
void
TimelineModel::sendMessageEvent(const T &content, mtx::events::EventType eventType)
{
- mtx::events::RoomEvent<T> msgCopy = {};
- msgCopy.content = content;
- msgCopy.type = eventType;
- emit newMessageToSend(msgCopy);
+ if constexpr (std::is_same_v<T, mtx::events::msg::StickerImage>) {
+ mtx::events::Sticker msgCopy = {};
+ msgCopy.content = content;
+ msgCopy.type = eventType;
+ emit newMessageToSend(msgCopy);
+ } else {
+ mtx::events::RoomEvent<T> msgCopy = {};
+ msgCopy.content = content;
+ msgCopy.type = eventType;
+ emit newMessageToSend(msgCopy);
+ }
resetReply();
resetEdit();
}
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index b39ef615..3e69f92b 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -19,6 +19,7 @@
#include "DelegateChooser.h"
#include "DeviceVerificationFlow.h"
#include "EventAccessors.h"
+#include "ImagePackModel.h"
#include "Logging.h"
#include "MainWindow.h"
#include "MatrixClient.h"
@@ -144,6 +145,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
qRegisterMetaType<mtx::events::msg::KeyVerificationReady>();
qRegisterMetaType<mtx::events::msg::KeyVerificationRequest>();
qRegisterMetaType<mtx::events::msg::KeyVerificationStart>();
+ qRegisterMetaType<ImagePackModel *>();
qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
"im.nheko",
@@ -593,6 +595,11 @@ TimelineViewManager::completerFor(QString completerName, QString roomId)
auto proxy = new CompletionProxyModel(roomModel);
roomModel->setParent(proxy);
return proxy;
+ } else if (completerName == "stickers") {
+ auto stickerModel = new ImagePackModel(roomId.toStdString(), true);
+ auto proxy = new CompletionProxyModel(stickerModel, 1, static_cast<size_t>(-1) / 4);
+ stickerModel->setParent(proxy);
+ return proxy;
}
return nullptr;
}
|