summary refs log tree commit diff
path: root/src/timeline
diff options
context:
space:
mode:
authorDeepBlueV7.X <nicolas.werner@hotmail.de>2021-11-21 22:46:51 +0100
committerGitHub <noreply@github.com>2021-11-21 22:46:51 +0100
commitb1092c0f2f8e0c1899733620becb71b66cb4f644 (patch)
tree93240f07830e865fc8695148fc8cee8cb086a22d /src/timeline
parentReturn nullopt for state events in rooms we are not in (diff)
parentTry to tame Windows headers (diff)
downloadnheko-b1092c0f2f8e0c1899733620becb71b66cb4f644.tar.xz
Merge pull request #822 from Nheko-Reborn/dm-filter
Add a filter for direct chats
Diffstat (limited to 'src/timeline')
-rw-r--r--src/timeline/CommunitiesModel.cpp42
-rw-r--r--src/timeline/CommunitiesModel.h4
-rw-r--r--src/timeline/InputBar.cpp5
-rw-r--r--src/timeline/RoomlistModel.cpp163
-rw-r--r--src/timeline/RoomlistModel.h10
-rw-r--r--src/timeline/TimelineViewManager.cpp6
-rw-r--r--src/timeline/TimelineViewManager.h2
7 files changed, 199 insertions, 33 deletions
diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp

