matrixion/src/timeline/CommunitiesModel.h

253 lines
7.4 KiB
C
Raw Normal View History

// SPDX-FileCopyrightText: Nheko Contributors
2021-06-10 00:52:28 +03:00
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QAbstractListModel>
#include <QHash>
2023-06-19 02:38:40 +03:00
#include <QQmlEngine>
2021-12-01 02:02:41 +03:00
#include <QSortFilterProxyModel>
2021-06-10 00:52:28 +03:00
#include <QString>
#include <QStringList>
2022-07-16 05:09:52 +03:00
#include <unordered_map>
2021-06-10 00:52:28 +03:00
#include <mtx/responses/sync.hpp>
#include "CacheStructs.h"
2021-12-01 02:02:41 +03:00
class CommunitiesModel;
2022-10-10 15:38:29 +03:00
class FilteredCommunitiesModel final : public QSortFilterProxyModel
2021-12-01 02:02:41 +03:00
{
Q_OBJECT
2023-06-19 02:38:40 +03:00
QML_ELEMENT
QML_UNCREATABLE("Use Communities.filtered() to create a FilteredCommunitiesModel")
2021-12-01 02:02:41 +03:00
public:
2022-07-15 17:19:06 +03:00
explicit FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr);
2021-12-01 02:02:41 +03:00
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override;
};
2022-08-10 01:20:44 +03:00
class SpaceItem
{
Q_GADGET
Q_PROPERTY(QString roomid MEMBER roomid CONSTANT)
Q_PROPERTY(QString name MEMBER name CONSTANT)
Q_PROPERTY(int treeIndex MEMBER treeIndex CONSTANT)
Q_PROPERTY(bool childValid MEMBER childValid CONSTANT)
Q_PROPERTY(bool parentValid MEMBER parentValid CONSTANT)
Q_PROPERTY(bool canonical MEMBER canonical CONSTANT)
Q_PROPERTY(bool canEditParent MEMBER canEditParent CONSTANT)
Q_PROPERTY(bool canEditChild MEMBER canEditChild CONSTANT)
public:
SpaceItem() {}
SpaceItem(QString roomid_,
QString name_,
int treeIndex_,
bool childValid_,
bool parentValid_,
bool canonical_,
bool canEditChild_,
bool canEditParent_)
: roomid(std::move(roomid_))
, name(std::move(name_))
, treeIndex(treeIndex_)
, childValid(childValid_)
, parentValid(parentValid_)
, canonical(canonical_)
, canEditParent(canEditParent_)
, canEditChild(canEditChild_)
2022-09-25 21:05:08 +03:00
{
}
2022-08-10 01:20:44 +03:00
QString roomid, name;
int treeIndex = 0;
bool childValid = false, parentValid = false, canonical = false;
bool canEditParent = false, canEditChild = false;
};
2022-10-10 15:38:29 +03:00
class CommunitiesModel final : public QAbstractListModel
2021-06-10 00:52:28 +03:00
{
2021-09-18 01:22:33 +03:00
Q_OBJECT
2023-06-19 02:38:40 +03:00
QML_NAMED_ELEMENT(Communities)
QML_SINGLETON
2021-09-18 01:22:33 +03:00
Q_PROPERTY(QString currentTagId READ currentTagId WRITE setCurrentTagId NOTIFY
currentTagIdChanged RESET resetCurrentTagId)
Q_PROPERTY(QStringList tags READ tags NOTIFY tagsChanged)
Q_PROPERTY(QStringList tagsWithDefault READ tagsWithDefault NOTIFY tagsChanged)
Q_PROPERTY(bool containsSubspaces READ containsSubspaces NOTIFY containsSubspacesChanged)
2021-06-10 00:52:28 +03:00
public:
2021-09-18 01:22:33 +03:00
enum Roles
{
AvatarUrl = Qt::UserRole,
DisplayName,
Tooltip,
2021-12-01 02:02:41 +03:00
Collapsed,
Collapsible,
2021-09-18 01:22:33 +03:00
Hidden,
2021-12-01 02:02:41 +03:00
Parent,
Depth,
2021-09-18 01:22:33 +03:00
Id,
UnreadMessages,
2022-04-21 04:30:16 +03:00
HasLoudNotification,
Muted,
2022-04-26 03:54:40 +03:00
IsDirect,
2021-09-18 01:22:33 +03:00
};
2021-06-10 00:52:28 +03:00
2021-12-01 02:02:41 +03:00
struct FlatTree
{
struct Elem
{
QString id;
2022-07-15 17:19:06 +03:00
int depth = 0;
mtx::responses::UnreadNotifications notificationCounts = {0, 0};
2021-12-01 02:02:41 +03:00
bool collapsed = false;
};
std::vector<Elem> tree;
int size() const { return static_cast<int>(tree.size()); }
int indexOf(const QString &s) const
{
for (int i = 0; i < size(); i++)
if (tree[i].id == s)
2021-12-01 02:02:41 +03:00
return i;
return -1;
}
int lastChild(int index) const
{
if (index >= size() || index < 0)
return index;
const auto depth = tree[index].depth;
int i = index + 1;
for (; i < size(); i++)
2021-12-01 02:24:57 +03:00
if (tree[i].depth <= depth)
2021-12-01 02:02:41 +03:00
break;
return i - 1;
}
int parent(int index) const
{
if (index >= size() || index < 0)
return -1;
const auto depth = tree[index].depth;
if (depth == 0)
return -1;
int i = index - 1;
for (; i >= 0; i--)
if (tree[i].depth < depth)
break;
return i;
}
2021-12-01 05:46:55 +03:00
void storeCollapsed();
void restoreCollapsed();
2021-12-01 02:02:41 +03:00
};
CommunitiesModel(QObject *parent);
2023-06-19 02:38:40 +03:00
static CommunitiesModel *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance_);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance_->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
return instance_;
}
2021-09-18 01:22:33 +03:00
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
(void)parent;
return 2 + tags_.size() + spaceOrder_.size();
2021-09-18 01:22:33 +03:00
}
QVariant data(const QModelIndex &index, int role) const override;
2021-12-01 02:02:41 +03:00
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
2021-06-10 00:52:28 +03:00
bool containsSubspaces() const
{
for (const auto &e : spaceOrder_.tree)
if (e.depth > 0)
return true;
return false;
}
Q_INVOKABLE QVariantList spaceChildrenListFromIndex(const QString &room, int idx = -1) const;
2022-08-10 01:20:44 +03:00
Q_INVOKABLE void updateSpaceStatus(QString space,
QString room,
bool setParent,
bool setChild,
bool canonical) const;
2021-06-10 00:52:28 +03:00
public slots:
2021-09-18 01:22:33 +03:00
void initializeSidebar();
void sync(const mtx::responses::Sync &sync_);
2021-09-18 01:22:33 +03:00
void clear();
QString currentTagId() const { return currentTagId_; }
void setCurrentTagId(const QString &tagId);
2022-09-20 22:26:28 +03:00
bool trySwitchToSpace(const QString &spaceId);
2021-09-18 01:22:33 +03:00
void resetCurrentTagId()
{
currentTagId_.clear();
emit currentTagIdChanged(currentTagId_);
}
QStringList tags() const { return tags_; }
QStringList tagsWithDefault() const
{
QStringList tagsWD = tags_;
tagsWD.prepend(QStringLiteral("m.lowpriority"));
tagsWD.prepend(QStringLiteral("m.favourite"));
tagsWD.removeOne(QStringLiteral("m.server_notice"));
2021-09-18 01:22:33 +03:00
tagsWD.removeDuplicates();
return tagsWD;
}
void toggleTagId(QString tagId);
void toggleTagMute(QString tagId);
2022-08-10 01:20:44 +03:00
2021-12-01 02:02:41 +03:00
FilteredCommunitiesModel *filtered() { return new FilteredCommunitiesModel(this, this); }
2021-06-10 00:52:28 +03:00
signals:
2021-09-18 01:22:33 +03:00
void currentTagIdChanged(QString tagId);
void hiddenTagsChanged();
void tagsChanged();
void containsSubspacesChanged();
2021-06-10 00:52:28 +03:00
private:
2021-09-18 01:22:33 +03:00
QStringList tags_;
QString currentTagId_;
2022-04-20 03:49:37 +03:00
QStringList hiddenTagIds_;
QStringList mutedTagIds_;
2021-12-01 02:02:41 +03:00
FlatTree spaceOrder_;
2021-09-18 01:22:33 +03:00
std::map<QString, RoomInfo> spaces_;
2022-04-26 03:54:40 +03:00
std::vector<std::string> directMessages_;
2021-12-01 02:02:41 +03:00
2022-07-15 17:19:06 +03:00
std::unordered_map<QString, mtx::responses::UnreadNotifications> roomNotificationCache;
std::unordered_map<QString, mtx::responses::UnreadNotifications> tagNotificationCache;
mtx::responses::UnreadNotifications globalUnreads{};
mtx::responses::UnreadNotifications dmUnreads{};
2021-12-01 02:02:41 +03:00
friend class FilteredCommunitiesModel;
2023-06-19 02:38:40 +03:00
inline static CommunitiesModel *instance_ = nullptr;
2021-06-10 00:52:28 +03:00
};