2023-02-22 01:48:49 +03:00
|
|
|
// SPDX-FileCopyrightText: Nheko Contributors
|
2021-03-05 02:35:15 +03:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
2019-11-09 05:06:10 +03:00
|
|
|
#include "TimelineViewManager.h"
|
|
|
|
|
2022-01-13 06:16:11 +03:00
|
|
|
#include <QApplication>
|
2023-04-23 21:55:28 +03:00
|
|
|
#include <QClipboard>
|
2022-01-02 23:46:29 +03:00
|
|
|
#include <QFileDialog>
|
2023-04-23 21:55:28 +03:00
|
|
|
#include <QMimeData>
|
2022-01-02 23:46:29 +03:00
|
|
|
#include <QStandardPaths>
|
2020-07-11 02:19:48 +03:00
|
|
|
#include <QString>
|
2019-11-09 05:06:10 +03:00
|
|
|
|
2022-12-07 14:47:03 +03:00
|
|
|
#include "Cache.h"
|
2023-09-08 00:10:04 +03:00
|
|
|
#include "Cache_p.h"
|
2019-11-09 05:06:10 +03:00
|
|
|
#include "ChatPage.h"
|
2021-07-21 02:03:38 +03:00
|
|
|
#include "CombinedImagePackModel.h"
|
2022-11-09 06:58:19 +03:00
|
|
|
#include "CommandCompleter.h"
|
2021-02-21 20:40:21 +03:00
|
|
|
#include "CompletionProxyModel.h"
|
2021-04-27 12:33:46 +03:00
|
|
|
#include "EventAccessors.h"
|
2023-05-19 04:15:55 +03:00
|
|
|
#include "GridImagePackModel.h"
|
2021-07-21 14:37:57 +03:00
|
|
|
#include "ImagePackListModel.h"
|
2021-06-11 03:13:12 +03:00
|
|
|
#include "InviteesModel.h"
|
2018-07-17 16:37:25 +03:00
|
|
|
#include "Logging.h"
|
2020-09-03 18:01:58 +03:00
|
|
|
#include "MainWindow.h"
|
2020-01-17 03:25:14 +03:00
|
|
|
#include "MatrixClient.h"
|
2021-02-21 20:40:21 +03:00
|
|
|
#include "RoomsModel.h"
|
2019-11-09 05:06:10 +03:00
|
|
|
#include "UserSettingsPage.h"
|
2021-02-21 20:40:21 +03:00
|
|
|
#include "UsersModel.h"
|
2022-06-16 02:19:26 +03:00
|
|
|
#include "Utils.h"
|
|
|
|
#include "encryption/VerificationManager.h"
|
|
|
|
#include "voip/CallManager.h"
|
|
|
|
#include "voip/WebRTCSession.h"
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2021-04-27 12:33:46 +03:00
|
|
|
namespace {
|
|
|
|
template<template<class...> class Op, class... Args>
|
|
|
|
using is_detected = typename nheko::detail::detector<nheko::nonesuch, void, Op, Args...>::value_t;
|
|
|
|
|
|
|
|
template<class Content>
|
|
|
|
using file_t = decltype(Content::file);
|
|
|
|
|
|
|
|
template<class Content>
|
|
|
|
using url_t = decltype(Content::url);
|
|
|
|
|
|
|
|
template<class Content>
|
|
|
|
using body_t = decltype(Content::body);
|
|
|
|
|
|
|
|
template<class Content>
|
|
|
|
using formatted_body_t = decltype(Content::formatted_body);
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
static constexpr bool
|
|
|
|
messageWithFileAndUrl(const mtx::events::Event<T> &)
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
return is_detected<file_t, T>::value && is_detected<url_t, T>::value;
|
2021-04-27 12:33:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
static constexpr void
|
|
|
|
removeReplyFallback(mtx::events::Event<T> &e)
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if constexpr (is_detected<body_t, T>::value) {
|
|
|
|
if constexpr (std::is_same_v<std::optional<std::string>,
|
|
|
|
std::remove_cv_t<decltype(e.content.body)>>) {
|
|
|
|
if (e.content.body) {
|
|
|
|
e.content.body = utils::stripReplyFromBody(e.content.body);
|
|
|
|
}
|
|
|
|
} else if constexpr (std::is_same_v<std::string,
|
|
|
|
std::remove_cv_t<decltype(e.content.body)>>) {
|
|
|
|
e.content.body = utils::stripReplyFromBody(e.content.body);
|
2021-04-27 12:33:46 +03:00
|
|
|
}
|
2021-09-18 01:22:33 +03:00
|
|
|
}
|
2021-04-27 12:33:46 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
if constexpr (is_detected<formatted_body_t, T>::value) {
|
|
|
|
if (e.content.format == "org.matrix.custom.html") {
|
|
|
|
e.content.formatted_body = utils::stripReplyFromFormattedBody(e.content.formatted_body);
|
2021-04-27 12:33:46 +03:00
|
|
|
}
|
2021-09-18 01:22:33 +03:00
|
|
|
}
|
2021-04-27 12:33:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-17 23:50:18 +03:00
|
|
|
void
|
2019-11-09 05:06:10 +03:00
|
|
|
TimelineViewManager::updateColorPalette()
|
2018-07-17 23:50:18 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
userColors.clear();
|
2018-07-17 23:50:18 +03:00
|
|
|
}
|
|
|
|
|
2020-02-20 22:51:07 +03:00
|
|
|
QColor
|
|
|
|
TimelineViewManager::userColor(QString id, QColor background)
|
|
|
|
{
|
2021-11-19 00:33:45 +03:00
|
|
|
QPair<QString, quint64> idx{id, background.rgba64()};
|
|
|
|
if (!userColors.contains(idx))
|
|
|
|
userColors.insert(idx, QColor(utils::generateContrastingHexColor(id, background)));
|
|
|
|
return userColors.value(idx);
|
2020-02-20 22:51:07 +03:00
|
|
|
}
|
|
|
|
|
2022-01-12 21:09:46 +03:00
|
|
|
TimelineViewManager::TimelineViewManager(CallManager *, ChatPage *parent)
|
2021-05-30 01:23:57 +03:00
|
|
|
: QObject(parent)
|
2021-05-28 23:14:59 +03:00
|
|
|
, rooms_(new RoomlistModel(this))
|
2023-06-19 02:38:40 +03:00
|
|
|
, frooms_(new FilteredRoomlistModel(this->rooms_))
|
2021-06-10 00:52:28 +03:00
|
|
|
, communities_(new CommunitiesModel(this))
|
2021-10-15 03:44:48 +03:00
|
|
|
, verificationManager_(new VerificationManager(this))
|
2021-12-30 06:54:03 +03:00
|
|
|
, presenceEmitter(new PresenceEmitter(this))
|
2017-04-13 04:11:22 +03:00
|
|
|
{
|
2023-06-19 02:38:40 +03:00
|
|
|
instance_ = this;
|
|
|
|
|
|
|
|
connect(this->communities_,
|
|
|
|
&CommunitiesModel::currentTagIdChanged,
|
|
|
|
frooms_,
|
|
|
|
&FilteredRoomlistModel::updateFilterTag);
|
|
|
|
connect(this->communities_,
|
|
|
|
&CommunitiesModel::hiddenTagsChanged,
|
|
|
|
frooms_,
|
|
|
|
&FilteredRoomlistModel::updateHiddenTagsAndSpaces);
|
2021-09-18 01:22:33 +03:00
|
|
|
|
|
|
|
updateColorPalette();
|
2022-01-12 21:09:46 +03:00
|
|
|
|
|
|
|
connect(UserSettings::instance().get(),
|
|
|
|
&UserSettings::themeChanged,
|
|
|
|
this,
|
|
|
|
&TimelineViewManager::updateColorPalette);
|
2021-12-29 08:10:08 +03:00
|
|
|
connect(parent,
|
2021-09-18 01:22:33 +03:00
|
|
|
&ChatPage::receivedRoomDeviceVerificationRequest,
|
2021-10-15 03:44:48 +03:00
|
|
|
verificationManager_,
|
|
|
|
&VerificationManager::receivedRoomDeviceVerificationRequest);
|
2021-12-29 08:10:08 +03:00
|
|
|
connect(parent,
|
2021-09-18 01:22:33 +03:00
|
|
|
&ChatPage::receivedDeviceVerificationRequest,
|
2021-10-15 03:44:48 +03:00
|
|
|
verificationManager_,
|
|
|
|
&VerificationManager::receivedDeviceVerificationRequest);
|
2021-12-29 08:10:08 +03:00
|
|
|
connect(parent,
|
2021-09-18 01:22:33 +03:00
|
|
|
&ChatPage::receivedDeviceVerificationStart,
|
2021-10-15 03:44:48 +03:00
|
|
|
verificationManager_,
|
|
|
|
&VerificationManager::receivedDeviceVerificationStart);
|
2021-09-18 01:22:33 +03:00
|
|
|
connect(parent, &ChatPage::loggedOut, this, [this]() {
|
|
|
|
isInitialSync_ = true;
|
|
|
|
emit initialSyncChanged(true);
|
|
|
|
});
|
2022-01-26 04:16:06 +03:00
|
|
|
connect(parent, &ChatPage::connectionLost, this, [this] {
|
|
|
|
isConnected_ = false;
|
|
|
|
emit isConnectedChanged(false);
|
|
|
|
});
|
|
|
|
connect(parent, &ChatPage::connectionRestored, this, [this] {
|
|
|
|
isConnected_ = true;
|
|
|
|
emit isConnectedChanged(true);
|
|
|
|
});
|
2023-01-07 03:39:08 +03:00
|
|
|
connect(rooms_, &RoomlistModel::spaceSelected, communities_, [this](QString roomId) {
|
|
|
|
communities_->setCurrentTagId("space:" + roomId);
|
|
|
|
});
|
2022-01-13 06:16:11 +03:00
|
|
|
}
|
|
|
|
|
2021-07-22 01:56:20 +03:00
|
|
|
void
|
2021-08-14 00:58:26 +03:00
|
|
|
TimelineViewManager::openRoomMembers(TimelineModel *room)
|
2021-07-22 01:56:20 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (!room)
|
|
|
|
return;
|
2022-02-21 07:01:01 +03:00
|
|
|
MemberList *memberList = new MemberList(room->roomId());
|
|
|
|
QQmlEngine::setObjectOwnership(memberList, QQmlEngine::JavaScriptOwnership);
|
2021-09-18 01:22:33 +03:00
|
|
|
emit openRoomMembersDialog(memberList, room);
|
2021-07-22 01:56:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimelineViewManager::openRoomSettings(QString room_id)
|
|
|
|
{
|
2022-02-21 07:01:01 +03:00
|
|
|
RoomSettings *settings = new RoomSettings(room_id);
|
2021-09-18 01:22:33 +03:00
|
|
|
connect(rooms_->getRoomById(room_id).data(),
|
|
|
|
&TimelineModel::roomAvatarUrlChanged,
|
|
|
|
settings,
|
|
|
|
&RoomSettings::avatarChanged);
|
2022-02-21 07:01:01 +03:00
|
|
|
QQmlEngine::setObjectOwnership(settings, QQmlEngine::JavaScriptOwnership);
|
2021-09-18 01:22:33 +03:00
|
|
|
emit openRoomSettingsDialog(settings);
|
2021-07-22 01:56:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimelineViewManager::openInviteUsers(QString roomId)
|
|
|
|
{
|
2023-02-26 07:19:15 +03:00
|
|
|
InviteesModel *model = new InviteesModel{rooms_->getRoomById(roomId).data()};
|
2021-09-18 01:22:33 +03:00
|
|
|
connect(model, &InviteesModel::accept, this, [this, model, roomId]() {
|
|
|
|
emit inviteUsers(roomId, model->mxids());
|
|
|
|
});
|
2022-02-21 07:01:01 +03:00
|
|
|
QQmlEngine::setObjectOwnership(model, QQmlEngine::JavaScriptOwnership);
|
2021-09-18 01:22:33 +03:00
|
|
|
emit openInviteUsersDialog(model);
|
2021-07-22 01:56:20 +03:00
|
|
|
}
|
|
|
|
|
2021-07-22 14:55:12 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::openGlobalUserProfile(QString userId)
|
2021-07-22 03:38:18 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
UserProfile *profile = new UserProfile{QString{}, userId, this};
|
2022-02-21 07:01:01 +03:00
|
|
|
QQmlEngine::setObjectOwnership(profile, QQmlEngine::JavaScriptOwnership);
|
2021-09-18 01:22:33 +03:00
|
|
|
emit openProfile(profile);
|
2021-07-22 03:38:18 +03:00
|
|
|
}
|
|
|
|
|
2022-03-27 00:28:31 +03:00
|
|
|
UserProfile *
|
2022-03-27 00:25:48 +03:00
|
|
|
TimelineViewManager::getGlobalUserProfile(QString userId)
|
|
|
|
{
|
|
|
|
UserProfile *profile = new UserProfile{QString{}, userId, this};
|
|
|
|
QQmlEngine::setObjectOwnership(profile, QQmlEngine::JavaScriptOwnership);
|
2022-03-27 00:28:31 +03:00
|
|
|
return (profile);
|
2022-03-27 00:25:48 +03:00
|
|
|
}
|
|
|
|
|
2020-10-27 20:14:06 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::setVideoCallItem()
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
WebRTCSession::instance().setVideoItem(
|
2022-01-12 21:09:46 +03:00
|
|
|
MainWindow::instance()->rootObject()->findChild<QQuickItem *>(
|
|
|
|
QStringLiteral("videoCallItem")));
|
2017-11-15 19:38:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-11-21 00:48:04 +03:00
|
|
|
TimelineViewManager::sync(const mtx::responses::Sync &sync_)
|
2021-05-19 20:34:10 +03:00
|
|
|
{
|
2021-11-21 00:48:04 +03:00
|
|
|
this->rooms_->sync(sync_);
|
|
|
|
this->communities_->sync(sync_);
|
2021-12-30 06:54:03 +03:00
|
|
|
this->presenceEmitter->sync(sync_.presence);
|
2023-09-08 00:10:04 +03:00
|
|
|
this->processIgnoredUsers(sync_.account_data);
|
2017-09-03 11:43:45 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
if (isInitialSync_) {
|
|
|
|
this->isInitialSync_ = false;
|
|
|
|
emit initialSyncChanged(false);
|
|
|
|
}
|
2017-04-13 04:11:22 +03:00
|
|
|
}
|
|
|
|
|
2021-04-29 20:09:16 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::showEvent(const QString &room_id, const QString &event_id)
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (auto room = rooms_->getRoomById(room_id)) {
|
2022-05-07 20:03:58 +03:00
|
|
|
auto exWin = MainWindow::instance()->windowForRoom(room_id);
|
|
|
|
if (exWin) {
|
2023-02-01 20:24:25 +03:00
|
|
|
exWin->setVisible(true);
|
|
|
|
exWin->raise();
|
2022-05-07 20:03:58 +03:00
|
|
|
exWin->requestActivate();
|
2023-02-01 20:24:25 +03:00
|
|
|
} else {
|
2021-09-18 01:22:33 +03:00
|
|
|
rooms_->setCurrentRoom(room_id);
|
2023-02-01 20:24:25 +03:00
|
|
|
MainWindow::instance()->setVisible(true);
|
|
|
|
MainWindow::instance()->raise();
|
2022-01-12 21:09:46 +03:00
|
|
|
MainWindow::instance()->requestActivate();
|
2021-09-18 01:22:33 +03:00
|
|
|
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
2021-04-29 20:09:16 +03:00
|
|
|
}
|
2021-09-18 01:22:33 +03:00
|
|
|
|
|
|
|
room->showEvent(event_id);
|
|
|
|
}
|
2021-04-29 20:09:16 +03:00
|
|
|
}
|
|
|
|
|
2020-09-03 20:51:50 +03:00
|
|
|
QString
|
|
|
|
TimelineViewManager::escapeEmoji(QString str) const
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
return utils::replaceEmoji(str);
|
2020-09-03 20:51:50 +03:00
|
|
|
}
|
|
|
|
|
2017-09-10 12:58:00 +03:00
|
|
|
void
|
2022-05-10 04:19:53 +03:00
|
|
|
TimelineViewManager::openImageOverlay(TimelineModel *room,
|
2022-10-04 00:57:30 +03:00
|
|
|
const QString &mxcUrl,
|
|
|
|
const QString &eventId,
|
2022-05-10 04:19:53 +03:00
|
|
|
double originalWidth,
|
|
|
|
double proportionalHeight)
|
2017-09-10 12:58:00 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (mxcUrl.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
2021-04-05 14:58:00 +03:00
|
|
|
|
2022-05-10 04:19:53 +03:00
|
|
|
emit showImageOverlay(room, eventId, mxcUrl, originalWidth, proportionalHeight);
|
2021-04-05 14:58:00 +03:00
|
|
|
}
|
|
|
|
|
2021-07-21 14:37:57 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::openImagePackSettings(QString roomid)
|
|
|
|
{
|
2022-02-21 07:01:01 +03:00
|
|
|
auto room = rooms_->getRoomById(roomid).get();
|
|
|
|
auto model = new ImagePackListModel(roomid.toStdString());
|
|
|
|
QQmlEngine::setObjectOwnership(model, QQmlEngine::JavaScriptOwnership);
|
|
|
|
emit showImagePackSettings(room, model);
|
2021-07-21 14:37:57 +03:00
|
|
|
}
|
|
|
|
|
2021-04-05 14:58:00 +03:00
|
|
|
void
|
2022-01-02 23:46:29 +03:00
|
|
|
TimelineViewManager::saveMedia(QString mxcUrl)
|
2021-04-05 14:58:00 +03:00
|
|
|
{
|
2022-01-02 23:46:29 +03:00
|
|
|
const QString downloadsFolder =
|
|
|
|
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
2023-06-02 01:24:26 +03:00
|
|
|
const QString openLocation = downloadsFolder + "/" + mxcUrl.split(u'/').constLast();
|
2021-04-05 14:58:00 +03:00
|
|
|
|
2022-01-12 21:09:46 +03:00
|
|
|
const QString filename = QFileDialog::getSaveFileName(nullptr, {}, openLocation);
|
2021-05-28 23:14:59 +03:00
|
|
|
|
2022-01-02 23:46:29 +03:00
|
|
|
if (filename.isEmpty())
|
|
|
|
return;
|
2021-06-11 22:25:06 +03:00
|
|
|
|
2022-01-02 23:46:29 +03:00
|
|
|
const auto url = mxcUrl.toStdString();
|
|
|
|
|
|
|
|
http::client()->download(url,
|
|
|
|
[filename, url](const std::string &data,
|
|
|
|
const std::string &,
|
|
|
|
const std::string &,
|
|
|
|
mtx::http::RequestErr err) {
|
|
|
|
if (err) {
|
|
|
|
nhlog::net()->warn("failed to retrieve image {}: {} {}",
|
|
|
|
url,
|
|
|
|
err->matrix_error.error,
|
|
|
|
static_cast<int>(err->status_code));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
QFile file(filename);
|
|
|
|
|
|
|
|
if (!file.open(QIODevice::WriteOnly))
|
|
|
|
return;
|
|
|
|
|
|
|
|
file.write(QByteArray(data.data(), (int)data.size()));
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
} catch (const std::exception &e) {
|
|
|
|
nhlog::ui()->warn("Error while saving file to: {}", e.what());
|
|
|
|
}
|
|
|
|
});
|
2017-12-01 18:33:49 +03:00
|
|
|
}
|
|
|
|
|
2023-04-23 21:55:28 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::copyImage(const QString &mxcUrl) const
|
|
|
|
{
|
|
|
|
const auto url = mxcUrl.toStdString();
|
|
|
|
QString mimeType;
|
|
|
|
|
|
|
|
http::client()->download(
|
|
|
|
url,
|
|
|
|
[url, mimeType](const std::string &data,
|
|
|
|
const std::string &,
|
|
|
|
const std::string &,
|
|
|
|
mtx::http::RequestErr err) {
|
|
|
|
if (err) {
|
|
|
|
nhlog::net()->warn("failed to retrieve media {}: {} {}",
|
|
|
|
url,
|
|
|
|
err->matrix_error.error,
|
|
|
|
static_cast<int>(err->status_code));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
auto img = utils::readImage(QByteArray(data.data(), (qsizetype)data.size()));
|
|
|
|
QGuiApplication::clipboard()->setImage(img);
|
|
|
|
|
|
|
|
return;
|
|
|
|
} catch (const std::exception &e) {
|
|
|
|
nhlog::ui()->warn("Error while copying file to clipboard: {}", e.what());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (auto room = rooms_->getRoomById(room_id)) {
|
|
|
|
room->markEventsAsRead(event_ids);
|
|
|
|
}
|
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)
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (auto room = rooms_->getRoomById(QString::fromStdString(room_id))) {
|
|
|
|
room->receivedSessionKey(session_id);
|
|
|
|
}
|
2020-10-20 20:46:37 +03:00
|
|
|
}
|
|
|
|
|
2018-06-28 16:16:43 +03:00
|
|
|
void
|
2021-05-24 15:04:07 +03:00
|
|
|
TimelineViewManager::initializeRoomlist()
|
2018-06-28 16:16:43 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
rooms_->initializeRooms();
|
|
|
|
communities_->initializeSidebar();
|
2018-06-28 16:16:43 +03:00
|
|
|
}
|
|
|
|
|
2021-01-07 12:44:59 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::queueReply(const QString &roomid,
|
|
|
|
const QString &repliedToEvent,
|
|
|
|
const QString &replyBody)
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (auto room = rooms_->getRoomById(roomid)) {
|
|
|
|
room->setReply(repliedToEvent);
|
|
|
|
room->input()->message(replyBody);
|
|
|
|
}
|
2021-01-07 12:44:59 +03:00
|
|
|
}
|
|
|
|
|
2020-07-11 02:19:48 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
2022-06-27 19:09:31 +03:00
|
|
|
const mtx::events::voip::CallInvite &callInvite)
|
2020-07-11 02:19:48 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (auto room = rooms_->getRoomById(roomid))
|
|
|
|
room->sendMessageEvent(callInvite, mtx::events::EventType::CallInvite);
|
2020-07-11 02:19:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
2022-06-27 19:09:31 +03:00
|
|
|
const mtx::events::voip::CallCandidates &callCandidates)
|
2020-07-11 02:19:48 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (auto room = rooms_->getRoomById(roomid))
|
|
|
|
room->sendMessageEvent(callCandidates, mtx::events::EventType::CallCandidates);
|
2020-07-11 02:19:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
2022-06-27 19:09:31 +03:00
|
|
|
const mtx::events::voip::CallAnswer &callAnswer)
|
2020-07-11 02:19:48 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (auto room = rooms_->getRoomById(roomid))
|
|
|
|
room->sendMessageEvent(callAnswer, mtx::events::EventType::CallAnswer);
|
2020-07-11 02:19:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
2022-06-27 19:09:31 +03:00
|
|
|
const mtx::events::voip::CallHangUp &callHangUp)
|
2020-07-11 02:19:48 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (auto room = rooms_->getRoomById(roomid))
|
|
|
|
room->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
|
2017-10-07 20:50:32 +03:00
|
|
|
}
|
2021-02-05 20:12:08 +03:00
|
|
|
|
2022-10-14 16:49:05 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
|
|
|
const mtx::events::voip::CallSelectAnswer &callSelectAnswer)
|
|
|
|
{
|
|
|
|
if (auto room = rooms_->getRoomById(roomid))
|
|
|
|
room->sendMessageEvent(callSelectAnswer, mtx::events::EventType::CallSelectAnswer);
|
|
|
|
}
|
|
|
|
void
|
|
|
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
|
|
|
const mtx::events::voip::CallReject &callReject)
|
|
|
|
{
|
|
|
|
if (auto room = rooms_->getRoomById(roomid))
|
|
|
|
room->sendMessageEvent(callReject, mtx::events::EventType::CallReject);
|
|
|
|
}
|
|
|
|
void
|
|
|
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
|
|
|
const mtx::events::voip::CallNegotiate &callNegotiate)
|
|
|
|
{
|
|
|
|
if (auto room = rooms_->getRoomById(roomid))
|
|
|
|
room->sendMessageEvent(callNegotiate, mtx::events::EventType::CallNegotiate);
|
|
|
|
}
|
|
|
|
|
2021-02-05 20:12:08 +03:00
|
|
|
void
|
|
|
|
TimelineViewManager::focusMessageInput()
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
emit focusInput();
|
2021-02-14 03:28:28 +03:00
|
|
|
}
|
2021-02-21 20:40:21 +03:00
|
|
|
|
2023-06-19 21:08:10 +03:00
|
|
|
QAbstractItemModel *
|
2022-10-04 00:57:30 +03:00
|
|
|
TimelineViewManager::completerFor(const QString &completerName, const QString &roomId)
|
2021-02-21 20:40:21 +03:00
|
|
|
{
|
2021-12-29 06:28:08 +03:00
|
|
|
if (completerName == QLatin1String("user")) {
|
2021-09-18 01:22:33 +03:00
|
|
|
auto userModel = new UsersModel(roomId.toStdString());
|
|
|
|
auto proxy = new CompletionProxyModel(userModel);
|
|
|
|
userModel->setParent(proxy);
|
|
|
|
return proxy;
|
2021-12-29 06:28:08 +03:00
|
|
|
} else if (completerName == QLatin1String("emoji")) {
|
2023-05-25 22:50:54 +03:00
|
|
|
auto emojiModel = new CombinedImagePackModel(roomId.toStdString());
|
2021-09-18 01:22:33 +03:00
|
|
|
auto proxy = new CompletionProxyModel(emojiModel);
|
|
|
|
emojiModel->setParent(proxy);
|
|
|
|
return proxy;
|
2021-12-29 06:28:08 +03:00
|
|
|
} else if (completerName == QLatin1String("room")) {
|
2021-09-18 01:22:33 +03:00
|
|
|
auto roomModel = new RoomsModel(false);
|
|
|
|
auto proxy = new CompletionProxyModel(roomModel, 4);
|
|
|
|
roomModel->setParent(proxy);
|
|
|
|
return proxy;
|
2021-12-29 06:28:08 +03:00
|
|
|
} else if (completerName == QLatin1String("roomAliases")) {
|
2021-09-18 01:22:33 +03:00
|
|
|
auto roomModel = new RoomsModel(true);
|
|
|
|
auto proxy = new CompletionProxyModel(roomModel);
|
|
|
|
roomModel->setParent(proxy);
|
|
|
|
return proxy;
|
2023-05-25 20:07:13 +03:00
|
|
|
} else if (completerName == QLatin1String("emojigrid")) {
|
|
|
|
auto stickerModel = new GridImagePackModel(roomId.toStdString(), false);
|
|
|
|
return stickerModel;
|
2023-05-19 04:15:55 +03:00
|
|
|
} else if (completerName == QLatin1String("stickergrid")) {
|
|
|
|
auto stickerModel = new GridImagePackModel(roomId.toStdString(), true);
|
|
|
|
return stickerModel;
|
2022-11-09 06:58:19 +03:00
|
|
|
} else if (completerName == QLatin1String("command")) {
|
2022-11-09 18:38:17 +03:00
|
|
|
auto commandCompleter = new CommandCompleter();
|
|
|
|
auto proxy = new CompletionProxyModel(commandCompleter);
|
2022-11-09 06:58:19 +03:00
|
|
|
commandCompleter->setParent(proxy);
|
|
|
|
return proxy;
|
2021-09-18 01:22:33 +03:00
|
|
|
}
|
|
|
|
return nullptr;
|
2021-02-22 22:16:40 +03:00
|
|
|
}
|
|
|
|
|
2021-04-11 17:31:49 +03:00
|
|
|
void
|
2023-04-11 01:11:46 +03:00
|
|
|
TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEvents const *e,
|
2021-04-17 20:28:04 +03:00
|
|
|
QString roomId)
|
2021-04-11 17:31:49 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
auto room = rooms_->getRoomById(roomId);
|
|
|
|
auto content = mtx::accessors::url(*e);
|
|
|
|
std::optional<mtx::crypto::EncryptedFile> encryptionInfo = mtx::accessors::file(*e);
|
|
|
|
|
2022-12-07 14:47:03 +03:00
|
|
|
if (encryptionInfo && !cache::isRoomEncrypted(roomId.toStdString())) {
|
2021-09-18 01:22:33 +03:00
|
|
|
http::client()->download(
|
|
|
|
content,
|
|
|
|
[this, roomId, e, encryptionInfo](const std::string &res,
|
|
|
|
const std::string &content_type,
|
|
|
|
const std::string &originalFilename,
|
|
|
|
mtx::http::RequestErr err) {
|
|
|
|
if (err)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto data =
|
|
|
|
mtx::crypto::to_string(mtx::crypto::decrypt_file(res, encryptionInfo.value()));
|
|
|
|
|
|
|
|
http::client()->upload(
|
|
|
|
data,
|
|
|
|
content_type,
|
|
|
|
originalFilename,
|
|
|
|
[this, roomId, e](const mtx::responses::ContentURI &res,
|
|
|
|
mtx::http::RequestErr err) mutable {
|
|
|
|
if (err) {
|
|
|
|
nhlog::net()->warn("failed to upload media: {} {} ({})",
|
|
|
|
err->matrix_error.error,
|
|
|
|
to_string(err->matrix_error.errcode),
|
|
|
|
static_cast<int>(err->status_code));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::visit(
|
|
|
|
[this, roomId, url = res.content_uri](auto ev) {
|
|
|
|
using namespace mtx::events;
|
|
|
|
if constexpr (EventType::RoomMessage ==
|
|
|
|
message_content_to_type<decltype(ev.content)> ||
|
|
|
|
EventType::Sticker ==
|
|
|
|
message_content_to_type<decltype(ev.content)>) {
|
|
|
|
if constexpr (messageWithFileAndUrl(ev)) {
|
|
|
|
ev.content.relations.relations.clear();
|
|
|
|
ev.content.file.reset();
|
|
|
|
ev.content.url = url;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto room = rooms_->getRoomById(roomId)) {
|
|
|
|
removeReplyFallback(ev);
|
|
|
|
ev.content.relations.relations.clear();
|
|
|
|
room->sendMessageEvent(ev.content,
|
|
|
|
mtx::events::EventType::RoomMessage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
*e);
|
|
|
|
});
|
2021-04-17 19:58:17 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
return;
|
|
|
|
});
|
2021-04-17 19:58:17 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
return;
|
|
|
|
}
|
2021-04-11 17:31:49 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
std::visit(
|
|
|
|
[room](auto e) {
|
2023-02-20 03:18:06 +03:00
|
|
|
constexpr auto type = mtx::events::message_content_to_type<decltype(e.content)>;
|
|
|
|
if constexpr (type == mtx::events::EventType::RoomMessage ||
|
|
|
|
type == mtx::events::EventType::Sticker) {
|
2021-09-18 01:22:33 +03:00
|
|
|
e.content.relations.relations.clear();
|
|
|
|
removeReplyFallback(e);
|
2023-02-20 03:18:06 +03:00
|
|
|
room->sendMessageEvent(e.content, type);
|
2021-09-18 01:22:33 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
*e);
|
2021-04-27 12:33:46 +03:00
|
|
|
}
|
2021-07-15 01:26:39 +03:00
|
|
|
|
|
|
|
//! WORKAROUND(Nico): for https://bugreports.qt.io/browse/QTBUG-93281
|
|
|
|
void
|
|
|
|
TimelineViewManager::fixImageRendering(QQuickTextDocument *t, QQuickItem *i)
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (t) {
|
|
|
|
QObject::connect(t->textDocument(), SIGNAL(imagesLoaded()), i, SLOT(updateWholeDocument()));
|
|
|
|
}
|
2021-07-15 01:26:39 +03:00
|
|
|
}
|
2023-09-08 00:10:04 +03:00
|
|
|
|
|
|
|
using IgnoredUsers = mtx::events::EphemeralEvent<mtx::events::account_data::IgnoredUsers>;
|
|
|
|
|
2023-09-08 01:17:03 +03:00
|
|
|
static QVector<QString>
|
|
|
|
convertIgnoredToQt(const IgnoredUsers &ev)
|
|
|
|
{
|
2023-09-08 00:10:04 +03:00
|
|
|
QVector<QString> users;
|
|
|
|
for (const mtx::events::account_data::IgnoredUser &user : ev.content.users) {
|
|
|
|
users.push_back(QString::fromStdString(user.id));
|
|
|
|
}
|
|
|
|
|
|
|
|
return users;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<QString>
|
|
|
|
TimelineViewManager::getIgnoredUsers()
|
|
|
|
{
|
|
|
|
const auto cache = cache::client()->getAccountData(mtx::events::EventType::IgnoredUsers);
|
|
|
|
if (!cache) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return convertIgnoredToQt(std::get<IgnoredUsers>(*cache));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-09-08 01:17:03 +03:00
|
|
|
TimelineViewManager::processIgnoredUsers(const mtx::responses::AccountData &data)
|
2023-09-08 00:10:04 +03:00
|
|
|
{
|
|
|
|
for (const mtx::events::collections::RoomAccountDataEvents::variant &ev : data.events) {
|
|
|
|
if (!std::holds_alternative<IgnoredUsers>(ev)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const auto &ignoredEv = std::get<IgnoredUsers>(ev);
|
2023-09-08 01:17:03 +03:00
|
|
|
|
2023-09-08 00:10:04 +03:00
|
|
|
emit this->ignoredUsersChanged(convertIgnoredToQt(ignoredEv));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|