matrixion/src/timeline/TimelineViewManager.cpp

731 lines
28 KiB
C++
Raw Normal View History

2019-11-09 05:06:10 +03:00
#include "TimelineViewManager.h"
#include <QDesktopServices>
2019-11-09 05:06:10 +03:00
#include <QMetaType>
#include <QPalette>
#include <QQmlContext>
2020-05-27 11:49:26 +03:00
#include <QQmlEngine>
2020-07-11 02:19:48 +03:00
#include <QString>
2019-11-09 05:06:10 +03:00
#include "BlurhashProvider.h"
2019-11-09 05:06:10 +03:00
#include "ChatPage.h"
#include "ColorImageProvider.h"
#include "DelegateChooser.h"
2020-10-27 19:45:28 +03:00
#include "DeviceVerificationFlow.h"
2018-07-17 16:37:25 +03:00
#include "Logging.h"
#include "MainWindow.h"
2020-01-17 03:25:14 +03:00
#include "MatrixClient.h"
2019-11-09 05:06:10 +03:00
#include "MxcImageProvider.h"
#include "UserSettingsPage.h"
#include "dialogs/ImageOverlay.h"
#include "emoji/EmojiModel.h"
#include "emoji/Provider.h"
2017-04-06 02:06:42 +03:00
2020-07-29 00:55:47 +03:00
#include <iostream> //only for debugging
2020-01-11 20:53:32 +03:00
Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
2020-07-04 05:24:28 +03:00
Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
2020-01-11 20:53:32 +03:00
namespace msgs = mtx::events::msg;
void
TimelineViewManager::updateEncryptedDescriptions()
{
2020-10-17 01:57:29 +03:00
auto decrypt = ChatPage::instance()->userSettings()->decryptSidebar();
QHash<QString, QSharedPointer<TimelineModel>>::iterator i;
for (i = models.begin(); i != models.end(); ++i) {
auto ptr = i.value();
if (!ptr.isNull()) {
2020-04-24 02:21:20 +03:00
ptr->setDecryptDescription(decrypt);
ptr->updateLastMessage();
}
}
}
void
2019-11-09 05:06:10 +03:00
TimelineViewManager::updateColorPalette()
{
userColors.clear();
2020-10-17 01:57:29 +03:00
if (ChatPage::instance()->userSettings()->theme() == "light") {
2020-03-30 22:48:28 +03:00
view->rootContext()->setContextProperty("currentActivePalette", QPalette());
view->rootContext()->setContextProperty("currentInactivePalette", QPalette());
2020-10-17 01:57:29 +03:00
} else if (ChatPage::instance()->userSettings()->theme() == "dark") {
2020-03-30 22:48:28 +03:00
view->rootContext()->setContextProperty("currentActivePalette", QPalette());
view->rootContext()->setContextProperty("currentInactivePalette", QPalette());
2019-11-09 05:06:10 +03:00
} else {
view->rootContext()->setContextProperty("currentActivePalette", QPalette());
view->rootContext()->setContextProperty("currentInactivePalette", nullptr);
}
}
QColor
TimelineViewManager::userColor(QString id, QColor background)
{
if (!userColors.contains(id))
userColors.insert(
id, QColor(utils::generateContrastingHexColor(id, background.name())));
return userColors.value(id);
}
2020-06-24 17:24:22 +03:00
QString
TimelineViewManager::userPresence(QString id) const
{
if (id.isEmpty())
return "";
else
return QString::fromStdString(
mtx::presence::to_string(cache::presenceState(id.toStdString())));
}
QString
TimelineViewManager::userStatus(QString id) const
{
return QString::fromStdString(cache::statusMessage(id.toStdString()));
}
2020-10-17 01:57:29 +03:00
TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *parent)
2019-11-09 05:06:10 +03:00
: imgProvider(new MxcImageProvider())
, colorImgProvider(new ColorImageProvider())
, blurhashProvider(new BlurhashProvider())
2020-07-11 02:19:48 +03:00
, callManager_(callManager)
{
2020-07-17 23:16:30 +03:00
qRegisterMetaType<mtx::events::msg::KeyVerificationAccept>();
qRegisterMetaType<mtx::events::msg::KeyVerificationCancel>();
qRegisterMetaType<mtx::events::msg::KeyVerificationDone>();
qRegisterMetaType<mtx::events::msg::KeyVerificationKey>();
qRegisterMetaType<mtx::events::msg::KeyVerificationMac>();
qRegisterMetaType<mtx::events::msg::KeyVerificationReady>();
qRegisterMetaType<mtx::events::msg::KeyVerificationRequest>();
qRegisterMetaType<mtx::events::msg::KeyVerificationStart>();
2019-11-09 05:06:10 +03:00
qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
"im.nheko",
2019-11-09 05:06:10 +03:00
1,
0,
"MtxEvent",
"Can't instantiate enum!");
2020-07-04 05:24:28 +03:00
qmlRegisterUncreatableMetaObject(verification::staticMetaObject,
"im.nheko",
1,
0,
"VerificationStatus",
"Can't instantiate enum!");
qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice");
qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser");
qmlRegisterUncreatableType<DeviceVerificationFlow>(
"im.nheko", 1, 0, "DeviceVerificationFlow", "Can't create verification flow from QML!");
2020-07-04 05:24:28 +03:00
qmlRegisterUncreatableType<UserProfile>(
"im.nheko",
1,
0,
"UserProfileModel",
"UserProfile needs to be instantiated on the C++ side");
static auto self = this;
qmlRegisterSingletonType<TimelineViewManager>(
2020-10-08 19:16:30 +03:00
"im.nheko", 1, 0, "TimelineManager", [](QQmlEngine *, QJSEngine *) -> QObject * {
return self;
});
qmlRegisterSingletonType<UserSettings>(
2020-10-08 19:16:30 +03:00
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
2020-10-17 01:57:29 +03:00
return ChatPage::instance()->userSettings().data();
});
2020-05-27 11:49:26 +03:00
2020-01-11 20:53:32 +03:00
qRegisterMetaType<mtx::events::collections::TimelineEvents>();
2020-07-04 05:24:28 +03:00
qRegisterMetaType<std::vector<DeviceInfo>>();
qmlRegisterType<emoji::EmojiModel>("im.nheko.EmojiModel", 1, 0, "EmojiModel");
qmlRegisterType<emoji::EmojiProxyModel>("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel");
qmlRegisterUncreatableType<QAbstractItemModel>(
"im.nheko.EmojiModel", 1, 0, "QAbstractItemModel", "Used by proxy models");
qmlRegisterUncreatableType<emoji::Emoji>(
"im.nheko.EmojiModel", 1, 0, "Emoji", "Used by emoji models");
qmlRegisterUncreatableMetaObject(emoji::staticMetaObject,
2020-06-11 07:37:54 +03:00
"im.nheko.EmojiModel",
1,
0,
"EmojiCategory",
"Error: Only enums");
2019-11-09 05:06:10 +03:00
#ifdef USE_QUICK_VIEW
view = new QQuickView();
container = QWidget::createWindowContainer(view, parent);
#else
view = new QQuickWidget(parent);
container = view;
view->setResizeMode(QQuickWidget::SizeRootObjectToView);
container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
2020-06-27 04:15:36 +03:00
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
view->quickWindow()->setTextRenderType(QQuickWindow::NativeTextRendering);
2020-06-27 04:15:36 +03:00
#endif
2019-11-09 05:06:10 +03:00
connect(view, &QQuickWidget::statusChanged, this, [](QQuickWidget::Status status) {
nhlog::ui()->debug("Status changed to {}", status);
});
#endif
container->setMinimumSize(200, 200);
updateColorPalette();
view->engine()->addImageProvider("MxcImage", imgProvider);
view->engine()->addImageProvider("colorimage", colorImgProvider);
view->engine()->addImageProvider("blurhash", blurhashProvider);
2019-11-09 05:06:10 +03:00
view->setSource(QUrl("qrc:///qml/TimelineView.qml"));
connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette);
connect(parent,
&ChatPage::decryptSidebarChanged,
this,
&TimelineViewManager::updateEncryptedDescriptions);
2020-07-29 00:55:47 +03:00
connect(
dynamic_cast<ChatPage *>(parent),
&ChatPage::receivedRoomDeviceVerificationRequest,
2020-07-29 00:55:47 +03:00
this,
[this](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &message,
TimelineModel *model) {
auto event_id = QString::fromStdString(message.event_id);
if (!this->dvList.contains(event_id)) {
if (auto flow = DeviceVerificationFlow::NewInRoomVerification(
this,
model,
message.content,
QString::fromStdString(message.sender),
event_id)) {
dvList[event_id] = flow;
emit newDeviceVerificationRequest(flow.data());
2020-06-26 12:40:37 +03:00
}
}
});
connect(dynamic_cast<ChatPage *>(parent),
&ChatPage::receivedDeviceVerificationRequest,
this,
[this](const mtx::events::msg::KeyVerificationRequest &msg, std::string sender) {
if (!msg.transaction_id)
return;
auto txnid = QString::fromStdString(msg.transaction_id.value());
if (!this->dvList.contains(txnid)) {
if (auto flow = DeviceVerificationFlow::NewToDeviceVerification(
this, msg, QString::fromStdString(sender), txnid)) {
dvList[txnid] = flow;
emit newDeviceVerificationRequest(flow.data());
}
}
});
connect(dynamic_cast<ChatPage *>(parent),
&ChatPage::receivedDeviceVerificationStart,
this,
[this](const mtx::events::msg::KeyVerificationStart &msg, std::string sender) {
if (!msg.transaction_id)
return;
auto txnid = QString::fromStdString(msg.transaction_id.value());
if (!this->dvList.contains(txnid)) {
if (auto flow = DeviceVerificationFlow::NewToDeviceVerification(
this, msg, QString::fromStdString(sender), txnid)) {
dvList[txnid] = flow;
emit newDeviceVerificationRequest(flow.data());
}
}
});
connect(parent, &ChatPage::loggedOut, this, [this]() {
2020-08-01 21:39:06 +03:00
isInitialSync_ = true;
emit initialSyncChanged(true);
});
2020-09-22 19:14:15 +03:00
connect(&WebRTCSession::instance(),
&WebRTCSession::stateChanged,
this,
&TimelineViewManager::callStateChanged);
connect(
callManager_, &CallManager::newCallParty, this, &TimelineViewManager::callPartyChanged);
2020-10-27 20:14:06 +03:00
connect(callManager_,
&CallManager::newVideoCallState,
this,
&TimelineViewManager::videoCallChanged);
}
void
TimelineViewManager::setVideoCallItem()
{
WebRTCSession::instance().setVideoItem(
view->rootObject()->findChild<QQuickItem *>("videoCallItem"));
}
void
2019-11-09 05:06:10 +03:00
TimelineViewManager::sync(const mtx::responses::Rooms &rooms)
{
2020-01-17 03:25:14 +03:00
for (const auto &[room_id, room] : rooms.join) {
2019-11-09 05:06:10 +03:00
// addRoom will only add the room, if it doesn't exist
2020-01-17 03:25:14 +03:00
addRoom(QString::fromStdString(room_id));
const auto &room_model = models.value(QString::fromStdString(room_id));
2020-07-11 02:19:48 +03:00
if (!isInitialSync_)
connect(room_model.data(),
&TimelineModel::newCallEvent,
callManager_,
&CallManager::syncEvent);
room_model->syncState(room.state);
2020-01-17 03:25:14 +03:00
room_model->addEvents(room.timeline);
2020-07-11 02:19:48 +03:00
if (!isInitialSync_)
disconnect(room_model.data(),
&TimelineModel::newCallEvent,
callManager_,
&CallManager::syncEvent);
2020-01-17 03:25:14 +03:00
2020-05-26 23:53:21 +03:00
if (ChatPage::instance()->userSettings()->typingNotifications()) {
2020-01-17 03:25:14 +03:00
std::vector<QString> typing;
typing.reserve(room.ephemeral.typing.size());
for (const auto &user : room.ephemeral.typing) {
if (user != http::client()->user_id().to_string())
typing.push_back(QString::fromStdString(user));
}
room_model->updateTypingUsers(typing);
}
2019-11-09 05:06:10 +03:00
}
this->isInitialSync_ = false;
emit initialSyncChanged(false);
}
void
2019-11-09 05:06:10 +03:00
TimelineViewManager::addRoom(const QString &room_id)
{
if (!models.contains(room_id)) {
QSharedPointer<TimelineModel> newRoom(new TimelineModel(this, room_id));
2020-10-17 01:57:29 +03:00
newRoom->setDecryptDescription(
ChatPage::instance()->userSettings()->decryptSidebar());
2020-04-24 02:21:20 +03:00
connect(newRoom.data(),
&TimelineModel::newEncryptedImage,
imgProvider,
&MxcImageProvider::addEncryptionInfo);
models.insert(room_id, std::move(newRoom));
}
}
void
2019-11-09 05:06:10 +03:00
TimelineViewManager::setHistoryView(const QString &room_id)
{
2019-11-09 05:06:10 +03:00
nhlog::ui()->info("Trying to activate room {}", room_id.toStdString());
2019-11-09 05:06:10 +03:00
auto room = models.find(room_id);
if (room != models.end()) {
timeline_ = room.value().data();
emit activeTimelineChanged(timeline_);
nhlog::ui()->info("Activated room {}", room_id.toStdString());
}
}
2020-09-03 20:51:50 +03:00
QString
TimelineViewManager::escapeEmoji(QString str) const
{
return utils::replaceEmoji(str);
}
void
TimelineViewManager::toggleMicMute()
{
WebRTCSession::instance().toggleMicMute();
emit micMuteChanged();
}
2020-11-09 18:51:17 +03:00
void
TimelineViewManager::toggleCameraView()
{
WebRTCSession::instance().toggleCameraView();
}
2017-09-10 12:58:00 +03:00
void
2019-12-03 04:26:41 +03:00
TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId) const
2017-09-10 12:58:00 +03:00
{
2020-11-30 22:56:39 +03:00
if (mxcUrl.isEmpty() || mxcUrl.isNull()) {
return;
}
2019-11-09 05:06:10 +03:00
QQuickImageResponse *imgResponse =
imgProvider->requestImageResponse(mxcUrl.remove("mxc://"), QSize());
2019-12-03 04:26:41 +03:00
connect(imgResponse, &QQuickImageResponse::finished, this, [this, eventId, imgResponse]() {
if (!imgResponse->errorString().isEmpty()) {
nhlog::ui()->error("Error when retrieving image for overlay: {}",
imgResponse->errorString().toStdString());
return;
}
auto pixmap = QPixmap::fromImage(imgResponse->textureFactory()->image());
2019-11-09 05:06:10 +03:00
2019-12-03 04:26:41 +03:00
auto imgDialog = new dialogs::ImageOverlay(pixmap);
imgDialog->showFullScreen();
connect(imgDialog,
&dialogs::ImageOverlay::saving,
timeline_,
[this, eventId, imgDialog]() {
// hide the overlay while presenting the save dialog for better
// cross platform support.
imgDialog->hide();
if (!timeline_->saveMedia(eventId)) {
imgDialog->show();
} else {
imgDialog->close();
}
});
2019-12-03 04:26:41 +03:00
});
2017-12-01 18:33:49 +03:00
}
void
TimelineViewManager::openLink(QString link) const
{
QDesktopServices::openUrl(link);
}
void
TimelineViewManager::openInviteUsersDialog()
{
MainWindow::instance()->openInviteUsersDialog(
[this](const QStringList &invitees) { emit inviteUsers(invitees); });
}
void
TimelineViewManager::openMemberListDialog() const
{
MainWindow::instance()->openMemberListDialog(timeline_->roomId());
}
void
TimelineViewManager::openLeaveRoomDialog() const
{
MainWindow::instance()->openLeaveRoomDialog(timeline_->roomId());
}
void
TimelineViewManager::openRoomSettings() const
{
MainWindow::instance()->openRoomSettings(timeline_->roomId());
}
void
TimelineViewManager::verifyUser(QString userid)
{
auto joined_rooms = cache::joinedRooms();
auto room_infos = cache::getRoomInfo(joined_rooms);
for (std::string room_id : joined_rooms) {
if ((room_infos[QString::fromStdString(room_id)].member_count == 2) &&
cache::isRoomEncrypted(room_id)) {
auto room_members = cache::roomMembers(room_id);
if (std::find(room_members.begin(),
room_members.end(),
(userid).toStdString()) != room_members.end()) {
auto model = models.value(QString::fromStdString(room_id));
auto flow = DeviceVerificationFlow::InitiateUserVerification(
this, model.data(), userid);
connect(model.data(),
&TimelineModel::updateFlowEventId,
this,
[this, flow](std::string eventId) {
dvList[QString::fromStdString(eventId)] = flow;
});
emit newDeviceVerificationRequest(flow.data());
return;
}
}
}
emit ChatPage::instance()->showNotification(
tr("No encrypted private chat found with this user. Create an "
"encrypted private chat with this user and try again."));
}
2020-10-05 23:58:07 +03:00
void
TimelineViewManager::removeVerificationFlow(DeviceVerificationFlow *flow)
{
for (auto it = dvList.keyValueBegin(); it != dvList.keyValueEnd(); ++it) {
if ((*it).second == flow) {
dvList.remove((*it).first);
2020-10-05 23:58:07 +03:00
return;
}
}
}
void
TimelineViewManager::verifyDevice(QString userid, QString deviceid)
{
auto flow = DeviceVerificationFlow::InitiateDeviceVerification(this, userid, deviceid);
this->dvList[flow->transactionId()] = flow;
emit newDeviceVerificationRequest(flow.data());
}
2017-08-20 13:47:22 +03:00
void
2019-11-09 05:06:10 +03:00
TimelineViewManager::updateReadReceipts(const QString &room_id,
const std::vector<QString> &event_ids)
2017-04-06 02:06:42 +03:00
{
2019-11-09 05:06:10 +03:00
auto room = models.find(room_id);
if (room != models.end()) {
room.value()->markEventsAsRead(event_ids);
2017-08-26 11:33:26 +03:00
}
2017-04-06 02:06:42 +03:00
}
2020-10-20 20:46:37 +03:00
void
TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::string &session_id)
{
auto room = models.find(QString::fromStdString(room_id));
if (room != models.end()) {
room.value()->receivedSessionKey(session_id);
}
}
void
2020-10-28 15:06:28 +03:00
TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
{
2020-10-28 15:06:28 +03:00
for (const auto &roomId : roomIds)
addRoom(roomId);
}
2017-08-20 13:47:22 +03:00
void
2020-04-13 17:22:30 +03:00
TimelineViewManager::queueTextMessage(const QString &msg)
{
2020-04-13 17:22:30 +03:00
if (!timeline_)
return;
2019-11-09 05:06:10 +03:00
mtx::events::msg::Text text = {};
text.body = msg.trimmed().toStdString();
2020-10-17 01:57:29 +03:00
if (ChatPage::instance()->userSettings()->markdown()) {
text.formatted_body = utils::markdownToHtml(msg).toStdString();
2020-01-27 19:25:09 +03:00
// Don't send formatted_body, when we don't need to
if (text.formatted_body.find("<") == std::string::npos)
2020-01-27 19:25:09 +03:00
text.formatted_body = "";
else
text.format = "org.matrix.custom.html";
}
2019-11-09 05:06:10 +03:00
2020-04-13 17:22:30 +03:00
if (!timeline_->reply().isEmpty()) {
auto related = timeline_->relatedInfo(timeline_->reply());
2020-01-12 18:39:01 +03:00
QString body;
bool firstLine = true;
2020-04-13 17:22:30 +03:00
for (const auto &line : related.quoted_body.split("\n")) {
2020-01-12 18:39:01 +03:00
if (firstLine) {
firstLine = false;
2020-04-13 17:22:30 +03:00
body = QString("> <%1> %2\n").arg(related.quoted_user).arg(line);
2020-01-12 18:39:01 +03:00
} else {
body = QString("%1\n> %2\n").arg(body).arg(line);
}
2019-11-09 05:06:10 +03:00
}
2017-08-26 11:33:26 +03:00
2020-01-12 18:39:01 +03:00
text.body = QString("%1\n%2").arg(body).arg(msg).toStdString();
2017-08-26 11:33:26 +03:00
// NOTE(Nico): rich replies always need a formatted_body!
text.format = "org.matrix.custom.html";
2020-10-17 01:57:29 +03:00
if (ChatPage::instance()->userSettings()->markdown())
text.formatted_body =
2020-04-13 17:22:30 +03:00
utils::getFormattedQuoteBody(related, utils::markdownToHtml(msg))
.toStdString();
else
text.formatted_body =
2020-04-13 17:22:30 +03:00
utils::getFormattedQuoteBody(related, msg.toHtmlEscaped()).toStdString();
2020-04-13 17:22:30 +03:00
text.relates_to.in_reply_to.event_id = related.related_event;
timeline_->resetReply();
2020-01-12 18:39:01 +03:00
}
2017-08-26 11:33:26 +03:00
2020-07-11 02:19:48 +03:00
timeline_->sendMessageEvent(text, mtx::events::EventType::RoomMessage);
}
void
2019-11-09 05:06:10 +03:00
TimelineViewManager::queueEmoteMessage(const QString &msg)
{
2019-11-09 05:06:10 +03:00
auto html = utils::markdownToHtml(msg);
2018-04-21 16:34:50 +03:00
2019-11-09 05:06:10 +03:00
mtx::events::msg::Emote emote;
emote.body = msg.trimmed().toStdString();
2020-10-17 01:57:29 +03:00
if (html != msg.trimmed().toHtmlEscaped() &&
ChatPage::instance()->userSettings()->markdown()) {
2019-11-09 05:06:10 +03:00
emote.formatted_body = html.toStdString();
2020-01-27 17:59:25 +03:00
emote.format = "org.matrix.custom.html";
}
2020-04-13 17:22:30 +03:00
if (!timeline_->reply().isEmpty()) {
emote.relates_to.in_reply_to.event_id = timeline_->reply().toStdString();
timeline_->resetReply();
}
2019-11-09 05:06:10 +03:00
if (timeline_)
2020-07-11 02:19:48 +03:00
timeline_->sendMessageEvent(emote, mtx::events::EventType::RoomMessage);
}
void
2020-07-20 01:42:48 +03:00
TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey)
{
2020-07-20 01:42:48 +03:00
if (!timeline_)
return;
auto reactions = timeline_->reactions(reactedEvent.toStdString());
QString selfReactedEvent;
for (const auto &reaction : reactions) {
if (reactionKey == reaction.key_) {
selfReactedEvent = reaction.selfReactedEvent_;
break;
}
}
if (selfReactedEvent.startsWith("m"))
return;
// If selfReactedEvent is empty, that means we haven't previously reacted
if (selfReactedEvent.isEmpty()) {
2020-07-20 01:42:48 +03:00
mtx::events::msg::Reaction reaction;
reaction.relates_to.rel_type = mtx::common::RelationType::Annotation;
reaction.relates_to.event_id = reactedEvent.toStdString();
reaction.relates_to.key = reactionKey.toStdString();
timeline_->sendMessageEvent(reaction, mtx::events::EventType::Reaction);
// Otherwise, we have previously reacted and the reaction should be redacted
} else {
2020-07-20 01:42:48 +03:00
timeline_->redactEvent(selfReactedEvent);
}
}
2017-08-20 13:47:22 +03:00
void
2019-11-09 05:06:10 +03:00
TimelineViewManager::queueImageMessage(const QString &roomid,
const QString &filename,
2019-12-14 19:08:36 +03:00
const std::optional<mtx::crypto::EncryptedFile> &file,
2019-11-09 05:06:10 +03:00
const QString &url,
const QString &mime,
uint64_t dsize,
2020-01-12 18:39:01 +03:00
const QSize &dimensions,
2020-04-13 17:22:30 +03:00
const QString &blurhash)
2017-04-06 02:06:42 +03:00
{
2019-11-09 05:06:10 +03:00
mtx::events::msg::Image image;
image.info.mimetype = mime.toStdString();
image.info.size = dsize;
image.info.blurhash = blurhash.toStdString();
2019-11-09 05:06:10 +03:00
image.body = filename.toStdString();
image.info.h = dimensions.height();
image.info.w = dimensions.width();
if (file)
image.file = file;
else
image.url = url.toStdString();
2020-01-12 18:39:01 +03:00
2020-04-13 17:22:30 +03:00
auto model = models.value(roomid);
if (!model->reply().isEmpty()) {
image.relates_to.in_reply_to.event_id = model->reply().toStdString();
model->resetReply();
}
2020-01-12 18:39:01 +03:00
2020-07-11 02:19:48 +03:00
model->sendMessageEvent(image, mtx::events::EventType::RoomMessage);
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
2019-12-05 17:31:53 +03:00
TimelineViewManager::queueFileMessage(
const QString &roomid,
const QString &filename,
2019-12-14 19:08:36 +03:00
const std::optional<mtx::crypto::EncryptedFile> &encryptedFile,
2019-12-05 17:31:53 +03:00
const QString &url,
const QString &mime,
2020-04-13 17:22:30 +03:00
uint64_t dsize)
2017-04-06 02:06:42 +03:00
{
2019-11-09 05:06:10 +03:00
mtx::events::msg::File file;
file.info.mimetype = mime.toStdString();
file.info.size = dsize;
file.body = filename.toStdString();
if (encryptedFile)
file.file = encryptedFile;
else
file.url = url.toStdString();
2020-01-12 18:39:01 +03:00
2020-04-13 17:22:30 +03:00
auto model = models.value(roomid);
if (!model->reply().isEmpty()) {
file.relates_to.in_reply_to.event_id = model->reply().toStdString();
model->resetReply();
}
2020-01-12 18:39:01 +03:00
2020-07-11 02:19:48 +03:00
model->sendMessageEvent(file, mtx::events::EventType::RoomMessage);
2017-04-06 02:06:42 +03:00
}
2017-04-11 22:48:02 +03:00
2019-11-09 05:06:10 +03:00
void
TimelineViewManager::queueAudioMessage(const QString &roomid,
const QString &filename,
2019-12-14 19:08:36 +03:00
const std::optional<mtx::crypto::EncryptedFile> &file,
2019-11-09 05:06:10 +03:00
const QString &url,
const QString &mime,
2020-04-13 17:22:30 +03:00
uint64_t dsize)
2017-04-11 22:48:02 +03:00
{
2019-11-09 05:06:10 +03:00
mtx::events::msg::Audio audio;
audio.info.mimetype = mime.toStdString();
audio.info.size = dsize;
audio.body = filename.toStdString();
audio.url = url.toStdString();
if (file)
audio.file = file;
else
audio.url = url.toStdString();
2020-01-12 18:39:01 +03:00
2020-04-13 17:22:30 +03:00
auto model = models.value(roomid);
if (!model->reply().isEmpty()) {
audio.relates_to.in_reply_to.event_id = model->reply().toStdString();
model->resetReply();
}
2020-01-12 18:39:01 +03:00
2020-07-11 02:19:48 +03:00
model->sendMessageEvent(audio, mtx::events::EventType::RoomMessage);
}
2017-05-08 19:44:01 +03:00
2019-11-09 05:06:10 +03:00
void
TimelineViewManager::queueVideoMessage(const QString &roomid,
const QString &filename,
2019-12-14 19:08:36 +03:00
const std::optional<mtx::crypto::EncryptedFile> &file,
2019-11-09 05:06:10 +03:00
const QString &url,
const QString &mime,
2020-04-13 17:22:30 +03:00
uint64_t dsize)
2017-10-07 20:50:32 +03:00
{
2019-11-09 05:06:10 +03:00
mtx::events::msg::Video video;
video.info.mimetype = mime.toStdString();
video.info.size = dsize;
video.body = filename.toStdString();
if (file)
video.file = file;
else
video.url = url.toStdString();
2020-01-12 18:39:01 +03:00
2020-04-13 17:22:30 +03:00
auto model = models.value(roomid);
if (!model->reply().isEmpty()) {
video.relates_to.in_reply_to.event_id = model->reply().toStdString();
model->resetReply();
}
2020-01-12 18:39:01 +03:00
2020-07-11 02:19:48 +03:00
model->sendMessageEvent(video, mtx::events::EventType::RoomMessage);
}
void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallInvite &callInvite)
{
models.value(roomid)->sendMessageEvent(callInvite, mtx::events::EventType::CallInvite);
}
void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallCandidates &callCandidates)
{
models.value(roomid)->sendMessageEvent(callCandidates,
mtx::events::EventType::CallCandidates);
}
void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallAnswer &callAnswer)
{
models.value(roomid)->sendMessageEvent(callAnswer, mtx::events::EventType::CallAnswer);
}
void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallHangUp &callHangUp)
{
models.value(roomid)->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
2017-10-07 20:50:32 +03:00
}