Sort the room list

pull/605/head
Nicolas Werner 4 years ago
parent cd67046f60
commit beeb60e4a1
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
  1. 2
      resources/qml/RoomList.qml
  2. 93
      src/timeline/RoomlistModel.cpp
  3. 26
      src/timeline/RoomlistModel.h
  4. 2
      src/timeline/TimelineModel.cpp
  5. 2
      src/timeline/TimelineModel.h
  6. 4
      src/timeline/TimelineViewManager.cpp

@ -131,7 +131,7 @@ Page {
Layout.alignment: Qt.AlignRight | Qt.AlignBottom Layout.alignment: Qt.AlignRight | Qt.AlignBottom
font.pixelSize: fontMetrics.font.pixelSize * 0.9 font.pixelSize: fontMetrics.font.pixelSize * 0.9
color: roomItem.unimportantText color: roomItem.unimportantText
text: model.timestamp text: model.time
} }
} }

@ -42,10 +42,13 @@ RoomlistModel::roleNames() const
{RoomName, "roomName"}, {RoomName, "roomName"},
{RoomId, "roomId"}, {RoomId, "roomId"},
{LastMessage, "lastMessage"}, {LastMessage, "lastMessage"},
{Time, "time"},
{Timestamp, "timestamp"}, {Timestamp, "timestamp"},
{HasUnreadMessages, "hasUnreadMessages"}, {HasUnreadMessages, "hasUnreadMessages"},
{HasLoudNotification, "hasLoudNotification"}, {HasLoudNotification, "hasLoudNotification"},
{NotificationCount, "notificationCount"}, {NotificationCount, "notificationCount"},
{IsInvite, "isInvite"},
{IsSpace, "isSpace"},
}; };
} }
@ -64,8 +67,10 @@ RoomlistModel::data(const QModelIndex &index, int role) const
return room->roomId(); return room->roomId();
case Roles::LastMessage: case Roles::LastMessage:
return room->lastMessage().body; return room->lastMessage().body;
case Roles::Timestamp: case Roles::Time:
return room->lastMessage().descriptiveTime; return room->lastMessage().descriptiveTime;
case Roles::Timestamp:
return QVariant(static_cast<quint64>(room->lastMessage().timestamp));
case Roles::HasUnreadMessages: case Roles::HasUnreadMessages:
return this->roomReadStatus.count(roomid) && return this->roomReadStatus.count(roomid) &&
this->roomReadStatus.at(roomid); this->roomReadStatus.at(roomid);
@ -73,6 +78,9 @@ RoomlistModel::data(const QModelIndex &index, int role) const
return room->hasMentions(); return room->hasMentions();
case Roles::NotificationCount: case Roles::NotificationCount:
return room->notificationCount(); return room->notificationCount();
case Roles::IsInvite:
case Roles::IsSpace:
return false;
default: default:
return {}; return {};
} }
@ -90,9 +98,9 @@ RoomlistModel::updateReadStatus(const std::map<QString, bool> roomReadStatus_)
if (roomUnread != roomReadStatus[roomid]) { if (roomUnread != roomReadStatus[roomid]) {
roomsToUpdate.push_back(this->roomidToIndex(roomid)); roomsToUpdate.push_back(this->roomidToIndex(roomid));
} }
}
this->roomReadStatus = roomReadStatus_; this->roomReadStatus[roomid] = roomUnread;
}
for (auto idx : roomsToUpdate) { for (auto idx : roomsToUpdate) {
emit dataChanged(index(idx), emit dataChanged(index(idx),
@ -135,6 +143,7 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
Roles::LastMessage, Roles::LastMessage,
Roles::Timestamp, Roles::Timestamp,
Roles::NotificationCount, Roles::NotificationCount,
Qt::DisplayRole,
}); });
}); });
connect( connect(
@ -162,6 +171,7 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
{ {
Roles::HasLoudNotification, Roles::HasLoudNotification,
Roles::NotificationCount, Roles::NotificationCount,
Qt::DisplayRole,
}); });
int total_unread_msgs = 0; int total_unread_msgs = 0;
@ -225,7 +235,6 @@ RoomlistModel::initializeRooms(const std::vector<QString> &roomIds_)
beginResetModel(); beginResetModel();
models.clear(); models.clear();
roomids.clear(); roomids.clear();
roomids = roomIds_;
for (const auto &id : roomIds_) for (const auto &id : roomIds_)
addRoom(id, true); addRoom(id, true);
endResetModel(); endResetModel();
@ -239,3 +248,79 @@ RoomlistModel::clear()
roomids.clear(); roomids.clear();
endResetModel(); 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);
}

@ -7,6 +7,7 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QHash> #include <QHash>
#include <QSharedPointer> #include <QSharedPointer>
#include <QSortFilterProxyModel>
#include <QString> #include <QString>
#include <mtx/responses/sync.hpp> #include <mtx/responses/sync.hpp>
@ -24,10 +25,13 @@ public:
RoomName, RoomName,
RoomId, RoomId,
LastMessage, LastMessage,
Time,
Timestamp, Timestamp,
HasUnreadMessages, HasUnreadMessages,
HasLoudNotification, HasLoudNotification,
NotificationCount, NotificationCount,
IsInvite,
IsSpace,
}; };
RoomlistModel(TimelineViewManager *parent = nullptr); RoomlistModel(TimelineViewManager *parent = nullptr);
@ -73,4 +77,26 @@ private:
std::vector<QString> roomids; std::vector<QString> roomids;
QHash<QString, QSharedPointer<TimelineModel>> models; QHash<QString, QSharedPointer<TimelineModel>> models;
std::map<QString, bool> roomReadStatus; 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;
}; };

@ -318,6 +318,8 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
, room_id_(room_id) , room_id_(room_id)
, manager_(manager) , manager_(manager)
{ {
lastMessage_.timestamp = 0;
connect( connect(
this, this,
&TimelineModel::redactionFailed, &TimelineModel::redactionFailed,

@ -382,7 +382,7 @@ private:
QString eventIdToShow; QString eventIdToShow;
int showEventTimerCounter = 0; int showEventTimerCounter = 0;
DescInfo lastMessage_; DescInfo lastMessage_{};
friend struct SendMessageVisitor; friend struct SendMessageVisitor;

@ -193,9 +193,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
}); });
qmlRegisterSingletonType<RoomlistModel>( qmlRegisterSingletonType<RoomlistModel>(
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * { "im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
auto ptr = self->rooms; return new FilteredRoomlistModel(self->rooms);
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
return ptr;
}); });
qmlRegisterSingletonType<UserSettings>( qmlRegisterSingletonType<UserSettings>(
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * { "im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {

Loading…
Cancel
Save