Merge pull request #1062 from Nheko-Reborn/perSpaceNotifs
Per-space notification bubbles
This commit is contained in:
commit
f62cb77680
13 changed files with 421 additions and 124 deletions
|
|
@ -88,7 +88,8 @@ UserSettings::load(std::optional<QString> profile)
|
|||
openImageExternal_ = settings.value(QStringLiteral("user/open_image_external"), false).toBool();
|
||||
openVideoExternal_ = settings.value(QStringLiteral("user/open_video_external"), false).toBool();
|
||||
decryptSidebar_ = settings.value(QStringLiteral("user/decrypt_sidebar"), true).toBool();
|
||||
privacyScreen_ = settings.value(QStringLiteral("user/privacy_screen"), false).toBool();
|
||||
spaceNotifications_ = settings.value(QStringLiteral("user/space_notifications"), true).toBool();
|
||||
privacyScreen_ = settings.value(QStringLiteral("user/privacy_screen"), false).toBool();
|
||||
privacyScreenTimeout_ =
|
||||
settings.value(QStringLiteral("user/privacy_screen_timeout"), 0).toInt();
|
||||
exposeDBusApi_ = settings.value(QStringLiteral("user/expose_dbus_api"), false).toBool();
|
||||
|
|
@ -132,7 +133,8 @@ UserSettings::load(std::optional<QString> profile)
|
|||
userId_ = settings.value(prefix + "auth/user_id", "").toString();
|
||||
deviceId_ = settings.value(prefix + "auth/device_id", "").toString();
|
||||
hiddenTags_ = settings.value(prefix + "user/hidden_tags", QStringList{}).toStringList();
|
||||
hiddenPins_ = settings.value(prefix + "user/hidden_pins", QStringList{}).toStringList();
|
||||
mutedTags_ = settings.value(prefix + "user/muted_tags", QStringList{"global"}).toStringList();
|
||||
hiddenPins_ = settings.value(prefix + "user/hidden_pins", QStringList{}).toStringList();
|
||||
hiddenWidgets_ = settings.value(prefix + "user/hidden_widgets", QStringList{}).toStringList();
|
||||
recentReactions_ =
|
||||
settings.value(prefix + "user/recent_reactions", QStringList{}).toStringList();
|
||||
|
|
@ -220,14 +222,21 @@ UserSettings::setGroupView(bool state)
|
|||
}
|
||||
|
||||
void
|
||||
UserSettings::setHiddenTags(QStringList hiddenTags)
|
||||
UserSettings::setHiddenTags(const QStringList &hiddenTags)
|
||||
{
|
||||
hiddenTags_ = hiddenTags;
|
||||
save();
|
||||
}
|
||||
|
||||
void
|
||||
UserSettings::setHiddenPins(QStringList hiddenTags)
|
||||
UserSettings::setMutedTags(const QStringList &mutedTags)
|
||||
{
|
||||
mutedTags_ = mutedTags;
|
||||
save();
|
||||
}
|
||||
|
||||
void
|
||||
UserSettings::setHiddenPins(const QStringList &hiddenTags)
|
||||
{
|
||||
hiddenPins_ = hiddenTags;
|
||||
save();
|
||||
|
|
@ -235,7 +244,7 @@ UserSettings::setHiddenPins(QStringList hiddenTags)
|
|||
}
|
||||
|
||||
void
|
||||
UserSettings::setHiddenWidgets(QStringList hiddenTags)
|
||||
UserSettings::setHiddenWidgets(const QStringList &hiddenTags)
|
||||
{
|
||||
hiddenWidgets_ = hiddenTags;
|
||||
save();
|
||||
|
|
@ -416,6 +425,16 @@ UserSettings::setDecryptSidebar(bool state)
|
|||
save();
|
||||
}
|
||||
|
||||
void
|
||||
UserSettings::setSpaceNotifications(bool state)
|
||||
{
|
||||
if (state == spaceNotifications_)
|
||||
return;
|
||||
spaceNotifications_ = state;
|
||||
emit spaceNotificationsChanged(state);
|
||||
save();
|
||||
}
|
||||
|
||||
void
|
||||
UserSettings::setPrivacyScreen(bool state)
|
||||
{
|
||||
|
|
@ -777,6 +796,7 @@ UserSettings::save()
|
|||
|
||||
settings.setValue(QStringLiteral("avatar_circles"), avatarCircles_);
|
||||
settings.setValue(QStringLiteral("decrypt_sidebar"), decryptSidebar_);
|
||||
settings.setValue(QStringLiteral("space_notifications"), spaceNotifications_);
|
||||
settings.setValue(QStringLiteral("privacy_screen"), privacyScreen_);
|
||||
settings.setValue(QStringLiteral("privacy_screen_timeout"), privacyScreenTimeout_);
|
||||
settings.setValue(QStringLiteral("mobile_mode"), mobileMode_);
|
||||
|
|
@ -830,6 +850,7 @@ UserSettings::save()
|
|||
onlyShareKeysWithVerifiedUsers_);
|
||||
settings.setValue(prefix + "user/online_key_backup", useOnlineKeyBackup_);
|
||||
settings.setValue(prefix + "user/hidden_tags", hiddenTags_);
|
||||
settings.setValue(prefix + "user/muted_tags", mutedTags_);
|
||||
settings.setValue(prefix + "user/hidden_pins", hiddenPins_);
|
||||
settings.setValue(prefix + "user/hidden_widgets", hiddenWidgets_);
|
||||
settings.setValue(prefix + "user/recent_reactions", recentReactions_);
|
||||
|
|
@ -923,6 +944,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
|||
return tr("Open videos with external program");
|
||||
case DecryptSidebar:
|
||||
return tr("Decrypt messages in sidebar");
|
||||
case SpaceNotifications:
|
||||
return tr("Show message counts for spaces");
|
||||
case PrivacyScreen:
|
||||
return tr("Privacy Screen");
|
||||
case PrivacyScreenTimeout:
|
||||
|
|
@ -1053,6 +1076,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
|||
return i->openVideoExternal();
|
||||
case DecryptSidebar:
|
||||
return i->decryptSidebar();
|
||||
case SpaceNotifications:
|
||||
return i->spaceNotifications();
|
||||
case PrivacyScreen:
|
||||
return i->privacyScreen();
|
||||
case PrivacyScreenTimeout:
|
||||
|
|
@ -1208,6 +1233,9 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
|||
case DecryptSidebar:
|
||||
return tr("Decrypt the messages shown in the sidebar.\nOnly affects messages in "
|
||||
"encrypted chats.");
|
||||
case SpaceNotifications:
|
||||
return tr(
|
||||
"Choose where to show the total number of notifications contained within a space.");
|
||||
case PrivacyScreen:
|
||||
return tr("When the window loses focus, the timeline will\nbe blurred.");
|
||||
case MobileMode:
|
||||
|
|
@ -1317,6 +1345,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
|||
case ShareKeysWithTrustedUsers:
|
||||
case UseOnlineKeyBackup:
|
||||
case ExposeDBusApi:
|
||||
case SpaceNotifications:
|
||||
return Toggle;
|
||||
case Profile:
|
||||
case UserId:
|
||||
|
|
@ -1409,7 +1438,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
|||
return fontDb.families();
|
||||
case EmojiFont:
|
||||
return fontDb.families(QFontDatabase::WritingSystem::Symbol);
|
||||
case Ringtone:
|
||||
case Ringtone: {
|
||||
QStringList l{
|
||||
QStringLiteral("Mute"),
|
||||
QStringLiteral("Default"),
|
||||
|
|
@ -1419,6 +1448,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
|||
l.push_back(i->ringtone());
|
||||
return l;
|
||||
}
|
||||
}
|
||||
} else if (role == Good) {
|
||||
switch (index.row()) {
|
||||
case OnlineBackupKey:
|
||||
|
|
@ -1624,6 +1654,13 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int
|
|||
return false;
|
||||
}
|
||||
return i->decryptSidebar();
|
||||
case SpaceNotifications: {
|
||||
if (value.userType() == QMetaType::Bool) {
|
||||
i->setSpaceNotifications(value.toBool());
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
case PrivacyScreen: {
|
||||
if (value.userType() == QMetaType::Bool) {
|
||||
i->setPrivacyScreen(value.toBool());
|
||||
|
|
@ -1936,7 +1973,9 @@ UserSettingsModel::UserSettingsModel(QObject *p)
|
|||
connect(s.get(), &UserSettings::decryptSidebarChanged, this, [this]() {
|
||||
emit dataChanged(index(DecryptSidebar), index(DecryptSidebar), {Value});
|
||||
});
|
||||
|
||||
connect(s.get(), &UserSettings::spaceNotificationsChanged, this, [this] {
|
||||
emit dataChanged(index(SpaceNotifications), index(SpaceNotifications), {Value});
|
||||
});
|
||||
connect(s.get(), &UserSettings::trayChanged, this, [this]() {
|
||||
emit dataChanged(index(Tray), index(Tray), {Value});
|
||||
emit dataChanged(index(StartInTray), index(StartInTray), {Enabled});
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ class UserSettings : public QObject
|
|||
bool avatarCircles READ avatarCircles WRITE setAvatarCircles NOTIFY avatarCirclesChanged)
|
||||
Q_PROPERTY(
|
||||
bool decryptSidebar READ decryptSidebar WRITE setDecryptSidebar NOTIFY decryptSidebarChanged)
|
||||
Q_PROPERTY(bool spaceNotifications READ spaceNotifications WRITE setSpaceNotifications NOTIFY
|
||||
spaceNotificationsChanged)
|
||||
Q_PROPERTY(
|
||||
bool privacyScreen READ privacyScreen WRITE setPrivacyScreen NOTIFY privacyScreenChanged)
|
||||
Q_PROPERTY(int privacyScreenTimeout READ privacyScreenTimeout WRITE setPrivacyScreenTimeout
|
||||
|
|
@ -162,6 +164,7 @@ public:
|
|||
void setAlertOnNotification(bool state);
|
||||
void setAvatarCircles(bool state);
|
||||
void setDecryptSidebar(bool state);
|
||||
void setSpaceNotifications(bool state);
|
||||
void setPrivacyScreen(bool state);
|
||||
void setPrivacyScreenTimeout(int state);
|
||||
void setPresence(Presence state);
|
||||
|
|
@ -184,9 +187,10 @@ public:
|
|||
void setDeviceId(QString deviceId);
|
||||
void setHomeserver(QString homeserver);
|
||||
void setDisableCertificateValidation(bool disabled);
|
||||
void setHiddenTags(QStringList hiddenTags);
|
||||
void setHiddenPins(QStringList hiddenTags);
|
||||
void setHiddenWidgets(QStringList hiddenTags);
|
||||
void setHiddenTags(const QStringList &hiddenTags);
|
||||
void setMutedTags(const QStringList &mutedTags);
|
||||
void setHiddenPins(const QStringList &hiddenTags);
|
||||
void setHiddenWidgets(const QStringList &hiddenTags);
|
||||
void setRecentReactions(QStringList recent);
|
||||
void setUseIdenticon(bool state);
|
||||
void setOpenImageExternal(bool state);
|
||||
|
|
@ -202,6 +206,7 @@ public:
|
|||
bool groupView() const { return groupView_; }
|
||||
bool avatarCircles() const { return avatarCircles_; }
|
||||
bool decryptSidebar() const { return decryptSidebar_; }
|
||||
bool spaceNotifications() const { return spaceNotifications_; }
|
||||
bool privacyScreen() const { return privacyScreen_; }
|
||||
int privacyScreenTimeout() const { return privacyScreenTimeout_; }
|
||||
bool markdown() const { return markdown_; }
|
||||
|
|
@ -250,6 +255,7 @@ public:
|
|||
QString homeserver() const { return homeserver_; }
|
||||
bool disableCertificateValidation() const { return disableCertificateValidation_; }
|
||||
QStringList hiddenTags() const { return hiddenTags_; }
|
||||
QStringList mutedTags() const { return mutedTags_; }
|
||||
QStringList hiddenPins() const { return hiddenPins_; }
|
||||
QStringList hiddenWidgets() const { return hiddenWidgets_; }
|
||||
QStringList recentReactions() const { return recentReactions_; }
|
||||
|
|
@ -278,6 +284,7 @@ signals:
|
|||
void alertOnNotificationChanged(bool state);
|
||||
void avatarCirclesChanged(bool state);
|
||||
void decryptSidebarChanged(bool state);
|
||||
void spaceNotificationsChanged(bool state);
|
||||
void privacyScreenChanged(bool state);
|
||||
void privacyScreenTimeoutChanged(int state);
|
||||
void timelineMaxWidthChanged(int state);
|
||||
|
|
@ -340,6 +347,7 @@ private:
|
|||
bool hasAlertOnNotification_;
|
||||
bool avatarCircles_;
|
||||
bool decryptSidebar_;
|
||||
bool spaceNotifications_;
|
||||
bool privacyScreen_;
|
||||
int privacyScreenTimeout_;
|
||||
bool shareKeysWithTrustedUsers_;
|
||||
|
|
@ -370,6 +378,7 @@ private:
|
|||
QString deviceId_;
|
||||
QString homeserver_;
|
||||
QStringList hiddenTags_;
|
||||
QStringList mutedTags_;
|
||||
QStringList hiddenPins_;
|
||||
QStringList hiddenWidgets_;
|
||||
QStringList recentReactions_;
|
||||
|
|
@ -424,6 +433,7 @@ class UserSettingsModel : public QAbstractListModel
|
|||
GroupView,
|
||||
SortByImportance,
|
||||
DecryptSidebar,
|
||||
SpaceNotifications,
|
||||
|
||||
TraySection,
|
||||
Tray,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <cmark.h>
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Cache_p.h"
|
||||
#include "Config.h"
|
||||
#include "EventAccessors.h"
|
||||
#include "Logging.h"
|
||||
|
|
|
|||
|
|
@ -9,11 +9,15 @@
|
|||
|
||||
#include "Cache.h"
|
||||
#include "Cache_p.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Logging.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "Utils.h"
|
||||
|
||||
CommunitiesModel::CommunitiesModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, hiddenTagIds_{UserSettings::instance()->hiddenTags()}
|
||||
, mutedTagIds_{UserSettings::instance()->mutedTags()}
|
||||
{}
|
||||
|
||||
QHash<int, QByteArray>
|
||||
|
|
@ -28,6 +32,9 @@ CommunitiesModel::roleNames() const
|
|||
{Hidden, "hidden"},
|
||||
{Depth, "depth"},
|
||||
{Id, "id"},
|
||||
{UnreadMessages, "unreadMessages"},
|
||||
{HasLoudNotification, "hasLoudNotification"},
|
||||
{Muted, "muted"},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -50,6 +57,13 @@ CommunitiesModel::setData(const QModelIndex &index, const QVariant &value, int r
|
|||
QVariant
|
||||
CommunitiesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == CommunitiesModel::Roles::Muted) {
|
||||
if (index.row() == 0)
|
||||
return mutedTagIds_.contains(QStringLiteral("global"));
|
||||
else
|
||||
return mutedTagIds_.contains(data(index, CommunitiesModel::Roles::Id).toString());
|
||||
}
|
||||
|
||||
if (index.row() == 0) {
|
||||
switch (role) {
|
||||
case CommunitiesModel::Roles::AvatarUrl:
|
||||
|
|
@ -70,6 +84,10 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
return 0;
|
||||
case CommunitiesModel::Roles::Id:
|
||||
return "";
|
||||
case CommunitiesModel::Roles::UnreadMessages:
|
||||
return (int)globalUnreads.notification_count;
|
||||
case CommunitiesModel::Roles::HasLoudNotification:
|
||||
return globalUnreads.highlight_count > 0;
|
||||
}
|
||||
} else if (index.row() == 1) {
|
||||
switch (role) {
|
||||
|
|
@ -84,16 +102,20 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
case CommunitiesModel::Roles::Collapsible:
|
||||
return false;
|
||||
case CommunitiesModel::Roles::Hidden:
|
||||
return hiddentTagIds_.contains(QStringLiteral("dm"));
|
||||
return hiddenTagIds_.contains(QStringLiteral("dm"));
|
||||
case CommunitiesModel::Roles::Parent:
|
||||
return "";
|
||||
case CommunitiesModel::Roles::Depth:
|
||||
return 0;
|
||||
case CommunitiesModel::Roles::Id:
|
||||
return "dm";
|
||||
case CommunitiesModel::Roles::UnreadMessages:
|
||||
return (int)dmUnreads.notification_count;
|
||||
case CommunitiesModel::Roles::HasLoudNotification:
|
||||
return dmUnreads.highlight_count > 0;
|
||||
}
|
||||
} else if (index.row() - 2 < spaceOrder_.size()) {
|
||||
auto id = spaceOrder_.tree.at(index.row() - 2).name;
|
||||
auto id = spaceOrder_.tree.at(index.row() - 2).id;
|
||||
switch (role) {
|
||||
case CommunitiesModel::Roles::AvatarUrl:
|
||||
return QString::fromStdString(spaces_.at(id).avatar_url);
|
||||
|
|
@ -107,10 +129,10 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
return idx != spaceOrder_.lastChild(idx);
|
||||
}
|
||||
case CommunitiesModel::Roles::Hidden:
|
||||
return hiddentTagIds_.contains("space:" + id);
|
||||
return hiddenTagIds_.contains("space:" + id);
|
||||
case CommunitiesModel::Roles::Parent: {
|
||||
if (auto p = spaceOrder_.parent(index.row() - 2); p >= 0)
|
||||
return spaceOrder_.tree[p].name;
|
||||
return spaceOrder_.tree[p].id;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
|
@ -118,6 +140,20 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
return spaceOrder_.tree.at(index.row() - 2).depth;
|
||||
case CommunitiesModel::Roles::Id:
|
||||
return "space:" + id;
|
||||
case CommunitiesModel::Roles::UnreadMessages: {
|
||||
int count = 0;
|
||||
auto end = spaceOrder_.lastChild(index.row() - 2);
|
||||
for (int i = index.row() - 2; i <= end; i++)
|
||||
count += spaceOrder_.tree[i].notificationCounts.notification_count;
|
||||
return count;
|
||||
}
|
||||
case CommunitiesModel::Roles::HasLoudNotification: {
|
||||
auto end = spaceOrder_.lastChild(index.row() - 2);
|
||||
for (int i = index.row() - 2; i <= end; i++)
|
||||
if (spaceOrder_.tree[i].notificationCounts.highlight_count > 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (index.row() - 2 < tags_.size() + spaceOrder_.size()) {
|
||||
auto tag = tags_.at(index.row() - 2 - spaceOrder_.size());
|
||||
|
|
@ -160,7 +196,7 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
|
||||
switch (role) {
|
||||
case CommunitiesModel::Roles::Hidden:
|
||||
return hiddentTagIds_.contains("tag:" + tag);
|
||||
return hiddenTagIds_.contains("tag:" + tag);
|
||||
case CommunitiesModel::Roles::Collapsed:
|
||||
return true;
|
||||
case CommunitiesModel::Roles::Collapsible:
|
||||
|
|
@ -171,6 +207,16 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
return 0;
|
||||
case CommunitiesModel::Roles::Id:
|
||||
return "tag:" + tag;
|
||||
case CommunitiesModel::Roles::UnreadMessages:
|
||||
if (auto it = tagNotificationCache.find(tag); it != tagNotificationCache.end())
|
||||
return (int)it->second.notification_count;
|
||||
else
|
||||
return 0;
|
||||
case CommunitiesModel::Roles::HasLoudNotification:
|
||||
if (auto it = tagNotificationCache.find(tag); it != tagNotificationCache.end())
|
||||
return it->second.highlight_count > 0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
|
|
@ -225,6 +271,21 @@ CommunitiesModel::initializeSidebar()
|
|||
tags_.clear();
|
||||
spaceOrder_.tree.clear();
|
||||
spaces_.clear();
|
||||
tagNotificationCache.clear();
|
||||
globalUnreads.notification_count = {};
|
||||
dmUnreads.notification_count = {};
|
||||
|
||||
auto e = cache::client()->getAccountData(mtx::events::EventType::Direct);
|
||||
if (e) {
|
||||
if (auto event =
|
||||
std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(
|
||||
&e.value())) {
|
||||
directMessages_.clear();
|
||||
for (const auto &[userId, roomIds] : event->content.user_to_rooms)
|
||||
for (const auto &roomId : roomIds)
|
||||
directMessages_.push_back(roomId);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::string> ts;
|
||||
|
||||
|
|
@ -244,6 +305,19 @@ CommunitiesModel::initializeSidebar()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &t : it->tags) {
|
||||
auto tagId = QString::fromStdString(t);
|
||||
auto &tNs = tagNotificationCache[tagId];
|
||||
tNs.notification_count += it->notification_count;
|
||||
tNs.highlight_count += it->highlight_count;
|
||||
}
|
||||
|
||||
auto &e = roomNotificationCache[it.key()];
|
||||
e.highlight_count = it->highlight_count;
|
||||
e.notification_count = it->notification_count;
|
||||
globalUnreads.notification_count += it->notification_count;
|
||||
globalUnreads.highlight_count += it->highlight_count;
|
||||
}
|
||||
|
||||
// NOTE(Nico): We build a forrest from the Directed Cyclic(!) Graph of spaces. To do that we
|
||||
|
|
@ -277,8 +351,16 @@ CommunitiesModel::initializeSidebar()
|
|||
for (const auto &t : ts)
|
||||
tags_.push_back(QString::fromStdString(t));
|
||||
|
||||
hiddentTagIds_ = UserSettings::instance()->hiddenTags();
|
||||
spaceOrder_.restoreCollapsed();
|
||||
|
||||
for (auto &space : spaceOrder_.tree) {
|
||||
for (const auto &c : cache::client()->getChildRoomIds(space.id.toStdString())) {
|
||||
const auto &counts = roomNotificationCache[QString::fromStdString(c)];
|
||||
space.notificationCounts.highlight_count += counts.highlight_count;
|
||||
space.notificationCounts.notification_count += counts.notification_count;
|
||||
}
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
|
||||
emit tagsChanged();
|
||||
|
|
@ -298,12 +380,12 @@ CommunitiesModel::FlatTree::storeCollapsed()
|
|||
|
||||
for (const auto &e : tree) {
|
||||
if (e.depth > depth) {
|
||||
current.push_back(e.name);
|
||||
current.push_back(e.id);
|
||||
} else if (e.depth == depth) {
|
||||
current.back() = e.name;
|
||||
current.back() = e.id;
|
||||
} else {
|
||||
current.pop_back();
|
||||
current.back() = e.name;
|
||||
current.back() = e.id;
|
||||
}
|
||||
|
||||
if (e.collapsed)
|
||||
|
|
@ -323,12 +405,12 @@ CommunitiesModel::FlatTree::restoreCollapsed()
|
|||
|
||||
for (auto &e : tree) {
|
||||
if (e.depth > depth) {
|
||||
current.push_back(e.name);
|
||||
current.push_back(e.id);
|
||||
} else if (e.depth == depth) {
|
||||
current.back() = e.name;
|
||||
current.back() = e.id;
|
||||
} else {
|
||||
current.pop_back();
|
||||
current.back() = e.name;
|
||||
current.back() = e.id;
|
||||
}
|
||||
|
||||
if (elements.contains(current))
|
||||
|
|
@ -353,7 +435,6 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
|
|||
bool tagsUpdated = false;
|
||||
|
||||
for (const auto &[roomid, room] : sync_.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)) {
|
||||
|
|
@ -373,6 +454,78 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
|
|||
e)) {
|
||||
tagsUpdated = true;
|
||||
}
|
||||
|
||||
auto roomId = QString::fromStdString(roomid);
|
||||
auto &oldUnreads = roomNotificationCache[roomId];
|
||||
auto notificationCDiff = -static_cast<int64_t>(oldUnreads.notification_count) +
|
||||
static_cast<int64_t>(room.unread_notifications.notification_count);
|
||||
auto highlightCDiff = -static_cast<int64_t>(oldUnreads.highlight_count) +
|
||||
static_cast<int64_t>(room.unread_notifications.highlight_count);
|
||||
|
||||
auto applyDiff = [notificationCDiff,
|
||||
highlightCDiff](mtx::responses::UnreadNotifications &n) {
|
||||
n.highlight_count = static_cast<int64_t>(n.highlight_count) + highlightCDiff;
|
||||
n.notification_count = static_cast<int64_t>(n.notification_count) + notificationCDiff;
|
||||
};
|
||||
if (highlightCDiff || notificationCDiff) {
|
||||
// bool hidden = hiddenTagIds_.contains(roomId);
|
||||
applyDiff(globalUnreads);
|
||||
emit dataChanged(index(0),
|
||||
index(0),
|
||||
{
|
||||
UnreadMessages,
|
||||
HasLoudNotification,
|
||||
});
|
||||
if (std::find(begin(directMessages_), end(directMessages_), roomid) !=
|
||||
end(directMessages_)) {
|
||||
applyDiff(dmUnreads);
|
||||
emit dataChanged(index(1),
|
||||
index(1),
|
||||
{
|
||||
UnreadMessages,
|
||||
HasLoudNotification,
|
||||
});
|
||||
}
|
||||
|
||||
auto spaces = cache::client()->getParentRoomIds(roomid);
|
||||
auto tags = cache::singleRoomInfo(roomid).tags;
|
||||
|
||||
for (const auto &t : tags) {
|
||||
auto tagId = QString::fromStdString(t);
|
||||
applyDiff(tagNotificationCache[tagId]);
|
||||
int idx = tags_.indexOf(tagId) + 2 + spaceOrder_.size();
|
||||
emit dataChanged(index(idx),
|
||||
index(idx),
|
||||
{
|
||||
UnreadMessages,
|
||||
HasLoudNotification,
|
||||
});
|
||||
}
|
||||
|
||||
for (const auto &s : spaces) {
|
||||
auto spaceId = QString::fromStdString(s);
|
||||
|
||||
for (int i = 0; i < spaceOrder_.size(); i++) {
|
||||
if (spaceOrder_.tree[i].id != spaceId)
|
||||
continue;
|
||||
|
||||
applyDiff(spaceOrder_.tree[i].notificationCounts);
|
||||
|
||||
int idx = i;
|
||||
do {
|
||||
emit dataChanged(index(idx + 2),
|
||||
index(idx + 2),
|
||||
{
|
||||
UnreadMessages,
|
||||
HasLoudNotification,
|
||||
});
|
||||
idx = spaceOrder_.parent(idx);
|
||||
} while (idx != -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
roomNotificationCache[roomId] = room.unread_notifications;
|
||||
}
|
||||
for (const auto &[roomid, room] : sync_.rooms.leave) {
|
||||
(void)room;
|
||||
|
|
@ -380,8 +533,12 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
|
|||
tagsUpdated = true;
|
||||
}
|
||||
for (const auto &e : sync_.account_data.events) {
|
||||
if (std::holds_alternative<
|
||||
mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(e)) {
|
||||
if (auto event =
|
||||
std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(&e)) {
|
||||
directMessages_.clear();
|
||||
for (const auto &[userId, roomIds] : event->content.user_to_rooms)
|
||||
for (const auto &roomId : roomIds)
|
||||
directMessages_.push_back(roomId);
|
||||
tagsUpdated = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -392,7 +549,7 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
|
|||
}
|
||||
|
||||
void
|
||||
CommunitiesModel::setCurrentTagId(QString tagId)
|
||||
CommunitiesModel::setCurrentTagId(const QString &tagId)
|
||||
{
|
||||
if (tagId.startsWith(QLatin1String("tag:"))) {
|
||||
auto tag = tagId.mid(4);
|
||||
|
|
@ -406,7 +563,7 @@ CommunitiesModel::setCurrentTagId(QString tagId)
|
|||
} else if (tagId.startsWith(QLatin1String("space:"))) {
|
||||
auto tag = tagId.mid(6);
|
||||
for (const auto &t : spaceOrder_.tree) {
|
||||
if (t.name == tag) {
|
||||
if (t.id == tag) {
|
||||
this->currentTagId_ = tagId;
|
||||
emit currentTagIdChanged(currentTagId_);
|
||||
return;
|
||||
|
|
@ -425,13 +582,11 @@ CommunitiesModel::setCurrentTagId(QString tagId)
|
|||
void
|
||||
CommunitiesModel::toggleTagId(QString tagId)
|
||||
{
|
||||
if (hiddentTagIds_.contains(tagId)) {
|
||||
hiddentTagIds_.removeOne(tagId);
|
||||
UserSettings::instance()->setHiddenTags(hiddentTagIds_);
|
||||
} else {
|
||||
hiddentTagIds_.push_back(tagId);
|
||||
UserSettings::instance()->setHiddenTags(hiddentTagIds_);
|
||||
}
|
||||
if (hiddenTagIds_.contains(tagId))
|
||||
hiddenTagIds_.removeOne(tagId);
|
||||
else
|
||||
hiddenTagIds_.push_back(tagId);
|
||||
UserSettings::instance()->setHiddenTags(hiddenTagIds_);
|
||||
|
||||
if (tagId.startsWith(QLatin1String("tag:"))) {
|
||||
auto idx = tags_.indexOf(tagId.mid(4));
|
||||
|
|
@ -449,6 +604,34 @@ CommunitiesModel::toggleTagId(QString tagId)
|
|||
emit hiddenTagsChanged();
|
||||
}
|
||||
|
||||
void
|
||||
CommunitiesModel::toggleTagMute(QString tagId)
|
||||
{
|
||||
if (tagId.isEmpty())
|
||||
tagId = QStringLiteral("global");
|
||||
|
||||
if (mutedTagIds_.contains(tagId))
|
||||
mutedTagIds_.removeOne(tagId);
|
||||
else
|
||||
mutedTagIds_.push_back(tagId);
|
||||
UserSettings::instance()->setMutedTags(mutedTagIds_);
|
||||
|
||||
if (tagId.startsWith(QLatin1String("tag:"))) {
|
||||
auto idx = tags_.indexOf(tagId.mid(4));
|
||||
if (idx != -1)
|
||||
emit dataChanged(index(idx + 1 + spaceOrder_.size()),
|
||||
index(idx + 1 + spaceOrder_.size()));
|
||||
} else if (tagId.startsWith(QLatin1String("space:"))) {
|
||||
auto idx = spaceOrder_.indexOf(tagId.mid(6));
|
||||
if (idx != -1)
|
||||
emit dataChanged(index(idx + 1), index(idx + 1));
|
||||
} else if (tagId == QLatin1String("dm")) {
|
||||
emit dataChanged(index(1), index(1));
|
||||
} else if (tagId == QLatin1String("global")) {
|
||||
emit dataChanged(index(0), index(0));
|
||||
}
|
||||
}
|
||||
|
||||
FilteredCommunitiesModel::FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class FilteredCommunitiesModel : public QSortFilterProxyModel
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr);
|
||||
explicit FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr);
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override;
|
||||
};
|
||||
|
|
@ -48,14 +48,21 @@ public:
|
|||
Parent,
|
||||
Depth,
|
||||
Id,
|
||||
UnreadMessages,
|
||||
HasLoudNotification,
|
||||
Muted,
|
||||
IsDirect,
|
||||
};
|
||||
|
||||
struct FlatTree
|
||||
{
|
||||
struct Elem
|
||||
{
|
||||
QString name;
|
||||
int depth = 0;
|
||||
QString id;
|
||||
int depth = 0;
|
||||
|
||||
mtx::responses::UnreadNotifications notificationCounts = {0, 0};
|
||||
|
||||
bool collapsed = false;
|
||||
};
|
||||
|
||||
|
|
@ -65,7 +72,7 @@ public:
|
|||
int indexOf(const QString &s) const
|
||||
{
|
||||
for (int i = 0; i < size(); i++)
|
||||
if (tree[i].name == s)
|
||||
if (tree[i].id == s)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -121,7 +128,7 @@ public slots:
|
|||
void sync(const mtx::responses::Sync &sync_);
|
||||
void clear();
|
||||
QString currentTagId() const { return currentTagId_; }
|
||||
void setCurrentTagId(QString tagId);
|
||||
void setCurrentTagId(const QString &tagId);
|
||||
void resetCurrentTagId()
|
||||
{
|
||||
currentTagId_.clear();
|
||||
|
|
@ -138,6 +145,7 @@ public slots:
|
|||
return tagsWD;
|
||||
}
|
||||
void toggleTagId(QString tagId);
|
||||
void toggleTagMute(QString tagId);
|
||||
FilteredCommunitiesModel *filtered() { return new FilteredCommunitiesModel(this, this); }
|
||||
|
||||
signals:
|
||||
|
|
@ -149,9 +157,16 @@ signals:
|
|||
private:
|
||||
QStringList tags_;
|
||||
QString currentTagId_;
|
||||
QStringList hiddentTagIds_;
|
||||
QStringList hiddenTagIds_;
|
||||
QStringList mutedTagIds_;
|
||||
FlatTree spaceOrder_;
|
||||
std::map<QString, RoomInfo> spaces_;
|
||||
std::vector<std::string> directMessages_;
|
||||
|
||||
std::unordered_map<QString, mtx::responses::UnreadNotifications> roomNotificationCache;
|
||||
std::unordered_map<QString, mtx::responses::UnreadNotifications> tagNotificationCache;
|
||||
mtx::responses::UnreadNotifications globalUnreads{};
|
||||
mtx::responses::UnreadNotifications dmUnreads{};
|
||||
|
||||
friend class FilteredCommunitiesModel;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -330,10 +330,13 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
|
|||
Qt::DisplayRole,
|
||||
});
|
||||
|
||||
if (getRoomById(room_id)->isSpace())
|
||||
return; // no need to update space notifications
|
||||
|
||||
int total_unread_msgs = 0;
|
||||
|
||||
for (const auto &room : qAsConst(models)) {
|
||||
if (!room.isNull())
|
||||
if (!room.isNull() && !room->isSpace())
|
||||
total_unread_msgs += room->notificationCount();
|
||||
}
|
||||
|
||||
|
|
@ -639,15 +642,18 @@ RoomlistModel::clear()
|
|||
}
|
||||
|
||||
void
|
||||
RoomlistModel::joinPreview(QString roomid, QString parentSpace)
|
||||
RoomlistModel::joinPreview(QString roomid)
|
||||
{
|
||||
if (previewedRooms.contains(roomid)) {
|
||||
auto child = cache::client()->getStateEvent<mtx::events::state::space::Child>(
|
||||
parentSpace.toStdString(), roomid.toStdString());
|
||||
ChatPage::instance()->joinRoomVia(
|
||||
roomid.toStdString(),
|
||||
(child && child->content.via) ? child->content.via.value() : std::vector<std::string>{},
|
||||
false);
|
||||
std::vector<std::string> vias;
|
||||
auto parents = cache::client()->getParentRoomIds(roomid.toStdString());
|
||||
for (const auto &p : parents) {
|
||||
auto child = cache::client()->getStateEvent<mtx::events::state::space::Child>(
|
||||
p, roomid.toStdString());
|
||||
if (child && child->content.via)
|
||||
vias.insert(vias.end(), child->content.via->begin(), child->content.via->end());
|
||||
}
|
||||
ChatPage::instance()->joinRoomVia(roomid.toStdString(), vias, false);
|
||||
}
|
||||
}
|
||||
void
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ public slots:
|
|||
|
||||
return -1;
|
||||
}
|
||||
void joinPreview(QString roomid, QString parentSpace);
|
||||
void joinPreview(QString roomid);
|
||||
void acceptInvite(QString roomid);
|
||||
void declineInvite(QString roomid);
|
||||
void leave(QString roomid, QString reason = "");
|
||||
|
|
@ -169,11 +169,7 @@ public slots:
|
|||
{
|
||||
return mapFromSource(roomlistmodel->index(roomlistmodel->roomidToIndex(roomid))).row();
|
||||
}
|
||||
void joinPreview(QString roomid)
|
||||
{
|
||||
roomlistmodel->joinPreview(roomid,
|
||||
filterType == FilterBy::Space ? filterStr : QLatin1String(""));
|
||||
}
|
||||
void joinPreview(QString roomid) { roomlistmodel->joinPreview(roomid); }
|
||||
void acceptInvite(QString roomid) { roomlistmodel->acceptInvite(roomid); }
|
||||
void declineInvite(QString roomid) { roomlistmodel->declineInvite(roomid); }
|
||||
void leave(QString roomid, QString reason = "") { roomlistmodel->leave(roomid, reason); }
|
||||
|
|
|
|||
|
|
@ -370,10 +370,6 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
|
|||
this->highlight_count = roomInfo.highlight_count;
|
||||
lastMessage_.timestamp = roomInfo.approximate_last_modification_ts;
|
||||
|
||||
// this connection will simplify adding the plainRoomNameChanged() signal everywhere that it
|
||||
// needs to be
|
||||
connect(this, &TimelineModel::roomNameChanged, this, &TimelineModel::plainRoomNameChanged);
|
||||
|
||||
connect(
|
||||
this,
|
||||
&TimelineModel::redactionFailed,
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class TimelineModel : public QAbstractListModel
|
|||
bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged)
|
||||
Q_PROPERTY(QString roomId READ roomId CONSTANT)
|
||||
Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
|
||||
Q_PROPERTY(QString plainRoomName READ plainRoomName NOTIFY plainRoomNameChanged)
|
||||
Q_PROPERTY(QString plainRoomName READ plainRoomName NOTIFY roomNameChanged)
|
||||
Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged)
|
||||
Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged)
|
||||
Q_PROPERTY(QStringList pinnedMessages READ pinnedMessages NOTIFY pinnedMessagesChanged)
|
||||
|
|
@ -429,7 +429,6 @@ signals:
|
|||
void encryptionChanged();
|
||||
void trustlevelChanged();
|
||||
void roomNameChanged();
|
||||
void plainRoomNameChanged();
|
||||
void roomTopicChanged();
|
||||
void pinnedMessagesChanged();
|
||||
void widgetLinksChanged();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue