diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp
new file mode 100644
index 00000000..cedaacce
--- /dev/null
+++ b/src/timeline/CommunitiesModel.cpp
@@ -0,0 +1,158 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "CommunitiesModel.h"
+
+#include <set>
+
+#include "Cache.h"
+#include "UserSettingsPage.h"
+
+CommunitiesModel::CommunitiesModel(QObject *parent)
+ : QAbstractListModel(parent)
+{}
+
+QHash<int, QByteArray>
+CommunitiesModel::roleNames() const
+{
+ return {
+ {AvatarUrl, "avatarUrl"},
+ {DisplayName, "displayName"},
+ {Tooltip, "tooltip"},
+ {ChildrenHidden, "childrenHidden"},
+ };
+}
+
+QVariant
+CommunitiesModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() == 0) {
+ switch (role) {
+ case CommunitiesModel::Roles::AvatarUrl:
+ return QString(":/icons/icons/ui/world.png");
+ case CommunitiesModel::Roles::DisplayName:
+ return tr("All rooms");
+ case CommunitiesModel::Roles::Tooltip:
+ return tr("Shows all rooms without filtering.");
+ case CommunitiesModel::Roles::ChildrenHidden:
+ return false;
+ case CommunitiesModel::Roles::Id:
+ return "";
+ }
+ } else if (index.row() - 1 < tags_.size()) {
+ auto tag = tags_.at(index.row() - 1);
+ if (tag == "m.favourite") {
+ switch (role) {
+ case CommunitiesModel::Roles::AvatarUrl:
+ return QString(":/icons/icons/ui/star.png");
+ case CommunitiesModel::Roles::DisplayName:
+ return tr("Favourites");
+ case CommunitiesModel::Roles::Tooltip:
+ return tr("Rooms you have favourited.");
+ }
+ } else if (tag == "m.lowpriority") {
+ switch (role) {
+ case CommunitiesModel::Roles::AvatarUrl:
+ return QString(":/icons/icons/ui/star.png");
+ case CommunitiesModel::Roles::DisplayName:
+ return tr("Low Priority");
+ case CommunitiesModel::Roles::Tooltip:
+ return tr("Rooms with low priority.");
+ }
+ } else if (tag == "m.server_notice") {
+ switch (role) {
+ case CommunitiesModel::Roles::AvatarUrl:
+ return QString(":/icons/icons/ui/tag.png");
+ case CommunitiesModel::Roles::DisplayName:
+ return tr("Server Notices");
+ case CommunitiesModel::Roles::Tooltip:
+ return tr("Messages from your server or administrator.");
+ }
+ } else {
+ switch (role) {
+ case CommunitiesModel::Roles::AvatarUrl:
+ return QString(":/icons/icons/ui/tag.png");
+ case CommunitiesModel::Roles::DisplayName:
+ return tag.right(2);
+ case CommunitiesModel::Roles::Tooltip:
+ return tag.right(2);
+ }
+ }
+
+ switch (role) {
+ case CommunitiesModel::Roles::ChildrenHidden:
+ return UserSettings::instance()->hiddenTags().contains("tag:" + tag);
+ case CommunitiesModel::Roles::Id:
+ return "tag:" + tag;
+ }
+ }
+ return QVariant();
+}
+
+void
+CommunitiesModel::initializeSidebar()
+{
+ std::set<std::string> ts;
+ for (const auto &e : cache::roomInfo()) {
+ for (const auto &t : e.tags) {
+ if (t.find("u.") == 0 || t.find("m." == 0)) {
+ ts.insert(t);
+ }
+ }
+ }
+
+ beginResetModel();
+ tags_.clear();
+ for (const auto &t : ts)
+ tags_.push_back(QString::fromStdString(t));
+ endResetModel();
+
+ emit tagsChanged();
+}
+
+void
+CommunitiesModel::clear()
+{
+ beginResetModel();
+ tags_.clear();
+ endResetModel();
+
+ emit tagsChanged();
+}
+
+void
+CommunitiesModel::sync(const mtx::responses::Rooms &rooms)
+{
+ bool tagsUpdated = false;
+
+ for (const auto &[roomid, room] : rooms.join) {
+ (void)roomid;
+ for (const auto &e : room.account_data.events)
+ if (std::holds_alternative<
+ mtx::events::AccountDataEvent<mtx::events::account_data::Tags>>(e)) {
+ tagsUpdated = true;
+ }
+ }
+
+ if (tagsUpdated)
+ initializeSidebar();
+}
+
+void
+CommunitiesModel::setCurrentTagId(QString tagId)
+{
+ if (tagId.startsWith("tag:")) {
+ auto tag = tagId.remove(0, 4);
+ for (const auto &t : tags_) {
+ if (t == tag) {
+ this->currentTagId_ = tagId;
+ emit currentTagIdChanged();
+ return;
+ }
+ }
+ }
+
+ this->currentTagId_ = "";
+ emit currentTagIdChanged();
+}
diff --git a/src/timeline/CommunitiesModel.h b/src/timeline/CommunitiesModel.h
new file mode 100644
index 00000000..3f6a2a4c
--- /dev/null
+++ b/src/timeline/CommunitiesModel.h
@@ -0,0 +1,60 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <QAbstractListModel>
+#include <QHash>
+#include <QString>
+#include <QStringList>
+
+#include <mtx/responses/sync.hpp>
+
+class CommunitiesModel : public QAbstractListModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QString currentTagId READ currentTagId WRITE setCurrentTagId NOTIFY
+ currentTagIdChanged RESET resetCurrentTagId)
+ Q_PROPERTY(QStringList tags READ tags NOTIFY tagsChanged)
+
+public:
+ enum Roles
+ {
+ AvatarUrl = Qt::UserRole,
+ DisplayName,
+ Tooltip,
+ ChildrenHidden,
+ Id,
+ };
+
+ CommunitiesModel(QObject *parent = nullptr);
+ QHash<int, QByteArray> roleNames() const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override
+ {
+ (void)parent;
+ return 1 + tags_.size();
+ }
+ QVariant data(const QModelIndex &index, int role) const override;
+
+public slots:
+ void initializeSidebar();
+ void sync(const mtx::responses::Rooms &rooms);
+ void clear();
+ QString currentTagId() const { return currentTagId_; }
+ void setCurrentTagId(QString tagId);
+ void resetCurrentTagId()
+ {
+ currentTagId_.clear();
+ emit currentTagIdChanged();
+ }
+ QStringList tags() const { return tags_; }
+
+signals:
+ void currentTagIdChanged();
+ void tagsChanged();
+
+private:
+ QStringList tags_;
+ QString currentTagId_;
+};
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index 283224f1..4dd44b30 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -485,29 +485,6 @@ FilteredRoomlistModel::FilteredRoomlistModel(RoomlistModel *model, QObject *pare
sort(0);
}
-QStringList
-FilteredRoomlistModel::tags()
-{
- std::set<std::string> ts;
- for (const auto &e : cache::roomInfo()) {
- for (const auto &t : e.tags) {
- if (t.find("u.") == 0) {
- ts.insert(t);
- }
- }
- }
-
- QStringList ret{{
- "m.favourite",
- "m.lowpriority",
- }};
-
- for (const auto &t : ts)
- ret.push_back(QString::fromStdString(t));
-
- return ret;
-}
-
void
FilteredRoomlistModel::toggleTag(QString roomid, QString tag, bool on)
{
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index fa991f6b..7ee0419f 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -119,7 +119,6 @@ public slots:
void acceptInvite(QString roomid) { roomlistmodel->acceptInvite(roomid); }
void declineInvite(QString roomid) { roomlistmodel->declineInvite(roomid); }
void leave(QString roomid) { roomlistmodel->leave(roomid); }
- QStringList tags();
void toggleTag(QString roomid, QString tag, bool on);
TimelineModel *currentRoom() const { return roomlistmodel->currentRoom(); }
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index dd623f2f..faf56b85 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -135,6 +135,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
, blurhashProvider(new BlurhashProvider())
, callManager_(callManager)
, rooms_(new RoomlistModel(this))
+ , communities_(new CommunitiesModel(this))
{
qRegisterMetaType<mtx::events::msg::KeyVerificationAccept>();
qRegisterMetaType<mtx::events::msg::KeyVerificationCancel>();
@@ -196,6 +197,12 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
return new FilteredRoomlistModel(self->rooms_);
});
+ qmlRegisterSingletonType<RoomlistModel>(
+ "im.nheko", 1, 0, "Communities", [](QQmlEngine *, QJSEngine *) -> QObject * {
+ auto ptr = self->communities_;
+ QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
+ return ptr;
+ });
qmlRegisterSingletonType<UserSettings>(
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
auto ptr = ChatPage::instance()->userSettings().data();
@@ -324,6 +331,7 @@ void
TimelineViewManager::sync(const mtx::responses::Rooms &rooms_res)
{
this->rooms_->sync(rooms_res);
+ this->communities_->sync(rooms_res);
if (isInitialSync_) {
this->isInitialSync_ = false;
@@ -486,6 +494,7 @@ void
TimelineViewManager::initializeRoomlist()
{
rooms_->initializeRooms();
+ communities_->initializeSidebar();
}
void
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 68d9cd1b..556bcf4c 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -22,6 +22,7 @@
#include "WebRTCSession.h"
#include "emoji/EmojiModel.h"
#include "emoji/Provider.h"
+#include "timeline/CommunitiesModel.h"
#include "timeline/RoomlistModel.h"
class MxcImageProvider;
@@ -131,7 +132,8 @@ private:
bool isInitialSync_ = true;
bool isWindowFocused_ = false;
- RoomlistModel *rooms_ = nullptr;
+ RoomlistModel *rooms_ = nullptr;
+ CommunitiesModel *communities_ = nullptr;
QHash<QString, QColor> userColors;
|