summary refs log tree commit diff
path: root/src/timeline
diff options
context:
space:
mode:
authorJoe <rubberduckie3554@gmail.com>2021-07-24 18:26:25 -0400
committerJoe <rubberduckie3554@gmail.com>2021-07-24 18:26:25 -0400
commit3f567a8da7f41a2ce094f15340e39ea8aec55fb3 (patch)
tree42b6f59f0fa36ad738133198333cccf0c4100621 /src/timeline
parentRemove 'respond to key requests' functionality (diff)
parentFix edge case that could lead to no new one time keys being uploaded (diff)
downloadnheko-3f567a8da7f41a2ce094f15340e39ea8aec55fb3.tar.xz
Merge master and fix conflicts
Diffstat (limited to 'src/timeline')
-rw-r--r--src/timeline/InputBar.cpp26
-rw-r--r--src/timeline/InputBar.h2
-rw-r--r--src/timeline/Permissions.cpp6
-rw-r--r--src/timeline/Permissions.h4
-rw-r--r--src/timeline/TimelineModel.cpp35
-rw-r--r--src/timeline/TimelineModel.h33
-rw-r--r--src/timeline/TimelineViewManager.cpp82
-rw-r--r--src/timeline/TimelineViewManager.h17
8 files changed, 166 insertions, 39 deletions
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp

index b0747a7c..f17081e5 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp
@@ -19,6 +19,7 @@ #include "Cache.h" #include "ChatPage.h" +#include "CombinedImagePackModel.h" #include "CompletionProxyModel.h" #include "Config.h" #include "Logging.h" @@ -502,6 +503,31 @@ InputBar::video(const QString &filename, } void +InputBar::sticker(CombinedImagePackModel *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..2e6fb5c0 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h
@@ -12,6 +12,7 @@ #include <mtx/responses/messages.hpp> class TimelineModel; +class CombinedImagePackModel; 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(CombinedImagePackModel *model, int row); private slots: void startTyping(); diff --git a/src/timeline/Permissions.cpp b/src/timeline/Permissions.cpp
index 1eaab468..e4957045 100644 --- a/src/timeline/Permissions.cpp +++ b/src/timeline/Permissions.cpp
@@ -8,9 +8,9 @@ #include "MatrixClient.h" #include "TimelineModel.h" -Permissions::Permissions(TimelineModel *parent) +Permissions::Permissions(QString roomId, QObject *parent) : QObject(parent) - , room(parent) + , roomId_(roomId) { invalidate(); } @@ -19,7 +19,7 @@ void Permissions::invalidate() { pl = cache::client() - ->getStateEvent<mtx::events::state::PowerLevels>(room->roomId().toStdString()) + ->getStateEvent<mtx::events::state::PowerLevels>(roomId_.toStdString()) .value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{}) .content; } diff --git a/src/timeline/Permissions.h b/src/timeline/Permissions.h
index f7e6f389..7aab1ddb 100644 --- a/src/timeline/Permissions.h +++ b/src/timeline/Permissions.h
@@ -15,7 +15,7 @@ class Permissions : public QObject Q_OBJECT public: - Permissions(TimelineModel *parent); + Permissions(QString roomId, QObject *parent = nullptr); Q_INVOKABLE bool canInvite(); Q_INVOKABLE bool canBan(); @@ -28,6 +28,6 @@ public: void invalidate(); private: - TimelineModel *room; + QString roomId_; mtx::events::state::PowerLevels pl; }; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index ab11f99b..ee5564a5 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp
@@ -25,6 +25,7 @@ #include "Logging.h" #include "MainWindow.h" #include "MatrixClient.h" +#include "MemberList.h" #include "MxcImageProvider.h" #include "Olm.h" #include "TimelineViewManager.h" @@ -317,6 +318,7 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj , events(room_id.toStdString(), this) , room_id_(room_id) , manager_(manager) + , permissions_{room_id} { lastMessage_.timestamp = 0; @@ -325,6 +327,10 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj this->isSpace_ = create->content.type == mtx::events::state::room_type::space; this->isEncrypted_ = cache::isRoomEncrypted(room_id_.toStdString()); + // this connection will simplify adding the plainRoomNameChanged() signal everywhere that it + // needs to be + connect(this, &TimelineModel::roomNameChanged, this, &TimelineModel::plainRoomNameChanged); + connect( this, &TimelineModel::redactionFailed, @@ -344,6 +350,7 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj &EventStore::dataChanged, this, [this](int from, int to) { + relatedEventCacheBuster++; nhlog::ui()->debug( "data changed {} to {}", events.size() - to - 1, events.size() - from - 1); emit dataChanged(index(events.size() - to - 1, 0), @@ -443,6 +450,7 @@ TimelineModel::roleNames() const {RoomTopic, "roomTopic"}, {CallType, "callType"}, {Dump, "dump"}, + {RelatedEventCacheBuster, "relatedEventCacheBuster"}, }; } int @@ -676,6 +684,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r return QVariant(m); } + case RelatedEventCacheBuster: + return relatedEventCacheBuster; default: return QVariant(); } @@ -710,6 +720,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 { @@ -1049,14 +1067,6 @@ TimelineModel::openUserProfile(QString userid) } void -TimelineModel::openRoomSettings() -{ - RoomSettings *settings = new RoomSettings(roomId(), this); - connect(this, &TimelineModel::roomAvatarUrlChanged, settings, &RoomSettings::avatarChanged); - openRoomSettingsDialog(settings); -} - -void TimelineModel::replyAction(QString id) { setReply(id); @@ -1292,6 +1302,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 +1319,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..0e2ce153 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h
@@ -17,6 +17,8 @@ #include "CacheStructs.h" #include "EventStore.h" #include "InputBar.h" +#include "InviteesModel.h" +#include "MemberList.h" #include "Permissions.h" #include "ui/RoomSettings.h" #include "ui/UserProfile.h" @@ -158,7 +160,9 @@ class TimelineModel : public QAbstractListModel Q_PROPERTY(QString edit READ edit WRITE setEdit NOTIFY editChanged RESET resetEdit) Q_PROPERTY( bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged) + Q_PROPERTY(QString roomId READ roomId CONSTANT) Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) + Q_PROPERTY(QString plainRoomName READ plainRoomName NOTIFY plainRoomNameChanged) Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged) Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged) Q_PROPERTY(int roomMemberCount READ roomMemberCount NOTIFY roomMemberCountChanged) @@ -208,6 +212,7 @@ public: RoomTopic, CallType, Dump, + RelatedEventCacheBuster, }; Q_ENUM(Roles); @@ -215,10 +220,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; @@ -237,7 +239,6 @@ public: Q_INVOKABLE void forwardMessage(QString eventId, QString roomId); Q_INVOKABLE void viewDecryptedRawMessage(QString id) const; Q_INVOKABLE void openUserProfile(QString userid); - Q_INVOKABLE void openRoomSettings(); Q_INVOKABLE void editAction(QString id); Q_INVOKABLE void replyAction(QString id); Q_INVOKABLE void readReceiptsAction(QString id) const; @@ -354,14 +355,13 @@ signals: void lastMessageChanged(); void notificationsChanged(); - void openRoomSettingsDialog(RoomSettings *settings); - void newMessageToSend(mtx::events::collections::TimelineEvents event); void addPendingMessageToStore(mtx::events::collections::TimelineEvents event); void updateFlowEventId(std::string event_id); void encryptionChanged(); void roomNameChanged(); + void plainRoomNameChanged(); void roomTopicChanged(); void roomAvatarUrlChanged(); void roomMemberCountChanged(); @@ -391,7 +391,7 @@ private: TimelineViewManager *manager_; InputBar input_{this}; - Permissions permissions_{this}; + Permissions permissions_; QTimer showEventTimer{this}; QString eventIdToShow; @@ -403,6 +403,8 @@ private: int notification_count = 0, highlight_count = 0; + unsigned int relatedEventCacheBuster = 0; + bool decryptDescription = true; bool m_paginationInProgress = false; bool isSpace_ = false; @@ -413,10 +415,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..a6922be7 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp
@@ -15,15 +15,19 @@ #include "ChatPage.h" #include "Clipboard.h" #include "ColorImageProvider.h" +#include "CombinedImagePackModel.h" #include "CompletionProxyModel.h" #include "DelegateChooser.h" #include "DeviceVerificationFlow.h" #include "EventAccessors.h" +#include "ImagePackListModel.h" +#include "InviteesModel.h" #include "Logging.h" #include "MainWindow.h" #include "MatrixClient.h" #include "MxcImageProvider.h" #include "RoomsModel.h" +#include "SingleImagePackModel.h" #include "UserSettingsPage.h" #include "UsersModel.h" #include "dialogs/ImageOverlay.h" @@ -144,6 +148,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par qRegisterMetaType<mtx::events::msg::KeyVerificationReady>(); qRegisterMetaType<mtx::events::msg::KeyVerificationRequest>(); qRegisterMetaType<mtx::events::msg::KeyVerificationStart>(); + qRegisterMetaType<CombinedImagePackModel *>(); qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject, "im.nheko", @@ -172,6 +177,8 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par 0, "UserProfileModel", "UserProfile needs to be instantiated on the C++ side"); + qmlRegisterUncreatableType<MemberList>( + "im.nheko", 1, 0, "MemberList", "MemberList needs to be instantiated on the C++ side"); qmlRegisterUncreatableType<RoomSettings>( "im.nheko", 1, @@ -180,6 +187,24 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par "Room Settings needs to be instantiated on the C++ side"); qmlRegisterUncreatableType<TimelineModel>( "im.nheko", 1, 0, "Room", "Room needs to be instantiated on the C++ side"); + qmlRegisterUncreatableType<ImagePackListModel>( + "im.nheko", + 1, + 0, + "ImagePackListModel", + "ImagePackListModel needs to be instantiated on the C++ side"); + qmlRegisterUncreatableType<SingleImagePackModel>( + "im.nheko", + 1, + 0, + "SingleImagePackModel", + "SingleImagePackModel needs to be instantiated on the C++ side"); + qmlRegisterUncreatableType<InviteesModel>( + "im.nheko", + 1, + 0, + "InviteesModel", + "InviteesModel needs to be instantiated on the C++ side"); static auto self = this; qmlRegisterSingletonType<MainWindow>( @@ -341,6 +366,41 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par } void +TimelineViewManager::openRoomMembers(QString room_id) +{ + MemberList *memberList = new MemberList(room_id, this); + emit openRoomMembersDialog(memberList); +} + +void +TimelineViewManager::openRoomSettings(QString room_id) +{ + RoomSettings *settings = new RoomSettings(room_id, this); + connect(rooms_->getRoomById(room_id).data(), + &TimelineModel::roomAvatarUrlChanged, + settings, + &RoomSettings::avatarChanged); + emit openRoomSettingsDialog(settings); +} + +void +TimelineViewManager::openInviteUsers(QString roomId) +{ + InviteesModel *model = new InviteesModel{this}; + connect(model, &InviteesModel::accept, this, [this, model, roomId]() { + emit inviteUsers(roomId, model->mxids()); + }); + emit openInviteUsersDialog(model); +} + +void +TimelineViewManager::openGlobalUserProfile(QString userId) +{ + UserProfile *profile = new UserProfile{QString{}, userId, this}; + emit openProfile(profile); +} + +void TimelineViewManager::setVideoCallItem() { WebRTCSession::instance().setVideoItem( @@ -398,6 +458,12 @@ TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId) } void +TimelineViewManager::openImagePackSettings(QString roomid) +{ + emit showImagePackSettings(new ImagePackListModel(roomid.toStdString(), this)); +} + +void TimelineViewManager::openImageOverlayInternal(QString eventId, QImage img) { auto pixmap = QPixmap::fromImage(img); @@ -420,17 +486,6 @@ TimelineViewManager::openImageOverlayInternal(QString eventId, QImage img) } void -TimelineViewManager::openInviteUsersDialog() -{ - MainWindow::instance()->openInviteUsersDialog( - [this](const QStringList &invitees) { emit inviteUsers(invitees); }); -} -void -TimelineViewManager::openMemberListDialog(QString roomid) const -{ - MainWindow::instance()->openMemberListDialog(roomid); -} -void TimelineViewManager::openLeaveRoomDialog(QString roomid) const { MainWindow::instance()->openLeaveRoomDialog(roomid); @@ -593,6 +648,11 @@ TimelineViewManager::completerFor(QString completerName, QString roomId) auto proxy = new CompletionProxyModel(roomModel); roomModel->setParent(proxy); return proxy; + } else if (completerName == "stickers") { + auto stickerModel = new CombinedImagePackModel(roomId.toStdString(), true); + auto proxy = new CompletionProxyModel(stickerModel, 1, static_cast<size_t>(-1) / 4); + stickerModel->setParent(proxy); + return proxy; } return nullptr; } diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 15b4f523..54e3a935 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h
@@ -33,6 +33,7 @@ class ColorImageProvider; class UserSettings; class ChatPage; class DeviceVerificationFlow; +class ImagePackListModel; class TimelineViewManager : public QObject { @@ -57,6 +58,7 @@ public: Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; } bool isWindowFocused() const { return isWindowFocused_; } Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId); + Q_INVOKABLE void openImagePackSettings(QString roomid); Q_INVOKABLE QColor userColor(QString id, QColor background); Q_INVOKABLE QString escapeEmoji(QString str) const; Q_INVOKABLE QString htmlEscape(QString str) const { return str.toHtmlEscaped(); } @@ -64,9 +66,12 @@ public: Q_INVOKABLE QString userPresence(QString id) const; Q_INVOKABLE QString userStatus(QString id) const; + Q_INVOKABLE void openRoomMembers(QString room_id); + Q_INVOKABLE void openRoomSettings(QString room_id); + Q_INVOKABLE void openInviteUsers(QString roomId); + Q_INVOKABLE void openGlobalUserProfile(QString userId); + Q_INVOKABLE void focusMessageInput(); - Q_INVOKABLE void openInviteUsersDialog(); - Q_INVOKABLE void openMemberListDialog(QString roomid) const; Q_INVOKABLE void openLeaveRoomDialog(QString roomid) const; Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow); @@ -81,11 +86,17 @@ signals: void replyingEventChanged(QString replyingEvent); void replyClosed(); void newDeviceVerificationRequest(DeviceVerificationFlow *flow); - void inviteUsers(QStringList users); + void inviteUsers(QString roomId, QStringList users); + void showRoomList(); + void narrowViewChanged(); void focusChanged(); void focusInput(); void openImageOverlayInternalCb(QString eventId, QImage img); + void openRoomMembersDialog(MemberList *members); + void openRoomSettingsDialog(RoomSettings *settings); + void openInviteUsersDialog(InviteesModel *invitees); void openProfile(UserProfile *profile); + void showImagePackSettings(ImagePackListModel *packlist); public slots: void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);