diff options
author | Nicolas Werner <nicolas.werner@hotmail.de> | 2021-05-22 00:57:14 +0200 |
---|---|---|
committer | Nicolas Werner <nicolas.werner@hotmail.de> | 2021-05-22 00:57:14 +0200 |
commit | beeb60e4a12b47ae619e52629040aff5a8f43db2 (patch) | |
tree | f5fa4037fcae00d866ede81efebdc6273202bfee | |
parent | Make roomlist look nice (diff) | |
download | nheko-beeb60e4a12b47ae619e52629040aff5a8f43db2.tar.xz |
Sort the room list
-rw-r--r-- | resources/qml/RoomList.qml | 2 | ||||
-rw-r--r-- | src/timeline/RoomlistModel.cpp | 93 | ||||
-rw-r--r-- | src/timeline/RoomlistModel.h | 26 | ||||
-rw-r--r-- | src/timeline/TimelineModel.cpp | 2 | ||||
-rw-r--r-- | src/timeline/TimelineModel.h | 2 | ||||
-rw-r--r-- | src/timeline/TimelineViewManager.cpp | 4 |
6 files changed, 120 insertions, 9 deletions
diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index bb8deda6..f2a957c9 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -131,7 +131,7 @@ Page { Layout.alignment: Qt.AlignRight | Qt.AlignBottom font.pixelSize: fontMetrics.font.pixelSize * 0.9 color: roomItem.unimportantText - text: model.timestamp + text: model.time } } diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp index 5fc4dc65..afe9679a 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp @@ -42,10 +42,13 @@ RoomlistModel::roleNames() const {RoomName, "roomName"}, {RoomId, "roomId"}, {LastMessage, "lastMessage"}, + {Time, "time"}, {Timestamp, "timestamp"}, {HasUnreadMessages, "hasUnreadMessages"}, {HasLoudNotification, "hasLoudNotification"}, {NotificationCount, "notificationCount"}, + {IsInvite, "isInvite"}, + {IsSpace, "isSpace"}, }; } @@ -64,8 +67,10 @@ RoomlistModel::data(const QModelIndex &index, int role) const return room->roomId(); case Roles::LastMessage: return room->lastMessage().body; - case Roles::Timestamp: + 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); @@ -73,6 +78,9 @@ RoomlistModel::data(const QModelIndex &index, int role) const return room->hasMentions(); case Roles::NotificationCount: return room->notificationCount(); + case Roles::IsInvite: + case Roles::IsSpace: + return false; default: return {}; } @@ -90,9 +98,9 @@ RoomlistModel::updateReadStatus(const std::map<QString, bool> roomReadStatus_) if (roomUnread != roomReadStatus[roomid]) { roomsToUpdate.push_back(this->roomidToIndex(roomid)); } - } - this->roomReadStatus = roomReadStatus_; + this->roomReadStatus[roomid] = roomUnread; + } for (auto idx : roomsToUpdate) { emit dataChanged(index(idx), @@ -135,6 +143,7 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification) Roles::LastMessage, Roles::Timestamp, Roles::NotificationCount, + Qt::DisplayRole, }); }); connect( @@ -162,6 +171,7 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification) { Roles::HasLoudNotification, Roles::NotificationCount, + Qt::DisplayRole, }); int total_unread_msgs = 0; @@ -225,7 +235,6 @@ RoomlistModel::initializeRooms(const std::vector<QString> &roomIds_) beginResetModel(); models.clear(); roomids.clear(); - roomids = roomIds_; for (const auto &id : roomIds_) addRoom(id, true); endResetModel(); @@ -239,3 +248,79 @@ RoomlistModel::clear() roomids.clear(); endResetModel(); } + +namespace { +enum NotificationImportance : short +{ + ImportanceDisabled = -1, + AllEventsRead = 0, + NewMessage = 1, + NewMentions = 2, + Invite = 3 +}; +} + +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::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(); +} + +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(); + }); + + sort(0); +} diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h index c4c9d9ba..c3374bd2 100644 --- a/src/timeline/RoomlistModel.h +++ b/src/timeline/RoomlistModel.h @@ -7,6 +7,7 @@ #include <QAbstractListModel> #include <QHash> #include <QSharedPointer> +#include <QSortFilterProxyModel> #include <QString> #include <mtx/responses/sync.hpp> @@ -24,10 +25,13 @@ public: RoomName, RoomId, LastMessage, + Time, Timestamp, HasUnreadMessages, HasLoudNotification, NotificationCount, + IsInvite, + IsSpace, }; RoomlistModel(TimelineViewManager *parent = nullptr); @@ -73,4 +77,26 @@ private: std::vector<QString> roomids; QHash<QString, QSharedPointer<TimelineModel>> models; std::map<QString, bool> roomReadStatus; + + friend class FilteredRoomlistModel; +}; + +class FilteredRoomlistModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr); + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + +public slots: + int roomidToIndex(QString roomid) + { + return mapFromSource(roomlistmodel->index(roomlistmodel->roomidToIndex(roomid))) + .row(); + } + +private: + short int calculateImportance(const QModelIndex &idx) const; + RoomlistModel *roomlistmodel; + bool sortByImportance = true; }; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 19c3fb30..2625127c 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -318,6 +318,8 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj , room_id_(room_id) , manager_(manager) { + lastMessage_.timestamp = 0; + connect( this, &TimelineModel::redactionFailed, diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 5c1065cb..b3d3b663 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -382,7 +382,7 @@ private: QString eventIdToShow; int showEventTimerCounter = 0; - DescInfo lastMessage_; + DescInfo lastMessage_{}; friend struct SendMessageVisitor; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index b0c13b03..c84e0df8 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -193,9 +193,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par }); qmlRegisterSingletonType<RoomlistModel>( "im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * { - auto ptr = self->rooms; - QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership); - return ptr; + return new FilteredRoomlistModel(self->rooms); }); qmlRegisterSingletonType<UserSettings>( "im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * { |