summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-05-22 00:57:14 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2021-05-22 00:57:14 +0200
commitbeeb60e4a12b47ae619e52629040aff5a8f43db2 (patch)
treef5fa4037fcae00d866ede81efebdc6273202bfee
parentMake roomlist look nice (diff)
downloadnheko-beeb60e4a12b47ae619e52629040aff5a8f43db2.tar.xz
Sort the room list
-rw-r--r--resources/qml/RoomList.qml2
-rw-r--r--src/timeline/RoomlistModel.cpp93
-rw-r--r--src/timeline/RoomlistModel.h26
-rw-r--r--src/timeline/TimelineModel.cpp2
-rw-r--r--src/timeline/TimelineModel.h2
-rw-r--r--src/timeline/TimelineViewManager.cpp4
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 * {