Updated room sorting
Change the LastActivity sort order to Activity and update to a more flexible way of sorting based on an order from model roles. Add options to actually switch between Alphabetical and Activity Based on some old work by @tdfischer implements #103
This commit is contained in:
@@ -220,6 +220,8 @@ QHash<int, QByteArray> RoomTreeModel::roleNames() const
|
||||
roles[IsDirectChat] = "isDirectChat";
|
||||
roles[DelegateTypeRole] = "delegateType";
|
||||
roles[IconRole] = "icon";
|
||||
roles[AttentionRole] = "attention";
|
||||
roles[FavouriteRole] = "favourite";
|
||||
return roles;
|
||||
}
|
||||
|
||||
@@ -270,10 +272,10 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
|
||||
return NeoChatRoomType::typeForRoom(room);
|
||||
}
|
||||
if (role == NotificationCountRole) {
|
||||
return room->notificationCount();
|
||||
return int(room->notificationCount());
|
||||
}
|
||||
if (role == HighlightCountRole) {
|
||||
return room->highlightCount();
|
||||
return int(room->highlightCount());
|
||||
}
|
||||
if (role == LastActiveTimeRole) {
|
||||
return room->lastActiveTime();
|
||||
@@ -315,6 +317,12 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
|
||||
if (role == DelegateTypeRole) {
|
||||
return QStringLiteral("normal");
|
||||
}
|
||||
if (role == AttentionRole) {
|
||||
return room->notificationCount() + room->highlightCount() > 0;
|
||||
}
|
||||
if (role == FavouriteRole) {
|
||||
return room->isFavourite();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
IsDirectChat, /**< Whether this room is a direct chat. */
|
||||
DelegateTypeRole,
|
||||
IconRole,
|
||||
AttentionRole, /**< Whether there are any notifications. */
|
||||
FavouriteRole, /**< Whether the room is favourited. */
|
||||
};
|
||||
Q_ENUM(EventRoles)
|
||||
explicit RoomTreeModel(QObject *parent = nullptr);
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
SortFilterRoomTreeModel::SortFilterRoomTreeModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
setRoomSortOrder(static_cast<RoomSortOrder>(NeoChatConfig::sortOrder()));
|
||||
connect(NeoChatConfig::self(), &NeoChatConfig::SortOrderChanged, this, [this]() {
|
||||
setRoomSortOrder(static_cast<RoomSortOrder>(NeoChatConfig::sortOrder()));
|
||||
invalidateFilter();
|
||||
});
|
||||
|
||||
setRecursiveFilteringEnabled(true);
|
||||
sort(0);
|
||||
invalidateFilter();
|
||||
@@ -29,48 +35,75 @@ SortFilterRoomTreeModel::SortFilterRoomTreeModel(QObject *parent)
|
||||
void SortFilterRoomTreeModel::setRoomSortOrder(SortFilterRoomTreeModel::RoomSortOrder sortOrder)
|
||||
{
|
||||
m_sortOrder = sortOrder;
|
||||
Q_EMIT roomSortOrderChanged();
|
||||
if (sortOrder == SortFilterRoomTreeModel::Alphabetical) {
|
||||
setSortRole(RoomTreeModel::DisplayNameRole);
|
||||
} else if (sortOrder == SortFilterRoomTreeModel::LastActivity) {
|
||||
} else if (sortOrder == SortFilterRoomTreeModel::Activity) {
|
||||
setSortRole(RoomTreeModel::LastActiveTimeRole);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
SortFilterRoomTreeModel::RoomSortOrder SortFilterRoomTreeModel::roomSortOrder() const
|
||||
static const QVector<RoomTreeModel::EventRoles> alphabeticalSortPriorities{
|
||||
// Does exactly what it says on the tin.
|
||||
RoomTreeModel::DisplayNameRole,
|
||||
};
|
||||
|
||||
static const QVector<RoomTreeModel::EventRoles> activitySortPriorities{
|
||||
// Anything useful at the top, quiet rooms at the bottom
|
||||
RoomTreeModel::AttentionRole,
|
||||
// Organize by highlights, notifications, unread favorites, all other unread, in that order
|
||||
RoomTreeModel::HighlightCountRole,
|
||||
RoomTreeModel::NotificationCountRole,
|
||||
RoomTreeModel::FavouriteRole,
|
||||
// Finally sort by last activity time
|
||||
RoomTreeModel::LastActiveTimeRole,
|
||||
};
|
||||
|
||||
bool SortFilterRoomTreeModel::roleCmp(const QVariant &sortLeft, const QVariant &sortRight) const
|
||||
{
|
||||
return m_sortOrder;
|
||||
switch (sortLeft.typeId()) {
|
||||
case QMetaType::Bool:
|
||||
return (sortLeft == sortRight) ? false : sortLeft.toBool();
|
||||
case QMetaType::QString:
|
||||
return sortLeft.toString() < sortRight.toString();
|
||||
case QMetaType::Int:
|
||||
return sortLeft.toInt() > sortRight.toInt();
|
||||
case QMetaType::QDateTime:
|
||||
return sortLeft.toDateTime() > sortRight.toDateTime();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SortFilterRoomTreeModel::prioritiesCmp(const QVector<RoomTreeModel::EventRoles> &priorities,
|
||||
const QModelIndex &source_left,
|
||||
const QModelIndex &source_right) const
|
||||
{
|
||||
for (RoomTreeModel::EventRoles sortRole : priorities) {
|
||||
const auto sortLeft = sourceModel()->data(source_left, sortRole);
|
||||
const auto sortRight = sourceModel()->data(source_right, sortRole);
|
||||
if (sortLeft != sortRight) {
|
||||
return roleCmp(sortLeft, sortRight);
|
||||
}
|
||||
}
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
bool SortFilterRoomTreeModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
if (m_sortOrder == SortFilterRoomTreeModel::LastActivity) {
|
||||
// display favorite rooms always on top
|
||||
const auto categoryLeft = static_cast<NeoChatRoomType::Types>(sourceModel()->data(source_left, RoomTreeModel::CategoryRole).toInt());
|
||||
const auto categoryRight = static_cast<NeoChatRoomType::Types>(sourceModel()->data(source_right, RoomTreeModel::CategoryRole).toInt());
|
||||
// Don't sort the top level categories.
|
||||
if (!source_left.parent().isValid() || !source_right.parent().isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (categoryLeft == NeoChatRoomType::Types::Favorite && categoryRight == NeoChatRoomType::Types::Favorite) {
|
||||
return sourceModel()->data(source_left, RoomTreeModel::LastActiveTimeRole).toDateTime()
|
||||
> sourceModel()->data(source_right, RoomTreeModel::LastActiveTimeRole).toDateTime();
|
||||
}
|
||||
if (categoryLeft == NeoChatRoomType::Types::Favorite) {
|
||||
return true;
|
||||
} else if (categoryRight == NeoChatRoomType::Types::Favorite) {
|
||||
return false;
|
||||
}
|
||||
switch (m_sortOrder) {
|
||||
case SortFilterRoomTreeModel::Alphabetical:
|
||||
return prioritiesCmp(alphabeticalSortPriorities, source_left, source_right);
|
||||
case SortFilterRoomTreeModel::Activity:
|
||||
return prioritiesCmp(activitySortPriorities, source_left, source_right);
|
||||
}
|
||||
|
||||
return sourceModel()->data(source_left, RoomTreeModel::LastActiveTimeRole).toDateTime()
|
||||
> sourceModel()->data(source_right, RoomTreeModel::LastActiveTimeRole).toDateTime();
|
||||
}
|
||||
if (m_sortOrder != SortFilterRoomTreeModel::Categories) {
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
if (sourceModel()->data(source_left, RoomTreeModel::CategoryRole) != sourceModel()->data(source_right, RoomTreeModel::CategoryRole)) {
|
||||
return sourceModel()->data(source_left, RoomTreeModel::CategoryRole).toInt() < sourceModel()->data(source_right, RoomTreeModel::CategoryRole).toInt();
|
||||
}
|
||||
return sourceModel()->data(source_left, RoomTreeModel::LastActiveTimeRole).toDateTime()
|
||||
> sourceModel()->data(source_right, RoomTreeModel::LastActiveTimeRole).toDateTime();
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
void SortFilterRoomTreeModel::setFilterText(const QString &text)
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <QQmlEngine>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "models/roomtreemodel.h"
|
||||
|
||||
/**
|
||||
* @class SortFilterRoomTreeModel
|
||||
*
|
||||
@@ -31,13 +33,6 @@ class SortFilterRoomTreeModel : public QSortFilterProxyModel
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
/**
|
||||
* @brief The order by which the rooms will be sorted.
|
||||
*
|
||||
* @sa RoomSortOrder
|
||||
*/
|
||||
Q_PROPERTY(RoomSortOrder roomSortOrder READ roomSortOrder WRITE setRoomSortOrder NOTIFY roomSortOrderChanged)
|
||||
|
||||
/**
|
||||
* @brief The text to use to filter room names.
|
||||
*/
|
||||
@@ -56,8 +51,7 @@ class SortFilterRoomTreeModel : public QSortFilterProxyModel
|
||||
public:
|
||||
enum RoomSortOrder {
|
||||
Alphabetical,
|
||||
LastActivity,
|
||||
Categories,
|
||||
Activity,
|
||||
};
|
||||
Q_ENUM(RoomSortOrder)
|
||||
|
||||
@@ -71,7 +65,6 @@ public:
|
||||
explicit SortFilterRoomTreeModel(QObject *parent = nullptr);
|
||||
|
||||
void setRoomSortOrder(RoomSortOrder sortOrder);
|
||||
[[nodiscard]] RoomSortOrder roomSortOrder() const;
|
||||
|
||||
void setFilterText(const QString &text);
|
||||
[[nodiscard]] QString filterText() const;
|
||||
@@ -98,14 +91,16 @@ protected:
|
||||
[[nodiscard]] bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void roomSortOrderChanged();
|
||||
void filterTextChanged();
|
||||
void activeSpaceIdChanged();
|
||||
void modeChanged();
|
||||
|
||||
private:
|
||||
RoomSortOrder m_sortOrder = Categories;
|
||||
RoomSortOrder m_sortOrder = Activity;
|
||||
Mode m_mode = All;
|
||||
QString m_filterText;
|
||||
QString m_activeSpaceId;
|
||||
|
||||
bool roleCmp(const QVariant &left, const QVariant &right) const;
|
||||
bool prioritiesCmp(const QVector<RoomTreeModel::EventRoles> &priorities, const QModelIndex &left, const QModelIndex &right) const;
|
||||
};
|
||||
|
||||
@@ -118,6 +118,10 @@
|
||||
<label>Save the collapsed state of the room list</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="SortOrder" type="int">
|
||||
<label>The sort order for the rooms in the list.</label>
|
||||
<default>1</default>
|
||||
</entry>
|
||||
</group>
|
||||
<group name="NetworkProxy">
|
||||
<entry name="ProxyType" type="Enum">
|
||||
|
||||
@@ -65,6 +65,29 @@ FormCard.FormCardPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
FormCard.FormHeader {
|
||||
title: i18n("Room list sort order")
|
||||
}
|
||||
FormCard.FormCard {
|
||||
FormCard.FormRadioDelegate {
|
||||
text: i18nc("As in 'sort something based on last activity'", "Activity")
|
||||
checked: Config.sortOrder === 1
|
||||
enabled: !Config.isSortOrderImmutable
|
||||
onToggled: {
|
||||
Config.sortOrder = 1
|
||||
Config.save()
|
||||
}
|
||||
}
|
||||
FormCard.FormRadioDelegate {
|
||||
text: i18nc("As in 'sort something alphabetically'", "Alphabetical")
|
||||
checked: Config.sortOrder === 0
|
||||
enabled: !Config.isSortOrderImmutable
|
||||
onToggled: {
|
||||
Config.sortOrder = 0
|
||||
Config.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
FormCard.FormHeader {
|
||||
title: i18n("Timeline Events")
|
||||
}
|
||||
|
||||
@@ -148,7 +148,6 @@ Kirigami.Page {
|
||||
property bool filterTextJustChanged: false
|
||||
|
||||
sourceModel: root.roomTreeModel
|
||||
roomSortOrder: SortFilterRoomTreeModel.Categories
|
||||
activeSpaceId: spaceDrawer.selectedSpaceId
|
||||
mode: spaceDrawer.showDirectChats ? SortFilterRoomTreeModel.DirectChats : SortFilterRoomTreeModel.Rooms
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user