2023-02-22 01:48:49 +03:00
|
|
|
// SPDX-FileCopyrightText: Nheko Contributors
|
2021-05-19 20:34:10 +03:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2021-05-24 15:04:07 +03:00
|
|
|
#include <CacheStructs.h>
|
2021-05-19 20:34:10 +03:00
|
|
|
#include <QAbstractListModel>
|
|
|
|
#include <QHash>
|
2022-05-07 21:36:38 +03:00
|
|
|
#include <QQmlEngine>
|
2021-05-19 20:34:10 +03:00
|
|
|
#include <QSharedPointer>
|
2021-05-22 01:57:14 +03:00
|
|
|
#include <QSortFilterProxyModel>
|
2021-05-19 20:34:10 +03:00
|
|
|
#include <QString>
|
2021-05-28 18:25:46 +03:00
|
|
|
#include <set>
|
2021-05-19 20:34:10 +03:00
|
|
|
|
|
|
|
#include <mtx/responses/sync.hpp>
|
|
|
|
|
2021-05-28 23:14:59 +03:00
|
|
|
#include "TimelineModel.h"
|
|
|
|
|
2022-04-14 18:02:55 +03:00
|
|
|
#ifdef NHEKO_DBUS_SYS
|
|
|
|
#include "dbus/NhekoDBusBackend.h"
|
|
|
|
#endif
|
|
|
|
|
2021-05-19 20:34:10 +03:00
|
|
|
class TimelineViewManager;
|
|
|
|
|
2021-07-09 10:36:33 +03:00
|
|
|
class RoomPreview
|
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
Q_GADGET
|
|
|
|
Q_PROPERTY(QString roomid READ roomid CONSTANT)
|
|
|
|
Q_PROPERTY(QString roomName READ roomName CONSTANT)
|
|
|
|
Q_PROPERTY(QString roomTopic READ roomTopic CONSTANT)
|
|
|
|
Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl CONSTANT)
|
2022-12-27 03:40:03 +03:00
|
|
|
Q_PROPERTY(QString reason READ reason CONSTANT)
|
2023-06-10 01:49:49 +03:00
|
|
|
Q_PROPERTY(QString inviterAvatarUrl READ inviterAvatarUrl CONSTANT)
|
|
|
|
Q_PROPERTY(QString inviterDisplayName READ inviterDisplayName CONSTANT)
|
|
|
|
Q_PROPERTY(QString inviterUserId READ inviterUserId CONSTANT)
|
2021-09-18 01:22:33 +03:00
|
|
|
Q_PROPERTY(bool isInvite READ isInvite CONSTANT)
|
2023-03-18 14:46:44 +03:00
|
|
|
Q_PROPERTY(bool isFetched READ isFetched CONSTANT)
|
2021-07-09 10:36:33 +03:00
|
|
|
|
|
|
|
public:
|
2021-09-18 01:22:33 +03:00
|
|
|
RoomPreview() {}
|
2021-07-09 10:36:33 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
QString roomid() const { return roomid_; }
|
|
|
|
QString roomName() const { return roomName_; }
|
|
|
|
QString roomTopic() const { return roomTopic_; }
|
|
|
|
QString roomAvatarUrl() const { return roomAvatarUrl_; }
|
2022-12-27 03:40:03 +03:00
|
|
|
QString reason() const { return reason_; }
|
2023-06-10 01:49:49 +03:00
|
|
|
QString inviterAvatarUrl() const;
|
|
|
|
QString inviterDisplayName() const;
|
|
|
|
QString inviterUserId() const;
|
2021-09-18 01:22:33 +03:00
|
|
|
bool isInvite() const { return isInvite_; }
|
2023-03-18 14:46:44 +03:00
|
|
|
bool isFetched() const { return isFetched_; }
|
2021-07-09 10:36:33 +03:00
|
|
|
|
2022-12-27 03:40:03 +03:00
|
|
|
QString roomid_, roomName_, roomAvatarUrl_, roomTopic_, reason_;
|
2023-03-18 14:46:44 +03:00
|
|
|
bool isInvite_ = false, isFetched_ = true;
|
2021-07-09 10:36:33 +03:00
|
|
|
};
|
|
|
|
|
2022-10-10 15:38:29 +03:00
|
|
|
class RoomlistModel final : public QAbstractListModel
|
2021-05-19 20:34:10 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
Q_OBJECT
|
|
|
|
Q_PROPERTY(
|
|
|
|
TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET resetCurrentRoom)
|
|
|
|
Q_PROPERTY(RoomPreview currentRoomPreview READ currentRoomPreview NOTIFY currentRoomChanged
|
|
|
|
RESET resetCurrentRoom)
|
2021-05-19 20:34:10 +03:00
|
|
|
public:
|
2021-09-18 01:22:33 +03:00
|
|
|
enum Roles
|
|
|
|
{
|
|
|
|
AvatarUrl = Qt::UserRole,
|
|
|
|
RoomName,
|
|
|
|
RoomId,
|
|
|
|
LastMessage,
|
|
|
|
Time,
|
|
|
|
Timestamp,
|
|
|
|
HasUnreadMessages,
|
|
|
|
HasLoudNotification,
|
|
|
|
NotificationCount,
|
|
|
|
IsInvite,
|
|
|
|
IsSpace,
|
|
|
|
IsPreview,
|
|
|
|
IsPreviewFetched,
|
|
|
|
Tags,
|
|
|
|
ParentSpaces,
|
|
|
|
IsDirect,
|
|
|
|
DirectChatOtherUserId,
|
|
|
|
};
|
|
|
|
|
|
|
|
RoomlistModel(TimelineViewManager *parent = nullptr);
|
|
|
|
QHash<int, QByteArray> roleNames() const override;
|
|
|
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
|
|
|
{
|
|
|
|
(void)parent;
|
|
|
|
return (int)roomids.size();
|
|
|
|
}
|
|
|
|
QVariant data(const QModelIndex &index, int role) const override;
|
|
|
|
QSharedPointer<TimelineModel> getRoomById(QString id) const
|
|
|
|
{
|
|
|
|
if (models.contains(id))
|
|
|
|
return models.value(id);
|
|
|
|
else
|
|
|
|
return {};
|
|
|
|
}
|
2022-05-06 01:36:38 +03:00
|
|
|
RoomPreview getRoomPreviewById(QString roomid) const;
|
2021-05-19 20:34:10 +03:00
|
|
|
|
2023-02-18 04:59:33 +03:00
|
|
|
void refetchOnlineKeyBackupKeys();
|
|
|
|
|
2021-05-19 20:34:10 +03:00
|
|
|
public slots:
|
2021-09-18 01:22:33 +03:00
|
|
|
void initializeRooms();
|
2021-11-21 00:48:04 +03:00
|
|
|
void sync(const mtx::responses::Sync &sync_);
|
2021-09-18 01:22:33 +03:00
|
|
|
void clear();
|
2022-10-04 00:57:30 +03:00
|
|
|
int roomidToIndex(const QString &roomid)
|
2021-09-18 01:22:33 +03:00
|
|
|
{
|
|
|
|
for (int i = 0; i < (int)roomids.size(); i++) {
|
|
|
|
if (roomids[i] == roomid)
|
|
|
|
return i;
|
2021-06-08 23:18:51 +03:00
|
|
|
}
|
2021-05-21 22:19:03 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
return -1;
|
|
|
|
}
|
2022-10-04 00:57:30 +03:00
|
|
|
void joinPreview(const QString &roomid);
|
2021-09-18 01:22:33 +03:00
|
|
|
void acceptInvite(QString roomid);
|
|
|
|
void declineInvite(QString roomid);
|
2022-03-31 00:38:38 +03:00
|
|
|
void leave(QString roomid, QString reason = "");
|
2021-09-18 01:22:33 +03:00
|
|
|
TimelineModel *currentRoom() const { return currentRoom_.get(); }
|
|
|
|
RoomPreview currentRoomPreview() const { return currentRoomPreview_.value_or(RoomPreview{}); }
|
2022-10-04 00:57:30 +03:00
|
|
|
void setCurrentRoom(const QString &roomid);
|
2021-09-18 01:22:33 +03:00
|
|
|
void resetCurrentRoom()
|
|
|
|
{
|
|
|
|
currentRoom_ = nullptr;
|
|
|
|
currentRoomPreview_.reset();
|
2022-09-12 02:05:20 +03:00
|
|
|
emit currentRoomChanged("");
|
2021-09-18 01:22:33 +03:00
|
|
|
}
|
|
|
|
|
2021-05-21 22:19:03 +03:00
|
|
|
private slots:
|
2022-10-04 00:57:30 +03:00
|
|
|
void updateReadStatus(const std::map<QString, bool> &roomReadStatus_);
|
2021-05-21 22:19:03 +03:00
|
|
|
|
|
|
|
signals:
|
2021-09-18 01:22:33 +03:00
|
|
|
void totalUnreadMessageCountUpdated(int unreadMessages);
|
2022-09-12 02:05:20 +03:00
|
|
|
void currentRoomChanged(QString currentRoomId);
|
2021-09-18 01:22:33 +03:00
|
|
|
void fetchedPreview(QString roomid, RoomInfo info);
|
2023-01-07 03:39:08 +03:00
|
|
|
void spaceSelected(QString roomId);
|
2021-05-19 20:34:10 +03:00
|
|
|
|
|
|
|
private:
|
2021-09-18 01:22:33 +03:00
|
|
|
void addRoom(const QString &room_id, bool suppressInsertNotification = false);
|
2022-02-02 21:03:01 +03:00
|
|
|
void fetchPreviews(QString roomid, const std::string &from = "");
|
2021-11-21 00:48:04 +03:00
|
|
|
std::set<QString> updateDMs(mtx::events::AccountDataEvent<mtx::events::account_data::Direct> e);
|
2021-05-19 20:34:10 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
TimelineViewManager *manager = nullptr;
|
|
|
|
std::vector<QString> roomids;
|
|
|
|
QHash<QString, RoomInfo> invites;
|
|
|
|
QHash<QString, QSharedPointer<TimelineModel>> models;
|
|
|
|
std::map<QString, bool> roomReadStatus;
|
|
|
|
QHash<QString, std::optional<RoomInfo>> previewedRooms;
|
2021-05-22 01:57:14 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
QSharedPointer<TimelineModel> currentRoom_;
|
|
|
|
std::optional<RoomPreview> currentRoomPreview_;
|
2021-05-28 23:14:59 +03:00
|
|
|
|
2021-11-21 00:48:04 +03:00
|
|
|
std::map<QString, std::vector<QString>> directChatToUser;
|
|
|
|
|
2022-04-14 18:02:55 +03:00
|
|
|
#ifdef NHEKO_DBUS_SYS
|
|
|
|
NhekoDBusBackend *dbusInterface_;
|
|
|
|
friend class NhekoDBusBackend;
|
|
|
|
#endif
|
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
friend class FilteredRoomlistModel;
|
2021-05-22 01:57:14 +03:00
|
|
|
};
|
|
|
|
|
2022-10-10 15:38:29 +03:00
|
|
|
class FilteredRoomlistModel final : public QSortFilterProxyModel
|
2021-05-22 01:57:14 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
Q_OBJECT
|
2023-06-19 02:38:40 +03:00
|
|
|
|
|
|
|
QML_NAMED_ELEMENT(Rooms)
|
|
|
|
QML_SINGLETON
|
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
Q_PROPERTY(
|
|
|
|
TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET resetCurrentRoom)
|
|
|
|
Q_PROPERTY(RoomPreview currentRoomPreview READ currentRoomPreview NOTIFY currentRoomChanged
|
|
|
|
RESET resetCurrentRoom)
|
2021-05-22 01:57:14 +03:00
|
|
|
public:
|
2021-09-18 01:22:33 +03:00
|
|
|
FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr);
|
2023-06-19 02:38:40 +03:00
|
|
|
|
|
|
|
static FilteredRoomlistModel *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
|
|
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
|
|
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override;
|
2021-05-22 01:57:14 +03:00
|
|
|
|
|
|
|
public slots:
|
2021-09-18 01:22:33 +03:00
|
|
|
int roomidToIndex(QString roomid)
|
|
|
|
{
|
|
|
|
return mapFromSource(roomlistmodel->index(roomlistmodel->roomidToIndex(roomid))).row();
|
|
|
|
}
|
2022-07-16 04:07:00 +03:00
|
|
|
void joinPreview(QString roomid) { roomlistmodel->joinPreview(roomid); }
|
2021-09-18 01:22:33 +03:00
|
|
|
void acceptInvite(QString roomid) { roomlistmodel->acceptInvite(roomid); }
|
|
|
|
void declineInvite(QString roomid) { roomlistmodel->declineInvite(roomid); }
|
2022-03-31 00:38:38 +03:00
|
|
|
void leave(QString roomid, QString reason = "") { roomlistmodel->leave(roomid, reason); }
|
2022-10-04 00:57:30 +03:00
|
|
|
void toggleTag(const QString &roomid, const QString &tag, bool on);
|
2022-06-24 02:44:50 +03:00
|
|
|
void copyLink(QString roomid);
|
2021-09-18 01:22:33 +03:00
|
|
|
|
|
|
|
TimelineModel *currentRoom() const { return roomlistmodel->currentRoom(); }
|
|
|
|
RoomPreview currentRoomPreview() const { return roomlistmodel->currentRoomPreview(); }
|
|
|
|
void setCurrentRoom(QString roomid) { roomlistmodel->setCurrentRoom(std::move(roomid)); }
|
|
|
|
void resetCurrentRoom() { roomlistmodel->resetCurrentRoom(); }
|
2021-12-14 03:05:22 +03:00
|
|
|
TimelineModel *getRoomById(const QString &id) const
|
|
|
|
{
|
2022-05-07 21:27:25 +03:00
|
|
|
auto r = roomlistmodel->getRoomById(id).data();
|
|
|
|
QQmlEngine::setObjectOwnership(r, QQmlEngine::CppOwnership);
|
|
|
|
return r;
|
2021-12-14 03:05:22 +03:00
|
|
|
}
|
2022-05-06 01:36:38 +03:00
|
|
|
RoomPreview getRoomPreviewById(QString roomid) const
|
|
|
|
{
|
|
|
|
return roomlistmodel->getRoomPreviewById(roomid);
|
|
|
|
}
|
2021-09-18 01:22:33 +03:00
|
|
|
|
|
|
|
void nextRoomWithActivity();
|
|
|
|
void nextRoom();
|
|
|
|
void previousRoom();
|
|
|
|
|
|
|
|
void updateFilterTag(QString tagId)
|
|
|
|
{
|
2021-12-29 06:28:08 +03:00
|
|
|
if (tagId.startsWith(QLatin1String("tag:"))) {
|
2021-09-18 01:22:33 +03:00
|
|
|
filterType = FilterBy::Tag;
|
|
|
|
filterStr = tagId.mid(4);
|
2021-12-29 06:28:08 +03:00
|
|
|
} else if (tagId.startsWith(QLatin1String("space:"))) {
|
2021-09-18 01:22:33 +03:00
|
|
|
filterType = FilterBy::Space;
|
|
|
|
filterStr = tagId.mid(6);
|
2022-02-02 21:03:01 +03:00
|
|
|
roomlistmodel->fetchPreviews(filterStr);
|
2021-12-29 06:28:08 +03:00
|
|
|
} else if (tagId.startsWith(QLatin1String("dm"))) {
|
2021-11-21 00:48:04 +03:00
|
|
|
filterType = FilterBy::DirectChats;
|
|
|
|
filterStr.clear();
|
2021-09-18 01:22:33 +03:00
|
|
|
} else {
|
|
|
|
filterType = FilterBy::Nothing;
|
|
|
|
filterStr.clear();
|
2021-06-11 15:51:29 +03:00
|
|
|
}
|
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
invalidateFilter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateHiddenTagsAndSpaces();
|
2021-06-11 18:54:05 +03:00
|
|
|
|
2021-05-28 23:14:59 +03:00
|
|
|
signals:
|
2022-09-12 02:05:20 +03:00
|
|
|
void currentRoomChanged(QString currentRoomId);
|
2021-05-28 23:14:59 +03:00
|
|
|
|
2021-05-22 01:57:14 +03:00
|
|
|
private:
|
2021-09-18 01:22:33 +03:00
|
|
|
short int calculateImportance(const QModelIndex &idx) const;
|
|
|
|
RoomlistModel *roomlistmodel;
|
|
|
|
bool sortByImportance = true;
|
2023-04-13 14:45:00 +03:00
|
|
|
bool sortByAlphabet = false;
|
2021-09-18 01:22:33 +03:00
|
|
|
|
|
|
|
enum class FilterBy
|
|
|
|
{
|
|
|
|
Tag,
|
|
|
|
Space,
|
2021-11-21 00:48:04 +03:00
|
|
|
DirectChats,
|
2021-09-18 01:22:33 +03:00
|
|
|
Nothing,
|
|
|
|
};
|
2021-12-29 06:28:08 +03:00
|
|
|
QString filterStr = QLatin1String("");
|
2021-09-18 01:22:33 +03:00
|
|
|
FilterBy filterType = FilterBy::Nothing;
|
|
|
|
QStringList hiddenTags, hiddenSpaces;
|
2021-11-21 00:48:04 +03:00
|
|
|
bool hideDMs = false;
|
2023-06-19 02:38:40 +03:00
|
|
|
|
|
|
|
inline static FilteredRoomlistModel *instance_ = nullptr;
|
2021-05-19 20:34:10 +03:00
|
|
|
};
|