index 47ff521d..90f1532b 100644 --- a/src/timeline/CommunitiesModel.cpp +++ b/src/timeline/CommunitiesModel.cpp
@@ -44,8 +44,23 @@ CommunitiesModel::data(const QModelIndex &index, int role) const case CommunitiesModel::Roles::Id: return ""; } - } else if (index.row() - 1 < spaceOrder_.size()) { - auto id = spaceOrder_.at(index.row() - 1); + } else if (index.row() == 1) { + switch (role) { + case CommunitiesModel::Roles::AvatarUrl: + return QString(":/icons/icons/ui/people.svg"); + case CommunitiesModel::Roles::DisplayName: + return tr("Direct Chats"); + case CommunitiesModel::Roles::Tooltip: + return tr("Show direct chats."); + case CommunitiesModel::Roles::ChildrenHidden: + return false; + case CommunitiesModel::Roles::Hidden: + return hiddentTagIds_.contains("dm"); + case CommunitiesModel::Roles::Id: + return "dm"; + } + } else if (index.row() - 2 < spaceOrder_.size()) { + auto id = spaceOrder_.at(index.row() - 2); switch (role) { case CommunitiesModel::Roles::AvatarUrl: return QString::fromStdString(spaces_.at(id).avatar_url); @@ -59,8 +74,8 @@ CommunitiesModel::data(const QModelIndex &index, int role) const case CommunitiesModel::Roles::Id: return "space:" + id; } - } else if (index.row() - 1 < tags_.size() + spaceOrder_.size()) { - auto tag = tags_.at(index.row() - 1 - spaceOrder_.size()); + } else if (index.row() - 2 < tags_.size() + spaceOrder_.size()) { + auto tag = tags_.at(index.row() - 2 - spaceOrder_.size()); if (tag == "m.favourite") { switch (role) { case CommunitiesModel::Roles::AvatarUrl: @@ -156,11 +171,11 @@ CommunitiesModel::clear() } void -CommunitiesModel::sync(const mtx::responses::Rooms &rooms) +CommunitiesModel::sync(const mtx::responses::Sync &sync_) { bool tagsUpdated = false; - for (const auto &[roomid, room] : rooms.join) { + for (const auto &[roomid, room] : sync_.rooms.join) { (void)roomid; for (const auto &e : room.account_data.events) if (std::holds_alternative< @@ -182,11 +197,18 @@ CommunitiesModel::sync(const mtx::responses::Rooms &rooms) tagsUpdated = true; } } - for (const auto &[roomid, room] : rooms.leave) { + for (const auto &[roomid, room] : sync_.rooms.leave) { (void)room; if (spaceOrder_.contains(QString::fromStdString(roomid))) tagsUpdated = true; } + for (const auto &e : sync_.account_data.events) { + if (std::holds_alternative< + mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(e)) { + tagsUpdated = true; + break; + } + } if (tagsUpdated) initializeSidebar(); @@ -213,6 +235,10 @@ CommunitiesModel::setCurrentTagId(QString tagId) return; } } + } else if (tagId == "dm") { + this->currentTagId_ = tagId; + emit currentTagIdChanged(currentTagId_); + return; } this->currentTagId_ = ""; @@ -239,6 +265,8 @@ CommunitiesModel::toggleTagId(QString tagId) auto idx = spaceOrder_.indexOf(tagId.mid(6)); if (idx != -1) emit dataChanged(index(idx + 1), index(idx + 1), {Hidden}); + } else if (tagId == "dm") { + emit dataChanged(index(1), index(1), {Hidden}); } emit hiddenTagsChanged(); diff --git a/src/timeline/CommunitiesModel.h b/src/timeline/CommunitiesModel.h
index 0440d17f..114e3f94 100644 --- a/src/timeline/CommunitiesModel.h +++ b/src/timeline/CommunitiesModel.h
@@ -37,13 +37,13 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override { (void)parent; - return 1 + tags_.size() + spaceOrder_.size(); + return 2 + tags_.size() + spaceOrder_.size(); } QVariant data(const QModelIndex &index, int role) const override; public slots: void initializeSidebar(); - void sync(const mtx::responses::Rooms &rooms); + void sync(const mtx::responses::Sync &sync_); void clear(); QString currentTagId() const { return currentTagId_; } void setCurrentTagId(QString tagId); diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index 44df3411..bd4f59d8 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp
@@ -645,6 +645,11 @@ InputBar::command(QString command, QString args) return; } nhlog::net()->error("Could not resolve goto: {}", args.toStdString()); + } else if (command == "converttodm") { + utils::markRoomAsDirect(this->room->roomId(), + cache::getMembers(this->room->roomId().toStdString(), 0, -1)); + } else if (command == "converttoroom") { + utils::removeDirectFromRoom(this->room->roomId()); } } diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index cc9ff800..79324628 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp
@@ -95,6 +95,10 @@ RoomlistModel::data(const QModelIndex &index, int role) const return list; } else if (role == Roles::RoomId) { return roomid; + } else if (role == Roles::IsDirect) { + return directChatToUser.count(roomid) > 0; + } else if (role == Roles::DirectChatOtherUserId) { + return directChatToUser.count(roomid) ? directChatToUser.at(roomid).front() : ""; } if (models.contains(roomid)) { @@ -129,10 +133,6 @@ RoomlistModel::data(const QModelIndex &index, int role) const list.push_back(QString::fromStdString(t)); return list; } - case Roles::IsDirect: - return room->isDirect(); - case Roles::DirectChatOtherUserId: - return room->directChatOtherUserId(); default: return {}; } @@ -162,12 +162,6 @@ RoomlistModel::data(const QModelIndex &index, int role) const return false; case Roles::Tags: return QStringList(); - case Roles::IsDirect: - // The list of users from the room doesn't contain the invited - // users, so we won't factor the invite into the count - return room.member_count == 1; - case Roles::DirectChatOtherUserId: - return cache::getMembersFromInvite(roomid.toStdString(), 0, 1).front().user_id; default: return {}; } @@ -199,10 +193,6 @@ RoomlistModel::data(const QModelIndex &index, int role) const return true; case Roles::Tags: return QStringList(); - case Roles::IsDirect: - return false; - case Roles::DirectChatOtherUserId: - return QString{}; // should never be reached default: return {}; } @@ -443,10 +433,69 @@ RoomlistModel::fetchPreview(QString roomid_) const }); } +std::set<QString> +RoomlistModel::updateDMs(mtx::events::AccountDataEvent<mtx::events::account_data::Direct> event) +{ + std::set<QString> roomsToUpdate; + std::map<QString, std::vector<QString>> directChatToUserTemp; + + for (const auto &[user, rooms] : event.content.user_to_rooms) { + QString u = QString::fromStdString(user); + + for (const auto &r : rooms) { + directChatToUserTemp[QString::fromStdString(r)].push_back(u); + } + } + + for (auto l = directChatToUser.begin(), r = directChatToUserTemp.begin(); + l != directChatToUser.end() && r != directChatToUserTemp.end();) { + if (l == directChatToUser.end()) { + while (r != directChatToUserTemp.end()) { + roomsToUpdate.insert(r->first); + ++r; + } + } else if (r == directChatToUserTemp.end()) { + while (l != directChatToUser.end()) { + roomsToUpdate.insert(l->first); + ++l; + } + } else if (l->first == r->first) { + if (l->second != r->second) + roomsToUpdate.insert(l->first); + + ++l; + ++r; + } else if (l->first < r->first) { + roomsToUpdate.insert(l->first); + ++l; + } else if (l->first > r->first) { + roomsToUpdate.insert(r->first); + ++r; + } else { + throw std::logic_error("Infinite loop when updating DMs!"); + } + } + + this->directChatToUser = directChatToUserTemp; + + return roomsToUpdate; +} + void -RoomlistModel::sync(const mtx::responses::Rooms &rooms) +RoomlistModel::sync(const mtx::responses::Sync &sync_) { - for (const auto &[room_id, room] : rooms.join) { + for (const auto &e : sync_.account_data.events) { + if (auto event = + std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(&e)) { + auto updatedDMs = updateDMs(*event); + for (const auto &r : updatedDMs) { + if (auto idx = roomidToIndex(r); idx != -1) + emit dataChanged(index(idx), index(idx), {IsDirect, DirectChatOtherUserId}); + } + } + } + + for (const auto &[room_id, room] : sync_.rooms.join) { auto qroomid = QString::fromStdString(room_id); // addRoom will only add the room, if it doesn't exist @@ -477,7 +526,7 @@ RoomlistModel::sync(const mtx::responses::Rooms &rooms) } } - for (const auto &[room_id, room] : rooms.leave) { + for (const auto &[room_id, room] : sync_.rooms.leave) { (void)room; auto qroomid = QString::fromStdString(room_id); @@ -497,7 +546,7 @@ RoomlistModel::sync(const mtx::responses::Rooms &rooms) } } - for (const auto &[room_id, room] : rooms.invite) { + for (const auto &[room_id, room] : sync_.rooms.invite) { (void)room; auto qroomid = QString::fromStdString(room_id); @@ -527,9 +576,19 @@ RoomlistModel::initializeRooms() invites.clear(); currentRoom_ = nullptr; + auto e = cache::client()->getAccountData(mtx::events::EventType::Direct); + if (e) { + if (auto event = + std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>( + &e.value())) { + updateDMs(*event); + } + } + invites = cache::client()->invites(); - for (const auto &id : invites.keys()) + for (const auto &id : invites.keys()) { roomids.push_back(id); + } for (const auto &id : cache::client()->roomIds()) addRoom(id, true); @@ -568,6 +627,16 @@ RoomlistModel::acceptInvite(QString roomid) { if (invites.contains(roomid)) { // Don't remove invite yet, so that we can switch to it + auto members = cache::getMembersFromInvite(roomid.toStdString(), 0, -1); + auto local = utils::localUser(); + for (const auto &m : members) { + if (m.user_id == local && m.is_direct) { + nhlog::db()->info("marking {} as direct", roomid.toStdString()); + utils::markRoomAsDirect(roomid, members); + break; + } + } + ChatPage::instance()->joinRoom(roomid); } } @@ -756,11 +825,14 @@ FilteredRoomlistModel::updateHiddenTagsAndSpaces() { hiddenTags.clear(); hiddenSpaces.clear(); + hideDMs = false; for (const auto &t : UserSettings::instance()->hiddenTags()) { if (t.startsWith("tag:")) hiddenTags.push_back(t.mid(4)); else if (t.startsWith("space:")) hiddenSpaces.push_back(t.mid(6)); + else if (t == "dm") + hideDMs = true; } invalidateFilter(); @@ -801,7 +873,48 @@ FilteredRoomlistModel::filterAcceptsRow(int sourceRow, const QModelIndex &) cons return false; } + if (hideDMs) { + return !sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsDirect) + .toBool(); + } + return true; + } else if (filterType == FilterBy::DirectChats) { + if (sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsPreview) + .toBool()) { + return false; + } + + if (sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsSpace) + .toBool()) { + return false; + } + + if (!hiddenTags.empty()) { + auto tags = sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::Tags) + .toStringList(); + + for (const auto &t : tags) + if (hiddenTags.contains(t)) + return false; + } + + if (!hiddenSpaces.empty()) { + auto parents = sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::ParentSpaces) + .toStringList(); + for (const auto &t : parents) + if (hiddenSpaces.contains(t)) + return false; + } + + return sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsDirect) + .toBool(); } else if (filterType == FilterBy::Tag) { if (sourceModel() ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsPreview) @@ -837,6 +950,12 @@ FilteredRoomlistModel::filterAcceptsRow(int sourceRow, const QModelIndex &) cons return false; } + if (hideDMs) { + return !sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsDirect) + .toBool(); + } + return true; } else if (filterType == FilterBy::Space) { if (filterStr == sourceModel() @@ -874,6 +993,12 @@ FilteredRoomlistModel::filterAcceptsRow(int sourceRow, const QModelIndex &) cons return false; } + if (hideDMs) { + return !sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsDirect) + .toBool(); + } + return true; } else { return true; diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index 458e0fe7..5d0bcd53 100644 --- a/src/timeline/RoomlistModel.h +++ b/src/timeline/RoomlistModel.h
@@ -87,7 +87,7 @@ public: public slots: void initializeRooms(); - void sync(const mtx::responses::Rooms &rooms); + void sync(const mtx::responses::Sync &sync_); void clear(); int roomidToIndex(QString roomid) { @@ -123,6 +123,7 @@ signals: private: void addRoom(const QString &room_id, bool suppressInsertNotification = false); void fetchPreview(QString roomid) const; + std::set<QString> updateDMs(mtx::events::AccountDataEvent<mtx::events::account_data::Direct> e); TimelineViewManager *manager = nullptr; std::vector<QString> roomids; @@ -134,6 +135,8 @@ private: QSharedPointer<TimelineModel> currentRoom_; std::optional<RoomPreview> currentRoomPreview_; + std::map<QString, std::vector<QString>> directChatToUser; + friend class FilteredRoomlistModel; }; @@ -180,6 +183,9 @@ public slots: } else if (tagId.startsWith("space:")) { filterType = FilterBy::Space; filterStr = tagId.mid(6); + } else if (tagId.startsWith("dm")) { + filterType = FilterBy::DirectChats; + filterStr.clear(); } else { filterType = FilterBy::Nothing; filterStr.clear(); @@ -202,9 +208,11 @@ private: { Tag, Space, + DirectChats, Nothing, }; QString filterStr = ""; FilterBy filterType = FilterBy::Nothing; QStringList hiddenTags, hiddenSpaces; + bool hideDMs = false; }; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index c5fe6b4b..07fb0417 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp
@@ -359,10 +359,10 @@ TimelineViewManager::setVideoCallItem() } void -TimelineViewManager::sync(const mtx::responses::Rooms &rooms_res) +TimelineViewManager::sync(const mtx::responses::Sync &sync_) { - this->rooms_->sync(rooms_res); - this->communities_->sync(rooms_res); + this->rooms_->sync(sync_); + this->communities_->sync(sync_); if (isInitialSync_) { this->isInitialSync_ = false; diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 3e3952a8..a4b49829 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h
@@ -48,7 +48,7 @@ public: TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr); QWidget *getWidget() const { return container; } - void sync(const mtx::responses::Rooms &rooms); + void sync(const mtx::responses::Sync &sync_); MxcImageProvider *imageProvider() { return imgProvider; } CallManager *callManager() { return callManager_; }