diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 166c03ec..bee20d60 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -215,8 +215,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
this->current_room_ = room_id;
});
connect(room_list_, &RoomList::roomChanged, splitter, &Splitter::showChatView);
- connect(
- room_list_, &RoomList::roomChanged, view_manager_, &TimelineViewManager::setHistoryView);
connect(room_list_, &RoomList::acceptInvite, this, [this](const QString &room_id) {
joinRoom(room_id);
@@ -982,7 +980,7 @@ ChatPage::leaveRoom(const QString &room_id)
void
ChatPage::changeRoom(const QString &room_id)
{
- view_manager_->setHistoryView(room_id);
+ view_manager_->rooms()->setCurrentRoom(room_id);
room_list_->highlightSelectedRoom(room_id);
}
@@ -1397,7 +1395,8 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
if (sigil1 == "u") {
if (action.isEmpty()) {
- view_manager_->activeTimeline()->openUserProfile(mxid1);
+ if (auto t = view_manager_->rooms()->currentRoom())
+ t->openUserProfile(mxid1);
} else if (action == "chat") {
this->startChat(mxid1);
}
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index cda38b75..a283d24e 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -508,8 +508,7 @@ InputBar::command(QString command, QString args)
} else if (command == "react") {
auto eventId = room->reply();
if (!eventId.isEmpty())
- ChatPage::instance()->timelineManager()->queueReactionMessage(
- eventId, args.trimmed());
+ reaction(eventId, args.trimmed());
} else if (command == "join") {
ChatPage::instance()->joinRoom(args);
} else if (command == "part" || command == "leave") {
@@ -715,3 +714,35 @@ InputBar::stopTyping()
}
});
}
+
+void
+InputBar::reaction(const QString &reactedEvent, const QString &reactionKey)
+{
+ auto reactions = room->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()) {
+ mtx::events::msg::Reaction reaction;
+ mtx::common::Relation rel;
+ rel.rel_type = mtx::common::RelationType::Annotation;
+ rel.event_id = reactedEvent.toStdString();
+ rel.key = reactionKey.toStdString();
+ reaction.relations.relations.push_back(rel);
+
+ room->sendMessageEvent(reaction, mtx::events::EventType::Reaction);
+ // Otherwise, we have previously reacted and the reaction should be redacted
+ } else {
+ room->redactEvent(selfReactedEvent);
+ }
+}
diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h
index 9db16bae..c9728379 100644
--- a/src/timeline/InputBar.h
+++ b/src/timeline/InputBar.h
@@ -56,6 +56,7 @@ public slots:
void message(QString body,
MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED,
bool rainbowify = false);
+ void reaction(const QString &reactedEvent, const QString &reactionKey);
private slots:
void startTyping();
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index 63054aa9..ad4177a4 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -341,6 +341,8 @@ RoomlistModel::clear()
models.clear();
invites.clear();
roomids.clear();
+ currentRoom_ = nullptr;
+ emit currentRoomChanged();
endResetModel();
}
@@ -390,6 +392,17 @@ RoomlistModel::leave(QString roomid)
}
}
+void
+RoomlistModel::setCurrentRoom(QString roomid)
+{
+ nhlog::ui()->debug("Trying to switch to: {}", roomid.toStdString());
+ if (models.contains(roomid)) {
+ currentRoom_ = models.value(roomid);
+ emit currentRoomChanged();
+ nhlog::ui()->debug("Switched to: {}", roomid.toStdString());
+ }
+}
+
namespace {
enum NotificationImportance : short
{
@@ -463,6 +476,11 @@ FilteredRoomlistModel::FilteredRoomlistModel(RoomlistModel *model, QObject *pare
invalidate();
});
+ connect(roomlistmodel,
+ &RoomlistModel::currentRoomChanged,
+ this,
+ &FilteredRoomlistModel::currentRoomChanged);
+
sort(0);
}
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index 2d1e5264..1c6fa833 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -14,12 +14,14 @@
#include <mtx/responses/sync.hpp>
-class TimelineModel;
+#include "TimelineModel.h"
+
class TimelineViewManager;
class RoomlistModel : public QAbstractListModel
{
Q_OBJECT
+ Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged)
public:
enum Roles
{
@@ -69,12 +71,15 @@ public slots:
void acceptInvite(QString roomid);
void declineInvite(QString roomid);
void leave(QString roomid);
+ TimelineModel *currentRoom() const { return currentRoom_.get(); }
+ void setCurrentRoom(QString roomid);
private slots:
void updateReadStatus(const std::map<QString, bool> roomReadStatus_);
signals:
void totalUnreadMessageCountUpdated(int unreadMessages);
+ void currentRoomChanged();
private:
void addRoom(const QString &room_id, bool suppressInsertNotification = false);
@@ -85,12 +90,15 @@ private:
QHash<QString, QSharedPointer<TimelineModel>> models;
std::map<QString, bool> roomReadStatus;
+ QSharedPointer<TimelineModel> currentRoom_;
+
friend class FilteredRoomlistModel;
};
class FilteredRoomlistModel : public QSortFilterProxyModel
{
Q_OBJECT
+ Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged)
public:
FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr);
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
@@ -107,6 +115,12 @@ public slots:
QStringList tags();
void toggleTag(QString roomid, QString tag, bool on);
+ TimelineModel *currentRoom() const { return roomlistmodel->currentRoom(); }
+ void setCurrentRoom(QString roomid) { roomlistmodel->setCurrentRoom(std::move(roomid)); }
+
+signals:
+ void currentRoomChanged();
+
private:
short int calculateImportance(const QModelIndex &idx) const;
RoomlistModel *roomlistmodel;
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 9fa7f8b6..3b3ea423 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -133,7 +133,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
, colorImgProvider(new ColorImageProvider())
, blurhashProvider(new BlurhashProvider())
, callManager_(callManager)
- , rooms(new RoomlistModel(this))
+ , rooms_(new RoomlistModel(this))
{
qRegisterMetaType<mtx::events::msg::KeyVerificationAccept>();
qRegisterMetaType<mtx::events::msg::KeyVerificationCancel>();
@@ -193,7 +193,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
});
qmlRegisterSingletonType<RoomlistModel>(
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
- return new FilteredRoomlistModel(self->rooms);
+ return new FilteredRoomlistModel(self->rooms_);
});
qmlRegisterSingletonType<UserSettings>(
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
@@ -320,9 +320,9 @@ TimelineViewManager::setVideoCallItem()
}
void
-TimelineViewManager::sync(const mtx::responses::Rooms &rooms_)
+TimelineViewManager::sync(const mtx::responses::Rooms &rooms_res)
{
- this->rooms->sync(rooms_);
+ this->rooms_->sync(rooms_res);
if (isInitialSync_) {
this->isInitialSync_ = false;
@@ -331,36 +331,16 @@ TimelineViewManager::sync(const mtx::responses::Rooms &rooms_)
}
void
-TimelineViewManager::setHistoryView(const QString &room_id)
-{
- nhlog::ui()->info("Trying to activate room {}", room_id.toStdString());
-
- if (auto room = rooms->getRoomById(room_id)) {
- timeline_ = room.get();
- emit activeTimelineChanged(timeline_);
- container->setFocus();
- nhlog::ui()->info("Activated room {}", room_id.toStdString());
- }
-}
-
-void
-TimelineViewManager::highlightRoom(const QString &room_id)
-{
- ChatPage::instance()->highlightRoom(room_id);
-}
-
-void
TimelineViewManager::showEvent(const QString &room_id, const QString &event_id)
{
- if (auto room = rooms->getRoomById(room_id)) {
- if (timeline_ != room) {
- timeline_ = room.get();
- emit activeTimelineChanged(timeline_);
+ if (auto room = rooms_->getRoomById(room_id)) {
+ if (rooms_->currentRoom() != room) {
+ rooms_->setCurrentRoom(room_id);
container->setFocus();
nhlog::ui()->info("Activated room {}", room_id.toStdString());
}
- timeline_->showEvent(event_id);
+ room->showEvent(event_id);
}
}
@@ -395,17 +375,20 @@ TimelineViewManager::openImageOverlayInternal(QString eventId, QImage img)
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();
- }
- });
+
+ auto room = rooms_->currentRoom();
+ connect(
+ imgDialog, &dialogs::ImageOverlay::saving, room, [this, eventId, imgDialog, room]() {
+ // hide the overlay while presenting the save dialog for better
+ // cross platform support.
+ imgDialog->hide();
+
+ if (!room->saveMedia(eventId)) {
+ imgDialog->show();
+ } else {
+ imgDialog->close();
+ }
+ });
}
void
@@ -415,14 +398,14 @@ TimelineViewManager::openInviteUsersDialog()
[this](const QStringList &invitees) { emit inviteUsers(invitees); });
}
void
-TimelineViewManager::openMemberListDialog() const
+TimelineViewManager::openMemberListDialog(QString roomid) const
{
- MainWindow::instance()->openMemberListDialog(timeline_->roomId());
+ MainWindow::instance()->openMemberListDialog(roomid);
}
void
-TimelineViewManager::openLeaveRoomDialog() const
+TimelineViewManager::openLeaveRoomDialog(QString roomid) const
{
- MainWindow::instance()->openLeaveRoomDialog(timeline_->roomId());
+ MainWindow::instance()->openLeaveRoomDialog(roomid);
}
void
@@ -439,7 +422,7 @@ TimelineViewManager::verifyUser(QString userid)
room_members.end(),
(userid).toStdString()) != room_members.end()) {
if (auto model =
- rooms->getRoomById(QString::fromStdString(room_id))) {
+ rooms_->getRoomById(QString::fromStdString(room_id))) {
auto flow =
DeviceVerificationFlow::InitiateUserVerification(
this, model.data(), userid);
@@ -485,7 +468,7 @@ void
TimelineViewManager::updateReadReceipts(const QString &room_id,
const std::vector<QString> &event_ids)
{
- if (auto room = rooms->getRoomById(room_id)) {
+ if (auto room = rooms_->getRoomById(room_id)) {
room->markEventsAsRead(event_ids);
}
}
@@ -493,7 +476,7 @@ TimelineViewManager::updateReadReceipts(const QString &room_id,
void
TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::string &session_id)
{
- if (auto room = rooms->getRoomById(QString::fromStdString(room_id))) {
+ if (auto room = rooms_->getRoomById(QString::fromStdString(room_id))) {
room->receivedSessionKey(session_id);
}
}
@@ -501,7 +484,7 @@ TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::s
void
TimelineViewManager::initializeRoomlist()
{
- rooms->initializeRooms();
+ rooms_->initializeRooms();
}
void
@@ -509,51 +492,17 @@ TimelineViewManager::queueReply(const QString &roomid,
const QString &repliedToEvent,
const QString &replyBody)
{
- if (auto room = rooms->getRoomById(roomid)) {
+ if (auto room = rooms_->getRoomById(roomid)) {
room->setReply(repliedToEvent);
room->input()->message(replyBody);
}
}
void
-TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey)
-{
- 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()) {
- mtx::events::msg::Reaction reaction;
- mtx::common::Relation rel;
- rel.rel_type = mtx::common::RelationType::Annotation;
- rel.event_id = reactedEvent.toStdString();
- rel.key = reactionKey.toStdString();
- reaction.relations.relations.push_back(rel);
-
- timeline_->sendMessageEvent(reaction, mtx::events::EventType::Reaction);
- // Otherwise, we have previously reacted and the reaction should be redacted
- } else {
- timeline_->redactEvent(selfReactedEvent);
- }
-}
-void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallInvite &callInvite)
{
- if (auto room = rooms->getRoomById(roomid))
+ if (auto room = rooms_->getRoomById(roomid))
room->sendMessageEvent(callInvite, mtx::events::EventType::CallInvite);
}
@@ -561,7 +510,7 @@ void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallCandidates &callCandidates)
{
- if (auto room = rooms->getRoomById(roomid))
+ if (auto room = rooms_->getRoomById(roomid))
room->sendMessageEvent(callCandidates, mtx::events::EventType::CallCandidates);
}
@@ -569,7 +518,7 @@ void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallAnswer &callAnswer)
{
- if (auto room = rooms->getRoomById(roomid))
+ if (auto room = rooms_->getRoomById(roomid))
room->sendMessageEvent(callAnswer, mtx::events::EventType::CallAnswer);
}
@@ -577,7 +526,7 @@ void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallHangUp &callHangUp)
{
- if (auto room = rooms->getRoomById(roomid))
+ if (auto room = rooms_->getRoomById(roomid))
room->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
}
@@ -629,7 +578,7 @@ void
TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEvents *e,
QString roomId)
{
- auto room = rooms->getRoomById(roomId);
+ auto room = rooms_->getRoomById(roomId);
auto content = mtx::accessors::url(*e);
std::optional<mtx::crypto::EncryptedFile> encryptionInfo = mtx::accessors::file(*e);
@@ -672,7 +621,7 @@ TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEven
ev.content.url = url;
}
- if (auto room = rooms->getRoomById(roomId)) {
+ if (auto room = rooms_->getRoomById(roomId)) {
removeReplyFallback(ev);
ev.content.relations.relations
.clear();
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 37e50804..c4707208 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -36,8 +36,6 @@ class TimelineViewManager : public QObject
Q_OBJECT
Q_PROPERTY(
- TimelineModel *timeline MEMBER timeline_ READ activeTimeline NOTIFY activeTimelineChanged)
- Q_PROPERTY(
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
Q_PROPERTY(
bool isNarrowView MEMBER isNarrowView_ READ isNarrowView NOTIFY narrowViewChanged)
@@ -53,14 +51,8 @@ public:
MxcImageProvider *imageProvider() { return imgProvider; }
CallManager *callManager() { return callManager_; }
- void clearAll()
- {
- timeline_ = nullptr;
- emit activeTimelineChanged(nullptr);
- rooms->clear();
- }
+ void clearAll() { rooms_->clear(); }
- Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; }
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
bool isNarrowView() const { return isNarrowView_; }
bool isWindowFocused() const { return isWindowFocused_; }
@@ -74,8 +66,8 @@ public:
Q_INVOKABLE void focusMessageInput();
Q_INVOKABLE void openInviteUsersDialog();
- Q_INVOKABLE void openMemberListDialog() const;
- Q_INVOKABLE void openLeaveRoomDialog() const;
+ Q_INVOKABLE void openMemberListDialog(QString roomid) const;
+ Q_INVOKABLE void openLeaveRoomDialog(QString roomid) const;
Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
void verifyUser(QString userid);
@@ -107,20 +99,13 @@ public slots:
emit focusChanged();
}
- void setHistoryView(const QString &room_id);
- void highlightRoom(const QString &room_id);
void showEvent(const QString &room_id, const QString &event_id);
void focusTimeline();
- TimelineModel *getHistoryView(const QString &room_id)
- {
- return rooms->getRoomById(room_id).get();
- }
void updateColorPalette();
void queueReply(const QString &roomid,
const QString &repliedToEvent,
const QString &replyBody);
- void queueReactionMessage(const QString &reactedEvent, const QString &reactionKey);
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallInvite &);
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallCandidates &);
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallAnswer &);
@@ -147,6 +132,8 @@ public slots:
QObject *completerFor(QString completerName, QString roomId = "");
void forwardMessageToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
+ RoomlistModel *rooms() { return rooms_; }
+
private slots:
void openImageOverlayInternal(QString eventId, QImage img);
@@ -162,14 +149,13 @@ private:
ColorImageProvider *colorImgProvider;
BlurhashProvider *blurhashProvider;
- TimelineModel *timeline_ = nullptr;
CallManager *callManager_ = nullptr;
bool isInitialSync_ = true;
bool isNarrowView_ = false;
bool isWindowFocused_ = false;
- RoomlistModel *rooms = nullptr;
+ RoomlistModel *rooms_ = nullptr;
QHash<QString, QColor> userColors;
diff --git a/src/ui/NhekoDropArea.cpp b/src/ui/NhekoDropArea.cpp
index 54f48d3c..bbcedd7e 100644
--- a/src/ui/NhekoDropArea.cpp
+++ b/src/ui/NhekoDropArea.cpp
@@ -35,7 +35,7 @@ void
NhekoDropArea::dropEvent(QDropEvent *event)
{
if (event) {
- auto model = ChatPage::instance()->timelineManager()->getHistoryView(roomid_);
+ auto model = ChatPage::instance()->timelineManager()->rooms()->getRoomById(roomid_);
if (model) {
model->input()->insertMimeData(event->mimeData());
}
|