diff --git a/qml/component/MessageDelegate.qml b/qml/component/MessageDelegate.qml index 745212d..9eeaaa4 100644 --- a/qml/component/MessageDelegate.qml +++ b/qml/component/MessageDelegate.qml @@ -48,7 +48,7 @@ RowLayout { id: genericBubble highlighted: !sentByMe - colored: highlighted && eventType === "notice" + colored: highlighted && (eventType === "notice" || highlight) contentItem: ColumnLayout { id: messageColumn diff --git a/qml/form/RoomForm.qml b/qml/form/RoomForm.qml index 4ec648d..ffce4fa 100644 --- a/qml/form/RoomForm.qml +++ b/qml/form/RoomForm.qml @@ -241,6 +241,8 @@ Item { boundsBehavior: Flickable.DragOverBounds maximumFlickVelocity: 2048 + cacheBuffer: 200 + model: MessageEventModel { id: messageEventModel room: currentRoom diff --git a/qml/form/RoomListForm.qml b/qml/form/RoomListForm.qml index 8448898..d1d90ae 100644 --- a/qml/form/RoomListForm.qml +++ b/qml/form/RoomListForm.qml @@ -123,7 +123,7 @@ Item { Rectangle { anchors.fill: parent - visible: highlighted + visible: highlightCount > 0 || highlighted color: Material.accent opacity: 0.1 } diff --git a/src/matriqueroom.cpp b/src/matriqueroom.cpp index faa36c8..d11da12 100644 --- a/src/matriqueroom.cpp +++ b/src/matriqueroom.cpp @@ -12,7 +12,12 @@ MatriqueRoom::MatriqueRoom(Connection* connection, QString roomId, JoinState joinState) - : Room(connection, std::move(roomId), joinState) {} + : Room(connection, std::move(roomId), joinState) { + connect(this, &MatriqueRoom::notificationCountChanged, this, + &MatriqueRoom::countChanged); + connect(this, &MatriqueRoom::highlightCountChanged, this, + &MatriqueRoom::countChanged); +} void MatriqueRoom::chooseAndUploadFile() { auto localFile = QFileDialog::getOpenFileUrl(Q_NULLPTR, tr("Save File as")); @@ -87,3 +92,35 @@ QString MatriqueRoom::lastEvent() { return user(lastEvent->senderId())->displayname() + ": " + lastEvent->contentJson().value("body").toString(); } + +bool MatriqueRoom::isEventHighlighted(const RoomEvent* e) const { + return highlights.contains(e); +} + +void MatriqueRoom::checkForHighlights(const QMatrixClient::TimelineItem& ti) { + auto localUserId = localUser()->id(); + if (ti->senderId() == localUserId) return; + if (auto* e = ti.viewAs()) { + const auto& text = e->plainBody(); + if (text.contains(localUserId) || + text.contains(roomMembername(localUserId))) + highlights.insert(e); + } +} + +void MatriqueRoom::onAddNewTimelineEvents(timeline_iter_t from) { + std::for_each(from, messageEvents().cend(), + [this](const TimelineItem& ti) { checkForHighlights(ti); }); +} + +void MatriqueRoom::onAddHistoricalTimelineEvents(rev_iter_t from) { + std::for_each(from, messageEvents().crend(), + [this](const TimelineItem& ti) { checkForHighlights(ti); }); +} + +void MatriqueRoom::countChanged() { + if (displayed() && !hasUnreadMessages()) { + resetNotificationCount(); + resetHighlightCount(); + } +} diff --git a/src/matriqueroom.h b/src/matriqueroom.h index 32f13b0..eb0f1bf 100644 --- a/src/matriqueroom.h +++ b/src/matriqueroom.h @@ -30,13 +30,23 @@ class MatriqueRoom : public Room { QString getUsersTyping(); QString lastEvent(); + bool isEventHighlighted(const QMatrixClient::RoomEvent* e) const; private: QString m_cachedInput; + QSet highlights; QString getMIME(const QUrl& fileUrl) const; void postFile(const QUrl& localFile, const QUrl& mxcUrl); + void checkForHighlights(const QMatrixClient::TimelineItem& ti); + + void onAddNewTimelineEvents(timeline_iter_t from) override; + void onAddHistoricalTimelineEvents(rev_iter_t from) override; + + private slots: + void countChanged(); + signals: void cachedInputChanged(); diff --git a/src/messageeventmodel.cpp b/src/messageeventmodel.cpp index 7512840..da3f919 100644 --- a/src/messageeventmodel.cpp +++ b/src/messageeventmodel.cpp @@ -45,7 +45,7 @@ MessageEventModel::MessageEventModel(QObject* parent) MessageEventModel::~MessageEventModel() {} -void MessageEventModel::setRoom(QMatrixClient::Room* room) { +void MessageEventModel::setRoom(MatriqueRoom* room) { if (room == m_currentRoom) return; beginResetModel(); @@ -567,6 +567,8 @@ QVariant MessageEventModel::data(const QModelIndex& idx, int role) const { }; } + if (role == HighlightRole) return m_currentRoom->isEventHighlighted(&evt); + if (role == ReadMarkerRole) return evt.id() == lastReadEventId; if (role == SpecialMarksRole) { diff --git a/src/messageeventmodel.h b/src/messageeventmodel.h index 1d31f33..8161e3e 100644 --- a/src/messageeventmodel.h +++ b/src/messageeventmodel.h @@ -2,13 +2,14 @@ #define MESSAGEEVENTMODEL_H #include "room.h" +#include "matriqueroom.h" #include class MessageEventModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY( - QMatrixClient::Room* room READ getRoom WRITE setRoom NOTIFY roomChanged) + MatriqueRoom* room READ getRoom WRITE setRoom NOTIFY roomChanged) public: enum EventRoles { @@ -35,8 +36,8 @@ class MessageEventModel : public QAbstractListModel { explicit MessageEventModel(QObject* parent = nullptr); ~MessageEventModel(); - QMatrixClient::Room* getRoom() { return m_currentRoom; } - void setRoom(QMatrixClient::Room* room); + MatriqueRoom* getRoom() { return m_currentRoom; } + void setRoom(MatriqueRoom* room); int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, @@ -48,7 +49,7 @@ class MessageEventModel : public QAbstractListModel { void refreshRow(int row); private: - QMatrixClient::Room* m_currentRoom = nullptr; + MatriqueRoom* m_currentRoom = nullptr; QString lastReadEventId; int rowBelowInserted = -1; bool movingEvent = 0; diff --git a/src/roomlistmodel.cpp b/src/roomlistmodel.cpp index 91d1aae..1a460ec 100644 --- a/src/roomlistmodel.cpp +++ b/src/roomlistmodel.cpp @@ -153,6 +153,7 @@ QVariant RoomListModel::data(const QModelIndex& index, int role) const { return RoomType::Normal; } if (role == UnreadCountRole) return room->unreadCount(); + if (role == HighlightCountRole) return room->highlightCount(); if (role == LastEventRole) return room->lastEvent(); if (role == CurrentRoomRole) return QVariant::fromValue(room); return QVariant(); @@ -185,6 +186,7 @@ QHash RoomListModel::roleNames() const { roles[TopicRole] = "topic"; roles[CategoryRole] = "category"; roles[UnreadCountRole] = "unreadCount"; + roles[HighlightCountRole] = "highlightCount"; roles[LastEventRole] = "lastEvent"; roles[CurrentRoomRole] = "currentRoom"; return roles; diff --git a/src/roomlistmodel.h b/src/roomlistmodel.h index 6fa57e9..1091245 100644 --- a/src/roomlistmodel.h +++ b/src/roomlistmodel.h @@ -35,6 +35,7 @@ class RoomListModel : public QAbstractListModel { TopicRole, CategoryRole, UnreadCountRole, + HighlightCountRole, LastEventRole, CurrentRoomRole, };