diff options
Diffstat (limited to 'src/timeline/RoomlistModel.cpp')
-rw-r--r-- | src/timeline/RoomlistModel.cpp | 1595 |
1 files changed, 782 insertions, 813 deletions
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp index 2d1dd49d..2d60dcb3 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp @@ -17,978 +17,947 @@ RoomlistModel::RoomlistModel(TimelineViewManager *parent) : QAbstractListModel(parent) , manager(parent) { - [[maybe_unused]] static auto id = qRegisterMetaType<RoomPreview>(); - - connect(ChatPage::instance(), &ChatPage::decryptSidebarChanged, this, [this]() { - auto decrypt = ChatPage::instance()->userSettings()->decryptSidebar(); - QHash<QString, QSharedPointer<TimelineModel>>::iterator i; - for (i = models.begin(); i != models.end(); ++i) { - auto ptr = i.value(); - - if (!ptr.isNull()) { - ptr->setDecryptDescription(decrypt); - ptr->updateLastMessage(); - } - } - }); - - connect(this, - &RoomlistModel::totalUnreadMessageCountUpdated, - ChatPage::instance(), - &ChatPage::unreadMessages); - - connect( - this, - &RoomlistModel::fetchedPreview, - this, - [this](QString roomid, RoomInfo info) { - if (this->previewedRooms.contains(roomid)) { - this->previewedRooms.insert(roomid, std::move(info)); - auto idx = this->roomidToIndex(roomid); - emit dataChanged(index(idx), - index(idx), - { - Roles::RoomName, - Roles::AvatarUrl, - Roles::IsSpace, - Roles::IsPreviewFetched, - Qt::DisplayRole, - }); - } - }, - Qt::QueuedConnection); + [[maybe_unused]] static auto id = qRegisterMetaType<RoomPreview>(); + + connect(ChatPage::instance(), &ChatPage::decryptSidebarChanged, this, [this]() { + auto decrypt = ChatPage::instance()->userSettings()->decryptSidebar(); + QHash<QString, QSharedPointer<TimelineModel>>::iterator i; + for (i = models.begin(); i != models.end(); ++i) { + auto ptr = i.value(); + + if (!ptr.isNull()) { + ptr->setDecryptDescription(decrypt); + ptr->updateLastMessage(); + } + } + }); + + connect(this, + &RoomlistModel::totalUnreadMessageCountUpdated, + ChatPage::instance(), + &ChatPage::unreadMessages); + + connect( + this, + &RoomlistModel::fetchedPreview, + this, + [this](QString roomid, RoomInfo info) { + if (this->previewedRooms.contains(roomid)) { + this->previewedRooms.insert(roomid, std::move(info)); + auto idx = this->roomidToIndex(roomid); + emit dataChanged(index(idx), + index(idx), + { + Roles::RoomName, + Roles::AvatarUrl, + Roles::IsSpace, + Roles::IsPreviewFetched, + Qt::DisplayRole, + }); + } + }, + Qt::QueuedConnection); } QHash<int, QByteArray> RoomlistModel::roleNames() const { - return { - {AvatarUrl, "avatarUrl"}, - {RoomName, "roomName"}, - {RoomId, "roomId"}, - {LastMessage, "lastMessage"}, - {Time, "time"}, - {Timestamp, "timestamp"}, - {HasUnreadMessages, "hasUnreadMessages"}, - {HasLoudNotification, "hasLoudNotification"}, - {NotificationCount, "notificationCount"}, - {IsInvite, "isInvite"}, - {IsSpace, "isSpace"}, - {Tags, "tags"}, - {ParentSpaces, "parentSpaces"}, - {IsDirect, "isDirect"}, - {DirectChatOtherUserId, "directChatOtherUserId"}, - }; + return { + {AvatarUrl, "avatarUrl"}, + {RoomName, "roomName"}, + {RoomId, "roomId"}, + {LastMessage, "lastMessage"}, + {Time, "time"}, + {Timestamp, "timestamp"}, + {HasUnreadMessages, "hasUnreadMessages"}, + {HasLoudNotification, "hasLoudNotification"}, + {NotificationCount, "notificationCount"}, + {IsInvite, "isInvite"}, + {IsSpace, "isSpace"}, + {Tags, "tags"}, + {ParentSpaces, "parentSpaces"}, + {IsDirect, "isDirect"}, + {DirectChatOtherUserId, "directChatOtherUserId"}, + }; } QVariant RoomlistModel::data(const QModelIndex &index, int role) const { - if (index.row() >= 0 && static_cast<size_t>(index.row()) < roomids.size()) { - auto roomid = roomids.at(index.row()); - - if (role == Roles::ParentSpaces) { - auto parents = cache::client()->getParentRoomIds(roomid.toStdString()); - QStringList list; - for (const auto &t : parents) - list.push_back(QString::fromStdString(t)); - return list; - } else if (role == Roles::RoomId) { - return roomid; - } + if (index.row() >= 0 && static_cast<size_t>(index.row()) < roomids.size()) { + auto roomid = roomids.at(index.row()); + + if (role == Roles::ParentSpaces) { + auto parents = cache::client()->getParentRoomIds(roomid.toStdString()); + QStringList list; + for (const auto &t : parents) + list.push_back(QString::fromStdString(t)); + return list; + } else if (role == Roles::RoomId) { + return roomid; + } - if (models.contains(roomid)) { - auto room = models.value(roomid); - switch (role) { - case Roles::AvatarUrl: - return room->roomAvatarUrl(); - case Roles::RoomName: - return room->plainRoomName(); - case Roles::LastMessage: - return room->lastMessage().body; - case Roles::Time: - return room->lastMessage().descriptiveTime; - case Roles::Timestamp: - return QVariant( - static_cast<quint64>(room->lastMessage().timestamp)); - case Roles::HasUnreadMessages: - return this->roomReadStatus.count(roomid) && - this->roomReadStatus.at(roomid); - case Roles::HasLoudNotification: - return room->hasMentions(); - case Roles::NotificationCount: - return room->notificationCount(); - case Roles::IsInvite: - return false; - case Roles::IsSpace: - return room->isSpace(); - case Roles::IsPreview: - return false; - case Roles::Tags: { - auto info = cache::singleRoomInfo(roomid.toStdString()); - QStringList list; - for (const auto &t : info.tags) - list.push_back(QString::fromStdString(t)); - return list; - } - case Roles::IsDirect: - return room->isDirect(); - case Roles::DirectChatOtherUserId: - return room->directChatOtherUserId(); - default: - return {}; - } - } else if (invites.contains(roomid)) { - auto room = invites.value(roomid); - switch (role) { - case Roles::AvatarUrl: - return QString::fromStdString(room.avatar_url); - case Roles::RoomName: - return QString::fromStdString(room.name); - case Roles::LastMessage: - return tr("Pending invite."); - case Roles::Time: - return QString(); - case Roles::Timestamp: - return QVariant(static_cast<quint64>(0)); - case Roles::HasUnreadMessages: - case Roles::HasLoudNotification: - return false; - case Roles::NotificationCount: - return 0; - case Roles::IsInvite: - return true; - case Roles::IsSpace: - return false; - case Roles::IsPreview: - 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 {}; - } - } else if (previewedRooms.contains(roomid) && - previewedRooms.value(roomid).has_value()) { - auto room = previewedRooms.value(roomid).value(); - switch (role) { - case Roles::AvatarUrl: - return QString::fromStdString(room.avatar_url); - case Roles::RoomName: - return QString::fromStdString(room.name); - case Roles::LastMessage: - return tr("Previewing this room"); - case Roles::Time: - return QString(); - case Roles::Timestamp: - return QVariant(static_cast<quint64>(0)); - case Roles::HasUnreadMessages: - case Roles::HasLoudNotification: - return false; - case Roles::NotificationCount: - return 0; - case Roles::IsInvite: - return false; - case Roles::IsSpace: - return room.is_space; - case Roles::IsPreview: - return true; - case Roles::IsPreviewFetched: - return true; - case Roles::Tags: - return QStringList(); - case Roles::IsDirect: - return false; - case Roles::DirectChatOtherUserId: - return QString{}; // should never be reached - default: - return {}; - } - } else { - if (role == Roles::IsPreview) - return true; - else if (role == Roles::IsPreviewFetched) - return false; - - fetchPreview(roomid); - switch (role) { - case Roles::AvatarUrl: - return QString(); - case Roles::RoomName: - return tr("No preview available"); - case Roles::LastMessage: - return QString(); - case Roles::Time: - return QString(); - case Roles::Timestamp: - return QVariant(static_cast<quint64>(0)); - case Roles::HasUnreadMessages: - case Roles::HasLoudNotification: - return false; - case Roles::NotificationCount: - return 0; - case Roles::IsInvite: - return false; - case Roles::IsSpace: - return false; - case Roles::Tags: - return QStringList(); - default: - return {}; - } - } + if (models.contains(roomid)) { + auto room = models.value(roomid); + switch (role) { + case Roles::AvatarUrl: + return room->roomAvatarUrl(); + case Roles::RoomName: + return room->plainRoomName(); + case Roles::LastMessage: + return room->lastMessage().body; + case Roles::Time: + return room->lastMessage().descriptiveTime; + case Roles::Timestamp: + return QVariant(static_cast<quint64>(room->lastMessage().timestamp)); + case Roles::HasUnreadMessages: + return this->roomReadStatus.count(roomid) && this->roomReadStatus.at(roomid); + case Roles::HasLoudNotification: + return room->hasMentions(); + case Roles::NotificationCount: + return room->notificationCount(); + case Roles::IsInvite: + return false; + case Roles::IsSpace: + return room->isSpace(); + case Roles::IsPreview: + return false; + case Roles::Tags: { + auto info = cache::singleRoomInfo(roomid.toStdString()); + QStringList list; + for (const auto &t : info.tags) + list.push_back(QString::fromStdString(t)); + return list; + } + case Roles::IsDirect: + return room->isDirect(); + case Roles::DirectChatOtherUserId: + return room->directChatOtherUserId(); + default: + return {}; + } + } else if (invites.contains(roomid)) { + auto room = invites.value(roomid); + switch (role) { + case Roles::AvatarUrl: + return QString::fromStdString(room.avatar_url); + case Roles::RoomName: + return QString::fromStdString(room.name); + case Roles::LastMessage: + return tr("Pending invite."); + case Roles::Time: + return QString(); + case Roles::Timestamp: + return QVariant(static_cast<quint64>(0)); + case Roles::HasUnreadMessages: + case Roles::HasLoudNotification: + return false; + case Roles::NotificationCount: + return 0; + case Roles::IsInvite: + return true; + case Roles::IsSpace: + return false; + case Roles::IsPreview: + 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 {}; + } + } else if (previewedRooms.contains(roomid) && previewedRooms.value(roomid).has_value()) { + auto room = previewedRooms.value(roomid).value(); + switch (role) { + case Roles::AvatarUrl: + return QString::fromStdString(room.avatar_url); + case Roles::RoomName: + return QString::fromStdString(room.name); + case Roles::LastMessage: + return tr("Previewing this room"); + case Roles::Time: + return QString(); + case Roles::Timestamp: + return QVariant(static_cast<quint64>(0)); + case Roles::HasUnreadMessages: + case Roles::HasLoudNotification: + return false; + case Roles::NotificationCount: + return 0; + case Roles::IsInvite: + return false; + case Roles::IsSpace: + return room.is_space; + case Roles::IsPreview: + return true; + case Roles::IsPreviewFetched: + return true; + case Roles::Tags: + return QStringList(); + case Roles::IsDirect: + return false; + case Roles::DirectChatOtherUserId: + return QString{}; // should never be reached + default: + return {}; + } } else { + if (role == Roles::IsPreview) + return true; + else if (role == Roles::IsPreviewFetched) + return false; + + fetchPreview(roomid); + switch (role) { + case Roles::AvatarUrl: + return QString(); + case Roles::RoomName: + return tr("No preview available"); + case Roles::LastMessage: + return QString(); + case Roles::Time: + return QString(); + case Roles::Timestamp: + return QVariant(static_cast<quint64>(0)); + case Roles::HasUnreadMessages: + case Roles::HasLoudNotification: + return false; + case Roles::NotificationCount: + return 0; + case Roles::IsInvite: + return false; + case Roles::IsSpace: + return false; + case Roles::Tags: + return QStringList(); + default: return {}; + } } + } else { + return {}; + } } void RoomlistModel::updateReadStatus(const std::map<QString, bool> roomReadStatus_) { - std::vector<int> roomsToUpdate; - roomsToUpdate.resize(roomReadStatus_.size()); - for (const auto &[roomid, roomUnread] : roomReadStatus_) { - if (roomUnread != roomReadStatus[roomid]) { - roomsToUpdate.push_back(this->roomidToIndex(roomid)); - } - - this->roomReadStatus[roomid] = roomUnread; + std::vector<int> roomsToUpdate; + roomsToUpdate.resize(roomReadStatus_.size()); + for (const auto &[roomid, roomUnread] : roomReadStatus_) { + if (roomUnread != roomReadStatus[roomid]) { + roomsToUpdate.push_back(this->roomidToIndex(roomid)); } - for (auto idx : roomsToUpdate) { - emit dataChanged(index(idx), - index(idx), - { - Roles::HasUnreadMessages, - }); - } + this->roomReadStatus[roomid] = roomUnread; + } + + for (auto idx : roomsToUpdate) { + emit dataChanged(index(idx), + index(idx), + { + Roles::HasUnreadMessages, + }); + } } void RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification) { - if (!models.contains(room_id)) { - // ensure we get read status updates and are only connected once - connect(cache::client(), - &Cache::roomReadStatus, - this, - &RoomlistModel::updateReadStatus, - Qt::UniqueConnection); - - QSharedPointer<TimelineModel> newRoom(new TimelineModel(manager, room_id)); - newRoom->setDecryptDescription( - ChatPage::instance()->userSettings()->decryptSidebar()); - - connect(newRoom.data(), - &TimelineModel::newEncryptedImage, - manager->imageProvider(), - &MxcImageProvider::addEncryptionInfo); - connect(newRoom.data(), - &TimelineModel::forwardToRoom, - manager, - &TimelineViewManager::forwardMessageToRoom); - connect( - newRoom.data(), &TimelineModel::lastMessageChanged, this, [room_id, this]() { - auto idx = this->roomidToIndex(room_id); - emit dataChanged(index(idx), - index(idx), - { - Roles::HasLoudNotification, - Roles::LastMessage, - Roles::Timestamp, - Roles::NotificationCount, - Qt::DisplayRole, - }); - }); - connect( - newRoom.data(), &TimelineModel::roomAvatarUrlChanged, this, [room_id, this]() { - auto idx = this->roomidToIndex(room_id); - emit dataChanged(index(idx), - index(idx), - { - Roles::AvatarUrl, - }); - }); - connect(newRoom.data(), &TimelineModel::roomNameChanged, this, [room_id, this]() { - auto idx = this->roomidToIndex(room_id); - emit dataChanged(index(idx), - index(idx), - { - Roles::RoomName, - }); - }); - connect( - newRoom.data(), &TimelineModel::notificationsChanged, this, [room_id, this]() { - auto idx = this->roomidToIndex(room_id); - emit dataChanged(index(idx), - index(idx), - { - Roles::HasLoudNotification, - Roles::NotificationCount, - Qt::DisplayRole, - }); - - int total_unread_msgs = 0; - - for (const auto &room : models) { - if (!room.isNull()) - total_unread_msgs += room->notificationCount(); - } - - emit totalUnreadMessageCountUpdated(total_unread_msgs); - }); - - newRoom->updateLastMessage(); - - std::vector<QString> previewsToAdd; - if (newRoom->isSpace()) { - auto childs = cache::client()->getChildRoomIds(room_id.toStdString()); - for (const auto &c : childs) { - auto id = QString::fromStdString(c); - if (!(models.contains(id) || invites.contains(id) || - previewedRooms.contains(id))) { - previewsToAdd.push_back(std::move(id)); - } - } - } + if (!models.contains(room_id)) { + // ensure we get read status updates and are only connected once + connect(cache::client(), + &Cache::roomReadStatus, + this, + &RoomlistModel::updateReadStatus, + Qt::UniqueConnection); + + QSharedPointer<TimelineModel> newRoom(new TimelineModel(manager, room_id)); + newRoom->setDecryptDescription(ChatPage::instance()->userSettings()->decryptSidebar()); + + connect(newRoom.data(), + &TimelineModel::newEncryptedImage, + manager->imageProvider(), + &MxcImageProvider::addEncryptionInfo); + connect(newRoom.data(), + &TimelineModel::forwardToRoom, + manager, + &TimelineViewManager::forwardMessageToRoom); + connect(newRoom.data(), &TimelineModel::lastMessageChanged, this, [room_id, this]() { + auto idx = this->roomidToIndex(room_id); + emit dataChanged(index(idx), + index(idx), + { + Roles::HasLoudNotification, + Roles::LastMessage, + Roles::Timestamp, + Roles::NotificationCount, + Qt::DisplayRole, + }); + }); + connect(newRoom.data(), &TimelineModel::roomAvatarUrlChanged, this, [room_id, this]() { + auto idx = this->roomidToIndex(room_id); + emit dataChanged(index(idx), + index(idx), + { + Roles::AvatarUrl, + }); + }); + connect(newRoom.data(), &TimelineModel::roomNameChanged, this, [room_id, this]() { + auto idx = this->roomidToIndex(room_id); + emit dataChanged(index(idx), + index(idx), + { + Roles::RoomName, + }); + }); + connect(newRoom.data(), &TimelineModel::notificationsChanged, this, [room_id, this]() { + auto idx = this->roomidToIndex(room_id); + emit dataChanged(index(idx), + index(idx), + { + Roles::HasLoudNotification, + Roles::NotificationCount, + Qt::DisplayRole, + }); + + int total_unread_msgs = 0; + + for (const auto &room : models) { + if (!room.isNull()) + total_unread_msgs += room->notificationCount(); + } + + emit totalUnreadMessageCountUpdated(total_unread_msgs); + }); - bool wasInvite = invites.contains(room_id); - bool wasPreview = previewedRooms.contains(room_id); - if (!suppressInsertNotification && - ((!wasInvite && !wasPreview) || !previewedRooms.empty())) - // if the old room was already in the list, don't add it. Also add all - // previews at the same time. - beginInsertRows(QModelIndex(), - (int)roomids.size(), - (int)(roomids.size() + previewsToAdd.size() - - ((wasInvite || wasPreview) ? 1 : 0))); - - models.insert(room_id, std::move(newRoom)); - if (wasInvite) { - auto idx = roomidToIndex(room_id); - invites.remove(room_id); - emit dataChanged(index(idx), index(idx)); - } else if (wasPreview) { - auto idx = roomidToIndex(room_id); - previewedRooms.remove(room_id); - emit dataChanged(index(idx), index(idx)); - } else { - roomids.push_back(room_id); - } + newRoom->updateLastMessage(); - if ((wasInvite || wasPreview) && currentRoomPreview_ && - currentRoomPreview_->roomid() == room_id) { - currentRoom_ = models.value(room_id); - currentRoomPreview_.reset(); - emit currentRoomChanged(); + std::vector<QString> previewsToAdd; + if (newRoom->isSpace()) { + auto childs = cache::client()->getChildRoomIds(room_id.toStdString()); + for (const auto &c : childs) { + auto id = QString::fromStdString(c); + if (!(models.contains(id) || invites.contains(id) || previewedRooms.contains(id))) { + previewsToAdd.push_back(std::move(id)); } + } + } - for (auto p : previewsToAdd) { - previewedRooms.insert(p, std::nullopt); - roomids.push_back(std::move(p)); - } + bool wasInvite = invites.contains(room_id); + bool wasPreview = previewedRooms.contains(room_id); + if (!suppressInsertNotification && ((!wasInvite && !wasPreview) || !previewedRooms.empty())) + // if the old room was already in the list, don't add it. Also add all + // previews at the same time. + beginInsertRows( + QModelIndex(), + (int)roomids.size(), + (int)(roomids.size() + previewsToAdd.size() - ((wasInvite || wasPreview) ? 1 : 0))); + + models.insert(room_id, std::move(newRoom)); + if (wasInvite) { + auto idx = roomidToIndex(room_id); + invites.remove(room_id); + emit dataChanged(index(idx), index(idx)); + } else if (wasPreview) { + auto idx = roomidToIndex(room_id); + previewedRooms.remove(room_id); + emit dataChanged(index(idx), index(idx)); + } else { + roomids.push_back(room_id); + } - if (!suppressInsertNotification && - ((!wasInvite && !wasPreview) || !previewedRooms.empty())) - endInsertRows(); + if ((wasInvite || wasPreview) && currentRoomPreview_ && + currentRoomPreview_->roomid() == room_id) { + currentRoom_ = models.value(room_id); + currentRoomPreview_.reset(); + emit currentRoomChanged(); + } - emit ChatPage::instance()->newRoom(room_id); + for (auto p : previewsToAdd) { + previewedRooms.insert(p, std::nullopt); + roomids.push_back(std::move(p)); } + + if (!suppressInsertNotification && ((!wasInvite && !wasPreview) || !previewedRooms.empty())) + endInsertRows(); + + emit ChatPage::instance()->newRoom(room_id); + } } void RoomlistModel::fetchPreview(QString roomid_) const { - std::string roomid = roomid_.toStdString(); - http::client()->get_state_event<mtx::events::state::Create>( - roomid, - "", - [this, roomid](const mtx::events::state::Create &c, mtx::http::RequestErr err) { - bool is_space = false; - if (!err) { - is_space = c.type == mtx::events::state::room_type::space; - } - - http::client()->get_state_event<mtx::events::state::Avatar>( - roomid, - "", - [this, roomid, is_space](const mtx::events::state::Avatar &a, - mtx::http::RequestErr) { - auto avatar_url = a.url; - - http::client()->get_state_event<mtx::events::state::Topic>( - roomid, - "", - [this, roomid, avatar_url, is_space]( - const mtx::events::state::Topic &t, mtx::http::RequestErr) { - auto topic = t.topic; - http::client()->get_state_event<mtx::events::state::Name>( - roomid, - "", - [this, roomid, topic, avatar_url, is_space]( - const mtx::events::state::Name &n, - mtx::http::RequestErr err) { - if (err) { - nhlog::net()->warn( - "Failed to fetch name event to " - "create preview for {}", - roomid); - } - - // don't even add a preview, if we got not a single - // response - if (n.name.empty() && avatar_url.empty() && - topic.empty()) - return; - - RoomInfo info{}; - info.name = n.name; - info.is_space = is_space; - info.avatar_url = avatar_url; - info.topic = topic; - - const_cast<RoomlistModel *>(this)->fetchedPreview( - QString::fromStdString(roomid), info); - }); - }); - }); - }); + std::string roomid = roomid_.toStdString(); + http::client()->get_state_event<mtx::events::state::Create>( + roomid, "", [this, roomid](const mtx::events::state::Create &c, mtx::http::RequestErr err) { + bool is_space = false; + if (!err) { + is_space = c.type == mtx::events::state::room_type::space; + } + + http::client()->get_state_event<mtx::events::state::Avatar>( + roomid, + "", + [this, roomid, is_space](const mtx::events::state::Avatar &a, mtx::http::RequestErr) { + auto avatar_url = a.url; + + http::client()->get_state_event<mtx::events::state::Topic>( + roomid, + "", + [this, roomid, avatar_url, is_space](const mtx::events::state::Topic &t, + mtx::http::RequestErr) { + auto topic = t.topic; + http::client()->get_state_event<mtx::events::state::Name>( + roomid, + "", + [this, roomid, topic, avatar_url, is_space]( + const mtx::events::state::Name &n, mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("Failed to fetch name event to " + "create preview for {}", + roomid); + } + + // don't even add a preview, if we got not a single + // response + if (n.name.empty() && avatar_url.empty() && topic.empty()) + return; + + RoomInfo info{}; + info.name = n.name; + info.is_space = is_space; + info.avatar_url = avatar_url; + info.topic = topic; + + const_cast<RoomlistModel *>(this)->fetchedPreview( + QString::fromStdString(roomid), info); + }); + }); + }); + }); } void RoomlistModel::sync(const mtx::responses::Rooms &rooms) { - for (const auto &[room_id, room] : rooms.join) { - auto qroomid = QString::fromStdString(room_id); - - // addRoom will only add the room, if it doesn't exist - addRoom(qroomid); - const auto &room_model = models.value(qroomid); - room_model->sync(room); - // room_model->addEvents(room.timeline); - connect(room_model.data(), - &TimelineModel::newCallEvent, - manager->callManager(), - &CallManager::syncEvent, - Qt::UniqueConnection); - - if (ChatPage::instance()->userSettings()->typingNotifications()) { - for (const auto &ev : room.ephemeral.events) { - if (auto t = std::get_if< - mtx::events::EphemeralEvent<mtx::events::ephemeral::Typing>>( - &ev)) { - std::vector<QString> typing; - typing.reserve(t->content.user_ids.size()); - for (const auto &user : t->content.user_ids) { - if (user != http::client()->user_id().to_string()) - typing.push_back( - QString::fromStdString(user)); - } - room_model->updateTypingUsers(typing); - } - } + for (const auto &[room_id, room] : rooms.join) { + auto qroomid = QString::fromStdString(room_id); + + // addRoom will only add the room, if it doesn't exist + addRoom(qroomid); + const auto &room_model = models.value(qroomid); + room_model->sync(room); + // room_model->addEvents(room.timeline); + connect(room_model.data(), + &TimelineModel::newCallEvent, + manager->callManager(), + &CallManager::syncEvent, + Qt::UniqueConnection); + + if (ChatPage::instance()->userSettings()->typingNotifications()) { + for (const auto &ev : room.ephemeral.events) { + if (auto t = + std::get_if<mtx::events::EphemeralEvent<mtx::events::ephemeral::Typing>>( + &ev)) { + std::vector<QString> typing; + typing.reserve(t->content.user_ids.size()); + for (const auto &user : t->content.user_ids) { + if (user != http::client()->user_id().to_string()) + typing.push_back(QString::fromStdString(user)); + } + room_model->updateTypingUsers(typing); } + } } - - for (const auto &[room_id, room] : rooms.leave) { - (void)room; - auto qroomid = QString::fromStdString(room_id); - - if ((currentRoom_ && currentRoom_->roomId() == qroomid) || - (currentRoomPreview_ && currentRoomPreview_->roomid() == qroomid)) - resetCurrentRoom(); - - auto idx = this->roomidToIndex(qroomid); - if (idx != -1) { - beginRemoveRows(QModelIndex(), idx, idx); - roomids.erase(roomids.begin() + idx); - if (models.contains(qroomid)) - models.remove(qroomid); - else if (invites.contains(qroomid)) - invites.remove(qroomid); - endRemoveRows(); - } + } + + for (const auto &[room_id, room] : rooms.leave) { + (void)room; + auto qroomid = QString::fromStdString(room_id); + + if ((currentRoom_ && currentRoom_->roomId() == qroomid) || + (currentRoomPreview_ && currentRoomPreview_->roomid() == qroomid)) + resetCurrentRoom(); + + auto idx = this->roomidToIndex(qroomid); + if (idx != -1) { + beginRemoveRows(QModelIndex(), idx, idx); + roomids.erase(roomids.begin() + idx); + if (models.contains(qroomid)) + models.remove(qroomid); + else if (invites.contains(qroomid)) + invites.remove(qroomid); + endRemoveRows(); } + } - for (const auto &[room_id, room] : rooms.invite) { - (void)room; - auto qroomid = QString::fromStdString(room_id); - - auto invite = cache::client()->invite(room_id); - if (!invite) - continue; - - if (invites.contains(qroomid)) { - invites[qroomid] = *invite; - auto idx = roomidToIndex(qroomid); - emit dataChanged(index(idx), index(idx)); - } else { - beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size()); - invites.insert(qroomid, *invite); - roomids.push_back(std::move(qroomid)); - endInsertRows(); - } + for (const auto &[room_id, room] : rooms.invite) { + (void)room; + auto qroomid = QString::fromStdString(room_id); + + auto invite = cache::client()->invite(room_id); + if (!invite) + continue; + + if (invites.contains(qroomid)) { + invites[qroomid] = *invite; + auto idx = roomidToIndex(qroomid); + emit dataChanged(index(idx), index(idx)); + } else { + beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size()); + invites.insert(qroomid, *invite); + roomids.push_back(std::move(qroomid)); + endInsertRows(); } + } } void RoomlistModel::initializeRooms() { - beginResetModel(); - models.clear(); - roomids.clear(); - invites.clear(); - currentRoom_ = nullptr; + beginResetModel(); + models.clear(); + roomids.clear(); + invites.clear(); + currentRoom_ = nullptr; - invites = cache::client()->invites(); - for (const auto &id : invites.keys()) - roomids.push_back(id); + invites = cache::client()->invites(); + for (const auto &id : invites.keys()) + roomids.push_back(id); - for (const auto &id : cache::client()->roomIds()) - addRoom(id, true); + for (const auto &id : cache::client()->roomIds()) + addRoom(id, true); - nhlog::db()->info("Restored {} rooms from cache", rowCount()); + nhlog::db()->info("Restored {} rooms from cache", rowCount()); - endResetModel(); + endResetModel(); } void RoomlistModel::clear() { - beginResetModel(); - models.clear(); - invites.clear(); - roomids.clear(); - currentRoom_ = nullptr; - emit currentRoomChanged(); - endResetModel(); + beginResetModel(); + models.clear(); + invites.clear(); + roomids.clear(); + currentRoom_ = nullptr; + emit currentRoomChanged(); + endResetModel(); } void RoomlistModel::joinPreview(QString roomid, QString parentSpace) { - if (previewedRooms.contains(roomid)) { - auto child = cache::client()->getStateEvent<mtx::events::state::space::Child>( - parentSpace.toStdString(), roomid.toStdString()); - ChatPage::instance()->joinRoomVia(roomid.toStdString(), - (child && child->content.via) - ? child->content.via.value() - : std::vector<std::string>{}, - false); - } + if (previewedRooms.contains(roomid)) { + auto child = cache::client()->getStateEvent<mtx::events::state::space::Child>( + parentSpace.toStdString(), roomid.toStdString()); + ChatPage::instance()->joinRoomVia( + roomid.toStdString(), + (child && child->content.via) ? child->content.via.value() : std::vector<std::string>{}, + false); + } } void RoomlistModel::acceptInvite(QString roomid) { - if (invites.contains(roomid)) { - // Don't remove invite yet, so that we can switch to it - ChatPage::instance()->joinRoom(roomid); - } + if (invites.contains(roomid)) { + // Don't remove invite yet, so that we can switch to it + ChatPage::instance()->joinRoom(roomid); + } } void RoomlistModel::declineInvite(QString roomid) { - if (invites.contains(roomid)) { - auto idx = roomidToIndex(roomid); - - if (idx != -1) { - beginRemoveRows(QModelIndex(), idx, idx); - roomids.erase(roomids.begin() + idx); - invites.remove(roomid); - endRemoveRows(); - ChatPage::instance()->leaveRoom(roomid); - } + if (invites.contains(roomid)) { + auto idx = roomidToIndex(roomid); + + if (idx != -1) { + beginRemoveRows(QModelIndex(), idx, idx); + roomids.erase(roomids.begin() + idx); + invites.remove(roomid); + endRemoveRows(); + ChatPage::instance()->leaveRoom(roomid); } + } } void RoomlistModel::leave(QString roomid) { - if (models.contains(roomid)) { - auto idx = roomidToIndex(roomid); - - if (idx != -1) { - beginRemoveRows(QModelIndex(), idx, idx); - roomids.erase(roomids.begin() + idx); - models.remove(roomid); - endRemoveRows(); - ChatPage::instance()->leaveRoom(roomid); - } + if (models.contains(roomid)) { + auto idx = roomidToIndex(roomid); + + if (idx != -1) { + beginRemoveRows(QModelIndex(), idx, idx); + roomids.erase(roomids.begin() + idx); + models.remove(roomid); + endRemoveRows(); + ChatPage::instance()->leaveRoom(roomid); } + } } void RoomlistModel::setCurrentRoom(QString roomid) { - if ((currentRoom_ && currentRoom_->roomId() == roomid) || - (currentRoomPreview_ && currentRoomPreview_->roomid() == roomid)) - return; + if ((currentRoom_ && currentRoom_->roomId() == roomid) || + (currentRoomPreview_ && currentRoomPreview_->roomid() == roomid)) + return; + + nhlog::ui()->debug("Trying to switch to: {}", roomid.toStdString()); + if (models.contains(roomid)) { + currentRoom_ = models.value(roomid); + currentRoomPreview_.reset(); + emit currentRoomChanged(); + nhlog::ui()->debug("Switched to: {}", roomid.toStdString()); + } else if (invites.contains(roomid) || previewedRooms.contains(roomid)) { + currentRoom_ = nullptr; + std::optional<RoomInfo> i; - nhlog::ui()->debug("Trying to switch to: {}", roomid.toStdString()); - if (models.contains(roomid)) { - currentRoom_ = models.value(roomid); - currentRoomPreview_.reset(); - emit currentRoomChanged(); - nhlog::ui()->debug("Switched to: {}", roomid.toStdString()); - } else if (invites.contains(roomid) || previewedRooms.contains(roomid)) { - currentRoom_ = nullptr; - std::optional<RoomInfo> i; - - RoomPreview p; - - if (invites.contains(roomid)) { - i = invites.value(roomid); - p.isInvite_ = true; - } else { - i = previewedRooms.value(roomid); - p.isInvite_ = false; - } + RoomPreview p; - if (i) { - p.roomid_ = roomid; - p.roomName_ = QString::fromStdString(i->name); - p.roomTopic_ = QString::fromStdString(i->topic); - p.roomAvatarUrl_ = QString::fromStdString(i->avatar_url); - currentRoomPreview_ = std::move(p); - } + if (invites.contains(roomid)) { + i = invites.value(roomid); + p.isInvite_ = true; + } else { + i = previewedRooms.value(roomid); + p.isInvite_ = false; + } - emit currentRoomChanged(); - nhlog::ui()->debug("Switched to: {}", roomid.toStdString()); + if (i) { + p.roomid_ = roomid; + p.roomName_ = QString::fromStdString(i->name); + p.roomTopic_ = QString::fromStdString(i->topic); + p.roomAvatarUrl_ = QString::fromStdString(i->avatar_url); + currentRoomPreview_ = std::move(p); } + + emit currentRoomChanged(); + nhlog::ui()->debug("Switched to: {}", roomid.toStdString()); + } } namespace { enum NotificationImportance : short { - ImportanceDisabled = -3, - NoPreview = -2, - Preview = -1, - AllEventsRead = 0, - NewMessage = 1, - NewMentions = 2, - Invite = 3, - SubSpace = 4, - CurrentSpace = 5, + ImportanceDisabled = -3, + NoPreview = -2, + Preview = -1, + AllEventsRead = 0, + NewMessage = 1, + NewMentions = 2, + Invite = 3, + SubSpace = 4, + CurrentSpace = 5, }; } short int FilteredRoomlistModel::calculateImportance(const QModelIndex &idx) const { - // Returns the degree of importance of the unread messages in the room. - // If sorting by importance is disabled in settings, this only ever - // returns ImportanceDisabled or Invite - if (sourceModel()->data(idx, RoomlistModel::IsSpace).toBool()) { - if (filterType == FilterBy::Space && - filterStr == sourceModel()->data(idx, RoomlistModel::RoomId).toString()) - return CurrentSpace; - else - return SubSpace; - } else if (sourceModel()->data(idx, RoomlistModel::IsPreview).toBool()) { - if (sourceModel()->data(idx, RoomlistModel::IsPreviewFetched).toBool()) - return Preview; - else - return NoPreview; - } else if (sourceModel()->data(idx, RoomlistModel::IsInvite).toBool()) { - return Invite; - } else if (!this->sortByImportance) { - return ImportanceDisabled; - } else if (sourceModel()->data(idx, RoomlistModel::HasLoudNotification).toBool()) { - return NewMentions; - } else if (sourceModel()->data(idx, RoomlistModel::NotificationCount).toInt() > 0) { - return NewMessage; - } else { - return AllEventsRead; - } + // Returns the degree of importance of the unread messages in the room. + // If sorting by importance is disabled in settings, this only ever + // returns ImportanceDisabled or Invite + if (sourceModel()->data(idx, RoomlistModel::IsSpace).toBool()) { + if (filterType == FilterBy::Space && + filterStr == sourceModel()->data(idx, RoomlistModel::RoomId).toString()) + return CurrentSpace; + else + return SubSpace; + } else if (sourceModel()->data(idx, RoomlistModel::IsPreview).toBool()) { + if (sourceModel()->data(idx, RoomlistModel::IsPreviewFetched).toBool()) + return Preview; + else + return NoPreview; + } else if (sourceModel()->data(idx, RoomlistModel::IsInvite).toBool()) { + return Invite; + } else if (!this->sortByImportance) { + return ImportanceDisabled; + } else if (sourceModel()->data(idx, RoomlistModel::HasLoudNotification).toBool()) { + return NewMentions; + } else if (sourceModel()->data(idx, RoomlistModel::NotificationCount).toInt() > 0) { + return NewMessage; + } else { + return AllEventsRead; + } } bool FilteredRoomlistModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { - QModelIndex const left_idx = sourceModel()->index(left.row(), 0, QModelIndex()); - QModelIndex const right_idx = sourceModel()->index(right.row(), 0, QModelIndex()); - - // Sort by "importance" (i.e. invites before mentions before - // notifs before new events before old events), then secondly - // by recency. - - // Checking importance first - const auto a_importance = calculateImportance(left_idx); - const auto b_importance = calculateImportance(right_idx); - if (a_importance != b_importance) { - return a_importance > b_importance; - } - - // Now sort by recency - // Zero if empty, otherwise the time that the event occured - uint64_t a_recency = sourceModel()->data(left_idx, RoomlistModel::Timestamp).toULongLong(); - uint64_t b_recency = sourceModel()->data(right_idx, RoomlistModel::Timestamp).toULongLong(); - - if (a_recency != b_recency) - return a_recency > b_recency; - else - return left.row() < right.row(); + QModelIndex const left_idx = sourceModel()->index(left.row(), 0, QModelIndex()); + QModelIndex const right_idx = sourceModel()->index(right.row(), 0, QModelIndex()); + + // Sort by "importance" (i.e. invites before mentions before + // notifs before new events before old events), then secondly + // by recency. + + // Checking importance first + const auto a_importance = calculateImportance(left_idx); + const auto b_importance = calculateImportance(right_idx); + if (a_importance != b_importance) { + return a_importance > b_importance; + } + + // Now sort by recency + // Zero if empty, otherwise the time that the event occured + uint64_t a_recency = sourceModel()->data(left_idx, RoomlistModel::Timestamp).toULongLong(); + uint64_t b_recency = sourceModel()->data(right_idx, RoomlistModel::Timestamp).toULongLong(); + + if (a_recency != b_recency) + return a_recency > b_recency; + else + return left.row() < right.row(); } FilteredRoomlistModel::FilteredRoomlistModel(RoomlistModel *model, QObject *parent) : QSortFilterProxyModel(parent) , roomlistmodel(model) { - this->sortByImportance = UserSettings::instance()->sortByImportance(); - setSourceModel(model); - setDynamicSortFilter(true); - - QObject::connect(UserSettings::instance().get(), - &UserSettings::roomSortingChanged, - this, - [this](bool sortByImportance_) { - this->sortByImportance = sortByImportance_; - invalidate(); - }); - - connect(roomlistmodel, - &RoomlistModel::currentRoomChanged, - this, - &FilteredRoomlistModel::currentRoomChanged); - - sort(0); + this->sortByImportance = UserSettings::instance()->sortByImportance(); + setSourceModel(model); + setDynamicSortFilter(true); + + QObject::connect(UserSettings::instance().get(), + &UserSettings::roomSortingChanged, + this, + [this](bool sortByImportance_) { + this->sortByImportance = sortByImportance_; + invalidate(); + }); + + connect(roomlistmodel, + &RoomlistModel::currentRoomChanged, + this, + &FilteredRoomlistModel::currentRoomChanged); + + sort(0); } void FilteredRoomlistModel::updateHiddenTagsAndSpaces() { - hiddenTags.clear(); - hiddenSpaces.clear(); - 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)); - } - - invalidateFilter(); + hiddenTags.clear(); + hiddenSpaces.clear(); + 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)); + } + + invalidateFilter(); } bool FilteredRoomlistModel::filterAcceptsRow(int sourceRow, const QModelIndex &) const { - if (filterType == FilterBy::Nothing) { - if (sourceModel() - ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsPreview) - .toBool()) { - return false; - } + if (filterType == FilterBy::Nothing) { + 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 (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(); + 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; - } + 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; - } + 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 true; - } else if (filterType == FilterBy::Tag) { - if (sourceModel() - ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsPreview) - .toBool()) { - return false; - } + return true; + } else if (filterType == FilterBy::Tag) { + 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 (sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsSpace) + .toBool()) { + return false; + } - auto tags = sourceModel() - ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::Tags) - .toStringList(); + auto tags = sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::Tags) + .toStringList(); - if (!tags.contains(filterStr)) - return false; + if (!tags.contains(filterStr)) + return false; - if (!hiddenTags.empty()) { - for (const auto &t : tags) - if (t != filterStr && hiddenTags.contains(t)) - return false; - } + if (!hiddenTags.empty()) { + for (const auto &t : tags) + if (t != filterStr && 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; - } + 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 true; - } else if (filterType == FilterBy::Space) { - if (filterStr == sourceModel() - ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::RoomId) - .toString()) - return true; - - auto parents = - sourceModel() - ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::ParentSpaces) - .toStringList(); - - if (!parents.contains(filterStr)) - 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; - } + return true; + } else if (filterType == FilterBy::Space) { + if (filterStr == sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::RoomId) + .toString()) + return true; - if (!hiddenSpaces.empty()) { - for (const auto &t : parents) - if (hiddenSpaces.contains(t)) - return false; - } + auto parents = sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::ParentSpaces) + .toStringList(); - if (sourceModel() - ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsSpace) - .toBool() && - !parents.contains(filterStr)) { - return false; - } + if (!parents.contains(filterStr)) + return false; - return true; - } else { - return true; + 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()) { + for (const auto &t : parents) + if (hiddenSpaces.contains(t)) + return false; + } + + if (sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::IsSpace) + .toBool() && + !parents.contains(filterStr)) { + return false; } + + return true; + } else { + return true; + } } void FilteredRoomlistModel::toggleTag(QString roomid, QString tag, bool on) { - if (on) { - http::client()->put_tag( - roomid.toStdString(), tag.toStdString(), {}, [tag](mtx::http::RequestErr err) { - if (err) { - nhlog::ui()->error("Failed to add tag: {}, {}", - tag.toStdString(), - err->matrix_error.error); - } - }); - } else { - http::client()->delete_tag( - roomid.toStdString(), tag.toStdString(), [tag](mtx::http::RequestErr err) { - if (err) { - nhlog::ui()->error("Failed to delete tag: {}, {}", - tag.toStdString(), - err->matrix_error.error); - } - }); - } + if (on) { + http::client()->put_tag( + roomid.toStdString(), tag.toStdString(), {}, [tag](mtx::http::RequestErr err) { + if (err) { + nhlog::ui()->error( + "Failed to add tag: {}, {}", tag.toStdString(), err->matrix_error.error); + } + }); + } else { + http::client()->delete_tag( + roomid.toStdString(), tag.toStdString(), [tag](mtx::http::RequestErr err) { + if (err) { + nhlog::ui()->error( + "Failed to delete tag: {}, {}", tag.toStdString(), err->matrix_error.error); + } + }); + } } void FilteredRoomlistModel::nextRoomWithActivity() { - int roomWithMention = -1; - int roomWithNotification = -1; - int roomWithUnreadMessage = -1; - auto r = currentRoom(); - int currentRoomIdx = r ? roomidToIndex(r->roomId()) : -1; - // first look for mentions - for (int i = 0; i < (int)roomlistmodel->roomids.size(); i++) { - if (i == currentRoomIdx) - continue; - if (this->data(index(i, 0), RoomlistModel::HasLoudNotification).toBool()) { - roomWithMention = i; - break; - } - if (roomWithNotification == -1 && - this->data(index(i, 0), RoomlistModel::NotificationCount).toInt() > 0) { - roomWithNotification = i; - // don't break, we must continue looking for rooms with mentions - } - if (roomWithNotification == -1 && roomWithUnreadMessage == -1 && - this->data(index(i, 0), RoomlistModel::HasUnreadMessages).toBool()) { - roomWithUnreadMessage = i; - // don't break, we must continue looking for rooms with mentions - } + int roomWithMention = -1; + int roomWithNotification = -1; + int roomWithUnreadMessage = -1; + auto r = currentRoom(); + int currentRoomIdx = r ? roomidToIndex(r->roomId()) : -1; + // first look for mentions + for (int i = 0; i < (int)roomlistmodel->roomids.size(); i++) { + if (i == currentRoomIdx) + continue; + if (this->data(index(i, 0), RoomlistModel::HasLoudNotification).toBool()) { + roomWithMention = i; + break; } - QString targetRoomId = nullptr; - if (roomWithMention != -1) { - targetRoomId = - this->data(index(roomWithMention, 0), RoomlistModel::RoomId).toString(); - nhlog::ui()->debug("choosing {} for mentions", targetRoomId.toStdString()); - } else if (roomWithNotification != -1) { - targetRoomId = - this->data(index(roomWithNotification, 0), RoomlistModel::RoomId).toString(); - nhlog::ui()->debug("choosing {} for notifications", targetRoomId.toStdString()); - } else if (roomWithUnreadMessage != -1) { - targetRoomId = - this->data(index(roomWithUnreadMessage, 0), RoomlistModel::RoomId).toString(); - nhlog::ui()->debug("choosing {} for unread messages", targetRoomId.toStdString()); + if (roomWithNotification == -1 && + this->data(index(i, 0), RoomlistModel::NotificationCount).toInt() > 0) { + roomWithNotification = i; + // don't break, we must continue looking for rooms with mentions } - if (targetRoomId != nullptr) { - setCurrentRoom(targetRoomId); + if (roomWithNotification == -1 && roomWithUnreadMessage == -1 && + this->data(index(i, 0), RoomlistModel::HasUnreadMessages).toBool()) { + roomWithUnreadMessage = i; + // don't break, we must continue looking for rooms with mentions } + } + QString targetRoomId = nullptr; + if (roomWithMention != -1) { + targetRoomId = this->data(index(roomWithMention, 0), RoomlistModel::RoomId).toString(); + nhlog::ui()->debug("choosing {} for mentions", targetRoomId.toStdString()); + } else if (roomWithNotification != -1) { + targetRoomId = this->data(index(roomWithNotification, 0), RoomlistModel::RoomId).toString(); + nhlog::ui()->debug("choosing {} for notifications", targetRoomId.toStdString()); + } else if (roomWithUnreadMessage != -1) { + targetRoomId = + this->data(index(roomWithUnreadMessage, 0), RoomlistModel::RoomId).toString(); + nhlog::ui()->debug("choosing {} for unread messages", targetRoomId.toStdString()); + } + if (targetRoomId != nullptr) { + setCurrentRoom(targetRoomId); + } } void FilteredRoomlistModel::nextRoom() { - auto r = currentRoom(); - - if (r) { - int idx = roomidToIndex(r->roomId()); - idx++; - if (idx < rowCount()) { - setCurrentRoom( - data(index(idx, 0), RoomlistModel::Roles::RoomId).toString()); - } + auto r = currentRoom(); + + if (r) { + int idx = roomidToIndex(r->roomId()); + idx++; + if (idx < rowCount()) { + setCurrentRoom(data(index(idx, 0), RoomlistModel::Roles::RoomId).toString()); } + } } void FilteredRoomlistModel::previousRoom() { - auto r = currentRoom(); - - if (r) { - int idx = roomidToIndex(r->roomId()); - idx--; - if (idx >= 0) { - setCurrentRoom( - data(index(idx, 0), RoomlistModel::Roles::RoomId).toString()); - } + auto r = currentRoom(); + + if (r) { + int idx = roomidToIndex(r->roomId()); + idx--; + if (idx >= 0) { + setCurrentRoom(data(index(idx, 0), RoomlistModel::Roles::RoomId).toString()); } + } } |