Add Global Notification Settings
This add the final list of settings in the main setting window as a new page notifications as there are quite a few now. This completes previous work on push rules giving the ability to set the default global rules. Adding keyword rules is also now supported. This also uses the new mobileform layout. The settings are designed to give some visual feedback as options for whether notifications are on/off, play a sound or are highlighted are chosen. The left icon is designed to mimic the notification dot in the roomlist. The whole mobileform delegate can also be clicked to cycle through the available options. The rationale for whether an option is available is as follows: - Highlight is not available if would lead to every message in a room being highlighted - Keyword notifications cannot be switched off instead the rule is just deleted - Only keyword rules can be deleted, default rules cannot be touched There is also rules plumbed in for features that don't exist in neochat yet, i.e. encrypted chats and rooms, calls. I figured I may as well plumb these in and test them my plan was to hide them before merge, they can then be unhidden when the features are complete. 
This commit is contained in:
committed by
Carl Schwan
parent
c3fcd280fb
commit
1946228d2b
@@ -21,6 +21,7 @@ add_library(neochat STATIC
|
||||
userlistmodel.cpp
|
||||
publicroomlistmodel.cpp
|
||||
userdirectorylistmodel.cpp
|
||||
keywordnotificationrulemodel.cpp
|
||||
utils.cpp
|
||||
notificationsmanager.cpp
|
||||
sortfilterroomlistmodel.cpp
|
||||
@@ -138,6 +139,7 @@ if(ANDROID)
|
||||
"rating-unrated"
|
||||
"search"
|
||||
"mail-replied-symbolic"
|
||||
"edit-clear"
|
||||
"edit-copy"
|
||||
"gtk-quit"
|
||||
"compass"
|
||||
@@ -148,6 +150,10 @@ if(ANDROID)
|
||||
"preferences-system-users"
|
||||
"preferences-desktop-theme-global"
|
||||
"notifications"
|
||||
"notifications-disabled"
|
||||
"audio-volume-high"
|
||||
"audio-volume-muted"
|
||||
"draw-highlight"
|
||||
"zoom-in"
|
||||
"zoom-out"
|
||||
"image-rotate-left-symbolic"
|
||||
|
||||
108
src/keywordnotificationrulemodel.cpp
Normal file
108
src/keywordnotificationrulemodel.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "keywordnotificationrulemodel.h"
|
||||
#include "controller.h"
|
||||
#include "notificationsmanager.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <connection.h>
|
||||
#include <converters.h>
|
||||
#include <csapi/definitions/push_ruleset.h>
|
||||
#include <csapi/pushrules.h>
|
||||
#include <jobs/basejob.h>
|
||||
|
||||
KeywordNotificationRuleModel::KeywordNotificationRuleModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
controllerConnectionChanged();
|
||||
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, &KeywordNotificationRuleModel::controllerConnectionChanged);
|
||||
}
|
||||
|
||||
void KeywordNotificationRuleModel::controllerConnectionChanged()
|
||||
{
|
||||
connect(Controller::instance().activeConnection(), &Quotient::Connection::accountDataChanged, this, &KeywordNotificationRuleModel::updateNotificationRules);
|
||||
updateNotificationRules("m.push_rules");
|
||||
}
|
||||
|
||||
void KeywordNotificationRuleModel::updateNotificationRules(const QString &type)
|
||||
{
|
||||
if (type != "m.push_rules") {
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonObject ruleDataJson = Controller::instance().activeConnection()->accountDataJson("m.push_rules");
|
||||
const Quotient::PushRuleset ruleData = Quotient::fromJson<Quotient::PushRuleset>(ruleDataJson["global"].toObject());
|
||||
const QVector<Quotient::PushRule> contentRules = ruleData.content;
|
||||
|
||||
beginResetModel();
|
||||
m_notificationRules.clear();
|
||||
for (const auto &i : contentRules) {
|
||||
if (!m_notificationRules.contains(i.ruleId) && i.ruleId[0] != '.') {
|
||||
m_notificationRules.append(i.ruleId);
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QVariant KeywordNotificationRuleModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.row() >= m_notificationRules.count()) {
|
||||
qDebug() << "KeywordNotificationRuleModel, something's wrong: index.row() >= m_notificationRules.count()";
|
||||
return {};
|
||||
}
|
||||
|
||||
if (role == NameRole) {
|
||||
return m_notificationRules.at(index.row());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
int KeywordNotificationRuleModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
return m_notificationRules.count();
|
||||
}
|
||||
|
||||
void KeywordNotificationRuleModel::addKeyword(const QString &keyword)
|
||||
{
|
||||
if (m_notificationRules.count() == 0) {
|
||||
NotificationsManager::instance().initializeKeywordNotificationAction();
|
||||
}
|
||||
|
||||
const QVector<QVariant> actions = NotificationsManager::instance().getKeywordNotificationActions();
|
||||
|
||||
auto job = Controller::instance()
|
||||
.activeConnection()
|
||||
->callApi<Quotient::SetPushRuleJob>("global", "content", keyword, actions, "", "", QVector<Quotient::PushCondition>(), keyword);
|
||||
connect(job, &Quotient::BaseJob::success, this, [this, keyword]() {
|
||||
beginInsertRows(QModelIndex(), m_notificationRules.count(), m_notificationRules.count());
|
||||
m_notificationRules.append(keyword);
|
||||
endInsertRows();
|
||||
});
|
||||
}
|
||||
|
||||
void KeywordNotificationRuleModel::removeKeywordAtIndex(int index)
|
||||
{
|
||||
auto job = Controller::instance().activeConnection()->callApi<Quotient::DeletePushRuleJob>("global", "content", m_notificationRules[index]);
|
||||
connect(job, &Quotient::BaseJob::success, this, [this, index]() {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_notificationRules.removeAt(index);
|
||||
endRemoveRows();
|
||||
|
||||
if (m_notificationRules.count() == 0) {
|
||||
NotificationsManager::instance().deactivateKeywordNotificationAction();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> KeywordNotificationRuleModel::roleNames() const
|
||||
{
|
||||
return {{NameRole, QByteArrayLiteral("name")}};
|
||||
}
|
||||
35
src/keywordnotificationrulemodel.h
Normal file
35
src/keywordnotificationrulemodel.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <csapi/definitions/push_rule.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class KeywordNotificationRuleModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum EventRoles {
|
||||
NameRole = Qt::DisplayRole,
|
||||
};
|
||||
|
||||
KeywordNotificationRuleModel(QObject *parent = nullptr);
|
||||
|
||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
Q_INVOKABLE void addKeyword(const QString &keyword);
|
||||
Q_INVOKABLE void removeKeywordAtIndex(int index);
|
||||
|
||||
private Q_SLOTS:
|
||||
void controllerConnectionChanged();
|
||||
void updateNotificationRules(const QString &type);
|
||||
|
||||
private:
|
||||
QList<QString> m_notificationRules;
|
||||
};
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "filetypesingleton.h"
|
||||
#include "joinrulesevent.h"
|
||||
#include "linkpreviewer.h"
|
||||
#include "keywordnotificationrulemodel.h"
|
||||
#include "login.h"
|
||||
#include "matriximageprovider.h"
|
||||
#include "messageeventmodel.h"
|
||||
@@ -216,8 +217,10 @@ int main(int argc, char *argv[])
|
||||
#ifdef QUOTIENT_07
|
||||
qmlRegisterType<PollHandler>("org.kde.neochat", 1, 0, "PollHandler");
|
||||
#endif
|
||||
qmlRegisterType<KeywordNotificationRuleModel>("org.kde.neochat", 1, 0, "KeywordNotificationRuleModel");
|
||||
qmlRegisterUncreatableType<RoomMessageEvent>("org.kde.neochat", 1, 0, "RoomMessageEvent", "ENUM");
|
||||
qmlRegisterUncreatableType<PushNotificationState>("org.kde.neochat", 1, 0, "PushNotificationState", "ENUM");
|
||||
qmlRegisterUncreatableType<PushNotificationAction>("org.kde.neochat", 1, 0, "PushNotificationAction", "ENUM");
|
||||
qmlRegisterUncreatableType<NeoChatRoomType>("org.kde.neochat", 1, 0, "NeoChatRoomType", "ENUM");
|
||||
qmlRegisterUncreatableType<UserType>("org.kde.neochat", 1, 0, "UserType", "ENUM");
|
||||
qmlRegisterUncreatableType<NeoChatUser>("org.kde.neochat", 1, 0, "NeoChatUser", {});
|
||||
|
||||
@@ -211,7 +211,7 @@ private:
|
||||
bool m_hasFileUploading = false;
|
||||
int m_fileUploadingProgress = 0;
|
||||
|
||||
PushNotificationState::State m_currentPushNotificationState = PushNotificationState::State::Unknown;
|
||||
PushNotificationState::State m_currentPushNotificationState = PushNotificationState::Unknown;
|
||||
bool m_pushNotificationStateUpdating = false;
|
||||
|
||||
void checkForHighlights(const Quotient::TimelineItem &ti);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include <QImage>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KNotification>
|
||||
@@ -36,7 +37,9 @@ NotificationsManager::NotificationsManager(QObject *parent)
|
||||
{
|
||||
// Can't connect the signal up until the active connection has been established by the controller
|
||||
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this]() {
|
||||
connect(Controller::instance().activeConnection(), &Connection::accountDataChanged, this, &NotificationsManager::updateGlobalNotificationsEnabled);
|
||||
connect(Controller::instance().activeConnection(), &Connection::accountDataChanged, this, &NotificationsManager::updateNotificationRules);
|
||||
// Ensure that the push rule states are retrieved after the connection is changed
|
||||
updateNotificationRules("m.push_rules");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -137,34 +140,295 @@ void NotificationsManager::clearInvitationNotification(const QString &roomId)
|
||||
*/
|
||||
void NotificationsManager::setGlobalNotificationsEnabled(bool enabled)
|
||||
{
|
||||
using namespace Quotient;
|
||||
|
||||
auto job = Controller::instance().activeConnection()->callApi<IsPushRuleEnabledJob>("global", "override", ".m.rule.master");
|
||||
connect(job, &BaseJob::success, this, [this, job, enabled]() {
|
||||
if (job->enabled() == enabled) {
|
||||
Controller::instance().activeConnection()->callApi<SetPushRuleEnabledJob>("global", "override", ".m.rule.master", !enabled);
|
||||
m_globalNotificationsEnabled = enabled;
|
||||
Q_EMIT globalNotificationsEnabledChanged(m_globalNotificationsEnabled);
|
||||
}
|
||||
});
|
||||
setNotificationRuleEnabled("override", ".m.rule.master", !enabled);
|
||||
}
|
||||
|
||||
void NotificationsManager::updateGlobalNotificationsEnabled(QString type)
|
||||
void NotificationsManager::setOneToOneNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
setNotificationRuleActions("underride", ".m.rule.room_one_to_one", action);
|
||||
}
|
||||
|
||||
void NotificationsManager::setEncryptedOneToOneNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
setNotificationRuleActions("underride", ".m.rule.encrypted_room_one_to_one", action);
|
||||
}
|
||||
|
||||
void NotificationsManager::setGroupChatNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
setNotificationRuleActions("underride", ".m.rule.message", action);
|
||||
}
|
||||
|
||||
void NotificationsManager::setEncryptedGroupChatNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
setNotificationRuleActions("underride", ".m.rule.encrypted", action);
|
||||
}
|
||||
|
||||
/*
|
||||
* .m.rule.contains_display_name is an override rule so it needs to be disabled when off
|
||||
* so that other rules can match the message if they apply.
|
||||
*/
|
||||
void NotificationsManager::setDisplayNameNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
if (action == PushNotificationAction::Off) {
|
||||
setNotificationRuleEnabled("override", ".m.rule.contains_display_name", false);
|
||||
} else {
|
||||
setNotificationRuleActions("override", ".m.rule.contains_display_name", action);
|
||||
setNotificationRuleEnabled("override", ".m.rule.contains_display_name", true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* .m.rule.roomnotif is an override rule so it needs to be disabled when off
|
||||
* so that other rules can match the message if they apply.
|
||||
*/
|
||||
void NotificationsManager::setRoomNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
if (action == PushNotificationAction::Off) {
|
||||
setNotificationRuleEnabled("override", ".m.rule.roomnotif", false);
|
||||
} else {
|
||||
setNotificationRuleActions("override", ".m.rule.roomnotif", action);
|
||||
setNotificationRuleEnabled("override", ".m.rule.roomnotif", true);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationsManager::initializeKeywordNotificationAction()
|
||||
{
|
||||
m_keywordNotificationAction = PushNotificationAction::Highlight;
|
||||
Q_EMIT keywordNotificationActionChanged(m_keywordNotificationAction);
|
||||
}
|
||||
|
||||
void NotificationsManager::deactivateKeywordNotificationAction()
|
||||
{
|
||||
m_keywordNotificationAction = PushNotificationAction::Off;
|
||||
Q_EMIT keywordNotificationActionChanged(m_keywordNotificationAction);
|
||||
}
|
||||
|
||||
QVector<QVariant> NotificationsManager::getKeywordNotificationActions()
|
||||
{
|
||||
return toActions(m_keywordNotificationAction);
|
||||
}
|
||||
|
||||
void NotificationsManager::setKeywordNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
// Unlike the other rules this needs to be set here for the case where there are no keyords.
|
||||
m_keywordNotificationAction = action;
|
||||
Q_EMIT keywordNotificationActionChanged(m_keywordNotificationAction);
|
||||
|
||||
const QJsonObject accountData = Controller::instance().activeConnection()->accountDataJson("m.push_rules");
|
||||
const QJsonArray contentRuleArray = accountData["global"].toObject()["content"].toArray();
|
||||
for (const auto &i : contentRuleArray) {
|
||||
const QJsonObject contentRule = i.toObject();
|
||||
if (contentRule["rule_id"].toString()[0] != '.') {
|
||||
setNotificationRuleActions("content", contentRule["rule_id"].toString(), action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* .m.rule.invite_for_me is an override rule so it needs to be disabled when off
|
||||
* so that other rules can match the message if they apply.
|
||||
*/
|
||||
void NotificationsManager::setInviteNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
if (action == PushNotificationAction::Off) {
|
||||
setNotificationRuleEnabled("override", ".m.rule.invite_for_me", false);
|
||||
} else {
|
||||
setNotificationRuleActions("override", ".m.rule.invite_for_me", action);
|
||||
setNotificationRuleEnabled("override", ".m.rule.invite_for_me", true);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationsManager::setCallInviteNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
setNotificationRuleActions("underride", ".m.rule.call", action);
|
||||
}
|
||||
|
||||
/*
|
||||
* .m.rule.tombstone is an override rule so it needs to be disabled when off
|
||||
* so that other rules can match the message if they apply.
|
||||
*/
|
||||
void NotificationsManager::setTombstoneNotificationAction(PushNotificationAction::Action action)
|
||||
{
|
||||
if (action == PushNotificationAction::Off) {
|
||||
setNotificationRuleEnabled("override", ".m.rule.tombstone", false);
|
||||
} else {
|
||||
setNotificationRuleActions("override", ".m.rule.tombstone", action);
|
||||
setNotificationRuleEnabled("override", ".m.rule.tombstone", true);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationsManager::updateNotificationRules(const QString &type)
|
||||
{
|
||||
if (type != "m.push_rules") {
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject accountData = Controller::instance().activeConnection()->accountDataJson("m.push_rules");
|
||||
QJsonArray overrideRuleArray = accountData.value("global").toObject().value("override").toArray();
|
||||
const QJsonObject accountData = Controller::instance().activeConnection()->accountDataJson("m.push_rules");
|
||||
|
||||
// Update override rules
|
||||
const QJsonArray overrideRuleArray = accountData["global"].toObject()["override"].toArray();
|
||||
for (const auto &i : overrideRuleArray) {
|
||||
QJsonObject overrideRule = i.toObject();
|
||||
if (overrideRule.value("rule_id") == ".m.rule.master") {
|
||||
bool ruleEnabled = overrideRule.value("enabled").toBool();
|
||||
const QJsonObject overrideRule = i.toObject();
|
||||
if (overrideRule["rule_id"] == ".m.rule.master") {
|
||||
bool ruleEnabled = overrideRule["enabled"].toBool();
|
||||
m_globalNotificationsEnabled = !ruleEnabled;
|
||||
NeoChatConfig::self()->setShowNotifications(m_globalNotificationsEnabled);
|
||||
Q_EMIT globalNotificationsEnabledChanged(m_globalNotificationsEnabled);
|
||||
}
|
||||
|
||||
const PushNotificationAction::Action action = toAction(overrideRule);
|
||||
|
||||
if (overrideRule["rule_id"] == ".m.rule.contains_display_name") {
|
||||
m_displayNameNotificationAction = action;
|
||||
Q_EMIT displayNameNotificationActionChanged(m_displayNameNotificationAction);
|
||||
} else if (overrideRule["rule_id"] == ".m.rule.roomnotif") {
|
||||
m_roomNotificationAction = action;
|
||||
Q_EMIT roomNotificationActionChanged(m_roomNotificationAction);
|
||||
} else if (overrideRule["rule_id"] == ".m.rule.invite_for_me") {
|
||||
m_inviteNotificationAction = action;
|
||||
Q_EMIT inviteNotificationActionChanged(m_inviteNotificationAction);
|
||||
} else if (overrideRule["rule_id"] == ".m.rule.tombstone") {
|
||||
m_tombstoneNotificationAction = action;
|
||||
Q_EMIT tombstoneNotificationActionChanged(m_tombstoneNotificationAction);
|
||||
}
|
||||
}
|
||||
|
||||
// Update content rules
|
||||
const QJsonArray contentRuleArray = accountData["global"].toObject()["content"].toArray();
|
||||
PushNotificationAction::Action keywordAction = PushNotificationAction::Unknown;
|
||||
for (const auto &i : contentRuleArray) {
|
||||
const QJsonObject contentRule = i.toObject();
|
||||
const PushNotificationAction::Action action = toAction(contentRule);
|
||||
bool actionMismatch = false;
|
||||
|
||||
if (contentRule["rule_id"].toString()[0] != '.' && !actionMismatch) {
|
||||
if (keywordAction == PushNotificationAction::Unknown) {
|
||||
keywordAction = action;
|
||||
m_keywordNotificationAction = action;
|
||||
Q_EMIT keywordNotificationActionChanged(m_keywordNotificationAction);
|
||||
} else if (action != keywordAction) {
|
||||
actionMismatch = true;
|
||||
m_keywordNotificationAction = PushNotificationAction::On;
|
||||
Q_EMIT keywordNotificationActionChanged(m_keywordNotificationAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If there are no keywords set the state to off, this is the only time it'll be in the off state
|
||||
if (keywordAction == PushNotificationAction::Unknown) {
|
||||
m_keywordNotificationAction = PushNotificationAction::Off;
|
||||
Q_EMIT keywordNotificationActionChanged(m_keywordNotificationAction);
|
||||
}
|
||||
|
||||
// Update underride rules
|
||||
const QJsonArray underrideRuleArray = accountData["global"].toObject()["underride"].toArray();
|
||||
for (const auto &i : underrideRuleArray) {
|
||||
const QJsonObject underrideRule = i.toObject();
|
||||
const PushNotificationAction::Action action = toAction(underrideRule);
|
||||
|
||||
if (underrideRule["rule_id"] == ".m.rule.room_one_to_one") {
|
||||
m_oneToOneNotificationAction = action;
|
||||
Q_EMIT oneToOneNotificationActionChanged(m_oneToOneNotificationAction);
|
||||
} else if (underrideRule["rule_id"] == ".m.rule.encrypted_room_one_to_one") {
|
||||
m_encryptedOneToOneNotificationAction = action;
|
||||
Q_EMIT encryptedOneToOneNotificationActionChanged(m_encryptedOneToOneNotificationAction);
|
||||
} else if (underrideRule["rule_id"] == ".m.rule.message") {
|
||||
m_groupChatNotificationAction = action;
|
||||
Q_EMIT groupChatNotificationActionChanged(m_groupChatNotificationAction);
|
||||
} else if (underrideRule["rule_id"] == ".m.rule.encrypted") {
|
||||
m_encryptedGroupChatNotificationAction = action;
|
||||
Q_EMIT encryptedGroupChatNotificationActionChanged(m_encryptedGroupChatNotificationAction);
|
||||
} else if (underrideRule["rule_id"] == ".m.rule.call") {
|
||||
m_callInviteNotificationAction = action;
|
||||
Q_EMIT callInviteNotificationActionChanged(m_callInviteNotificationAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationsManager::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled)
|
||||
{
|
||||
auto job = Controller::instance().activeConnection()->callApi<IsPushRuleEnabledJob>("global", kind, ruleId);
|
||||
connect(job, &BaseJob::success, this, [job, kind, ruleId, enabled]() {
|
||||
if (job->enabled() != enabled) {
|
||||
Controller::instance().activeConnection()->callApi<SetPushRuleEnabledJob>("global", kind, ruleId, enabled);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NotificationsManager::setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action)
|
||||
{
|
||||
QVector<QVariant> actions;
|
||||
if (ruleId == ".m.rule.call") {
|
||||
actions = toActions(action, "ring");
|
||||
} else {
|
||||
actions = toActions(action);
|
||||
}
|
||||
|
||||
Controller::instance().activeConnection()->callApi<SetPushRuleActionsJob>("global", kind, ruleId, actions);
|
||||
}
|
||||
|
||||
PushNotificationAction::Action NotificationsManager::toAction(const QJsonObject &rule)
|
||||
{
|
||||
const QJsonArray actions = rule["actions"].toArray();
|
||||
bool isNoisy = false;
|
||||
bool highlightEnabled = false;
|
||||
const bool enabled = rule["enabled"].toBool();
|
||||
for (const auto &i : actions) {
|
||||
QJsonObject action = i.toObject();
|
||||
if (action["set_tweak"].toString() == "sound") {
|
||||
isNoisy = true;
|
||||
} else if (action["set_tweak"].toString() == "highlight") {
|
||||
if (action["value"].toString() != "false") {
|
||||
highlightEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
return PushNotificationAction::Off;
|
||||
}
|
||||
|
||||
if (actions[0] == "notify") {
|
||||
if (isNoisy && highlightEnabled) {
|
||||
return PushNotificationAction::NoisyHighlight;
|
||||
} else if (isNoisy) {
|
||||
return PushNotificationAction::Noisy;
|
||||
} else if (highlightEnabled) {
|
||||
return PushNotificationAction::Highlight;
|
||||
} else {
|
||||
return PushNotificationAction::On;
|
||||
}
|
||||
} else {
|
||||
return PushNotificationAction::Off;
|
||||
}
|
||||
}
|
||||
|
||||
QVector<QVariant> NotificationsManager::toActions(PushNotificationAction::Action action, const QString &sound)
|
||||
{
|
||||
// The caller should never try to set the state to unknown.
|
||||
// It exists only as a default state to diable the settings options until the actual state is retrieved from the server.
|
||||
if (action == PushNotificationAction::Unknown) {
|
||||
Q_ASSERT(false);
|
||||
return QVector<QVariant>();
|
||||
}
|
||||
|
||||
QVector<QVariant> actions;
|
||||
|
||||
if (action != PushNotificationAction::Off) {
|
||||
actions.append("notify");
|
||||
} else {
|
||||
actions.append("dont_notify");
|
||||
}
|
||||
if (action == PushNotificationAction::Noisy || action == PushNotificationAction::NoisyHighlight) {
|
||||
QJsonObject soundTweak;
|
||||
soundTweak.insert("set_tweak", "sound");
|
||||
soundTweak.insert("value", sound);
|
||||
actions.append(soundTweak);
|
||||
}
|
||||
if (action == PushNotificationAction::Highlight || action == PushNotificationAction::NoisyHighlight) {
|
||||
QJsonObject highlightTweak;
|
||||
highlightTweak.insert("set_tweak", "highlight");
|
||||
actions.append(highlightTweak);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -8,14 +8,51 @@
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
class KNotification;
|
||||
class NeoChatRoom;
|
||||
|
||||
class PushNotificationAction : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Action {
|
||||
Unknown = 0,
|
||||
Off,
|
||||
On,
|
||||
Noisy,
|
||||
Highlight,
|
||||
NoisyHighlight,
|
||||
};
|
||||
Q_ENUM(Action);
|
||||
};
|
||||
|
||||
class NotificationsManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool globalNotificationsEnabled MEMBER m_globalNotificationsEnabled WRITE setGlobalNotificationsEnabled NOTIFY globalNotificationsEnabledChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action oneToOneNotificationAction MEMBER m_oneToOneNotificationAction WRITE setOneToOneNotificationAction NOTIFY
|
||||
oneToOneNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action encryptedOneToOneNotificationAction MEMBER m_encryptedOneToOneNotificationAction WRITE
|
||||
setEncryptedOneToOneNotificationAction NOTIFY encryptedOneToOneNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action groupChatNotificationAction MEMBER m_groupChatNotificationAction WRITE setGroupChatNotificationAction NOTIFY
|
||||
groupChatNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action encryptedGroupChatNotificationAction MEMBER m_encryptedGroupChatNotificationAction WRITE
|
||||
setEncryptedGroupChatNotificationAction NOTIFY encryptedGroupChatNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action displayNameNotificationAction MEMBER m_displayNameNotificationAction WRITE setDisplayNameNotificationAction NOTIFY
|
||||
displayNameNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action roomNotificationAction MEMBER m_roomNotificationAction WRITE setRoomNotificationAction NOTIFY
|
||||
roomNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action keywordNotificationAction MEMBER m_keywordNotificationAction WRITE setKeywordNotificationAction NOTIFY
|
||||
keywordNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action inviteNotificationAction MEMBER m_inviteNotificationAction WRITE setInviteNotificationAction NOTIFY
|
||||
inviteNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action callInviteNotificationAction MEMBER m_callInviteNotificationAction WRITE setCallInviteNotificationAction NOTIFY
|
||||
callInviteNotificationActionChanged)
|
||||
Q_PROPERTY(PushNotificationAction::Action tombstoneNotificationAction MEMBER m_tombstoneNotificationAction WRITE setTombstoneNotificationAction NOTIFY
|
||||
tombstoneNotificationActionChanged)
|
||||
|
||||
public:
|
||||
static NotificationsManager &instance();
|
||||
@@ -26,7 +63,9 @@ public:
|
||||
|
||||
void clearInvitationNotification(const QString &roomId);
|
||||
|
||||
Q_INVOKABLE void setGlobalNotificationsEnabled(bool enabled);
|
||||
void initializeKeywordNotificationAction();
|
||||
void deactivateKeywordNotificationAction();
|
||||
QVector<QVariant> getKeywordNotificationActions();
|
||||
|
||||
private:
|
||||
NotificationsManager(QObject *parent = nullptr);
|
||||
@@ -35,10 +74,47 @@ private:
|
||||
QHash<QString, QPointer<KNotification>> m_invitations;
|
||||
|
||||
bool m_globalNotificationsEnabled;
|
||||
PushNotificationAction::Action m_oneToOneNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_encryptedOneToOneNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_groupChatNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_encryptedGroupChatNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_displayNameNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_roomNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_keywordNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_inviteNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_callInviteNotificationAction = PushNotificationAction::Unknown;
|
||||
PushNotificationAction::Action m_tombstoneNotificationAction = PushNotificationAction::Unknown;
|
||||
|
||||
void setGlobalNotificationsEnabled(bool enabled);
|
||||
void setOneToOneNotificationAction(PushNotificationAction::Action action);
|
||||
void setEncryptedOneToOneNotificationAction(PushNotificationAction::Action action);
|
||||
void setGroupChatNotificationAction(PushNotificationAction::Action action);
|
||||
void setEncryptedGroupChatNotificationAction(PushNotificationAction::Action action);
|
||||
void setDisplayNameNotificationAction(PushNotificationAction::Action action);
|
||||
void setRoomNotificationAction(PushNotificationAction::Action action);
|
||||
void setKeywordNotificationAction(PushNotificationAction::Action action);
|
||||
void setInviteNotificationAction(PushNotificationAction::Action action);
|
||||
void setCallInviteNotificationAction(PushNotificationAction::Action action);
|
||||
void setTombstoneNotificationAction(PushNotificationAction::Action action);
|
||||
|
||||
void setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled);
|
||||
void setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action);
|
||||
PushNotificationAction::Action toAction(const QJsonObject &rule);
|
||||
QVector<QVariant> toActions(PushNotificationAction::Action action, const QString &sound = "default");
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateGlobalNotificationsEnabled(QString type);
|
||||
void updateNotificationRules(const QString &type);
|
||||
|
||||
Q_SIGNALS:
|
||||
void globalNotificationsEnabledChanged(bool newState);
|
||||
void oneToOneNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void encryptedOneToOneNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void groupChatNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void encryptedGroupChatNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void displayNameNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void roomNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void keywordNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void inviteNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void callInviteNotificationActionChanged(PushNotificationAction::Action action);
|
||||
void tombstoneNotificationActionChanged(PushNotificationAction::Action action);
|
||||
};
|
||||
|
||||
@@ -72,22 +72,8 @@ Kirigami.ScrollablePage {
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Notifications and events")
|
||||
title: i18n("Timeline Events")
|
||||
}
|
||||
MobileForm.FormCheckDelegate {
|
||||
id: showNotificationsDelegate
|
||||
// TODO: When there are enough notification and timeline event
|
||||
// settings, make 2 separate groups with FormData labels.
|
||||
text: i18n("Show notifications")
|
||||
checked: Config.showNotifications
|
||||
enabled: !Config.isShowNotificationsImmutable
|
||||
onToggled: {
|
||||
Config.showNotifications = checked
|
||||
Config.save()
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: showNotificationsDelegate; below: showLeaveJoinEventDelegate }
|
||||
|
||||
MobileForm.FormCheckDelegate {
|
||||
id: showLeaveJoinEventDelegate
|
||||
|
||||
328
src/qml/Settings/GlobalNotificationsPage.qml
Normal file
328
src/qml/Settings/GlobalNotificationsPage.qml
Normal file
@@ -0,0 +1,328 @@
|
||||
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
title: i18nc("@title:window", "Notifications")
|
||||
ColumnLayout {
|
||||
id: notificationLayout
|
||||
anchors.fill: parent
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: MobileForm.FormSwitchDelegate {
|
||||
text: i18n("Enable notifications for this account")
|
||||
checked: Config.showNotifications
|
||||
enabled: !Config.isShowNotificationsImmutable
|
||||
onToggled: {
|
||||
Config.showNotifications = checked
|
||||
Config.save()
|
||||
NotificationsManager.globalNotificationsEnabled = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Room Notifications")
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Messages in one-to-one chats")
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.oneToOneNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.oneToOneNotificationAction)
|
||||
enabled: NotificationsManager.oneToOneNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.oneToOneNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.oneToOneNotificationAction != notificationAction) {
|
||||
NotificationsManager.oneToOneNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Encrypted messages in one-to-one chats")
|
||||
|
||||
visible: Controller.encryptionSupported
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.encryptedOneToOneNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.encryptedOneToOneNotificationAction)
|
||||
enabled: NotificationsManager.encryptedOneToOneNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.encryptedOneToOneNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.encryptedOneToOneNotificationAction != notificationAction) {
|
||||
NotificationsManager.encryptedOneToOneNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Messages in group chats")
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.groupChatNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.groupChatNotificationAction)
|
||||
enabled: NotificationsManager.groupChatNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.groupChatNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.groupChatNotificationAction != notificationAction) {
|
||||
NotificationsManager.groupChatNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Messages in encrypted group chats")
|
||||
|
||||
visible: Controller.encryptionSupported
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.encryptedGroupChatNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.encryptedGroupChatNotificationAction)
|
||||
enabled: NotificationsManager.encryptedGroupChatNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.encryptedGroupChatNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.encryptedGroupChatNotificationAction != notificationAction) {
|
||||
NotificationsManager.encryptedGroupChatNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Room upgrade messages")
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.tombstoneNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.tombstoneNotificationAction)
|
||||
highlightable: true
|
||||
highlightOn: notificationLayout.isNotificationRuleHighlight(NotificationsManager.tombstoneNotificationAction)
|
||||
enabled: NotificationsManager.tombstoneNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.tombstoneNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.tombstoneNotificationAction != notificationAction) {
|
||||
NotificationsManager.tombstoneNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("@Mentions")
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Messages containing my display name")
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.displayNameNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.displayNameNotificationAction)
|
||||
highlightable: true
|
||||
highlightOn: notificationLayout.isNotificationRuleHighlight(NotificationsManager.displayNameNotificationAction)
|
||||
enabled: NotificationsManager.displayNameNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.displayNameNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.displayNameNotificationAction != notificationAction) {
|
||||
NotificationsManager.displayNameNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Whole room (@room) notifications")
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.roomNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.roomNotificationAction)
|
||||
highlightable: true
|
||||
highlightOn: notificationLayout.isNotificationRuleHighlight(NotificationsManager.roomNotificationAction)
|
||||
enabled: NotificationsManager.roomNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.roomNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.roomNotificationAction != notificationAction) {
|
||||
NotificationsManager.roomNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Keywords")
|
||||
}
|
||||
NotificationRuleItem {
|
||||
id: keywordNotificationAction
|
||||
text: i18n("Messages containing my keywords")
|
||||
|
||||
notificationsOn: true
|
||||
notificationsOnModifiable: false
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.keywordNotificationAction)
|
||||
highlightable: true
|
||||
highlightOn: notificationLayout.isNotificationRuleHighlight(NotificationsManager.keywordNotificationAction)
|
||||
enabled: NotificationsManager.keywordNotificationAction !== PushNotificationAction.Unknown &&
|
||||
NotificationsManager.keywordNotificationAction !== PushNotificationAction.Off
|
||||
|
||||
notificationAction: NotificationsManager.keywordNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.keywordNotificationAction != notificationAction) {
|
||||
NotificationsManager.keywordNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
Repeater {
|
||||
model: KeywordNotificationRuleModel {
|
||||
id: keywordNotificationRuleModel
|
||||
}
|
||||
|
||||
delegate: NotificationRuleItem {
|
||||
text: name
|
||||
notificationAction: keywordNotificationAction.notificationAction
|
||||
notificationsOn: keywordNotificationAction.notificationsOn
|
||||
notificationsOnModifiable: false
|
||||
noisyOn: keywordNotificationAction.noisyOn
|
||||
noisyModifiable: false
|
||||
highlightOn: keywordNotificationAction.highlightOn
|
||||
deletable: true
|
||||
|
||||
onDeleteItemChanged: {
|
||||
if (deleteItem && deletable) {
|
||||
keywordNotificationRuleModel.removeKeywordAtIndex(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MobileForm.AbstractFormDelegate {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem : RowLayout {
|
||||
Kirigami.ActionTextField {
|
||||
id: keywordAddField
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
placeholderText: i18n("Keyword…")
|
||||
|
||||
rightActions: Kirigami.Action {
|
||||
icon.name: "edit-clear"
|
||||
visible: keywordAddField.text.length > 0
|
||||
onTriggered: {
|
||||
keywordAddField.text = ""
|
||||
}
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
keywordNotificationRuleModel.addKeyword(keywordAddField.text, PushNotificationAction.On)
|
||||
keywordAddField.text = ""
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
id: addButton
|
||||
|
||||
text: i18n("Add keyword")
|
||||
Accessible.name: text
|
||||
icon.name: "list-add"
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
onClicked: {
|
||||
keywordNotificationRuleModel.addKeyword(keywordAddField.text, PushNotificationAction.On)
|
||||
keywordAddField.text = ""
|
||||
}
|
||||
|
||||
QQC2.ToolTip {
|
||||
text: addButton.text
|
||||
delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Invites")
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Invites to a room")
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.inviteNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.inviteNotificationAction)
|
||||
highlightable: true
|
||||
highlightOn: notificationLayout.isNotificationRuleHighlight(NotificationsManager.inviteNotificationAction)
|
||||
enabled: NotificationsManager.inviteNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.inviteNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.inviteNotificationAction != notificationAction) {
|
||||
NotificationsManager.inviteNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
NotificationRuleItem {
|
||||
text: i18n("Call invitation")
|
||||
|
||||
// TODO enable this option when calls are supported
|
||||
visible: false
|
||||
|
||||
notificationsOn: notificationLayout.isNotificationRuleOn(NotificationsManager.callInviteNotificationAction)
|
||||
noisyOn: notificationLayout.isNotificationRuleNoisy(NotificationsManager.callInviteNotificationAction)
|
||||
highlightable: true
|
||||
highlightOn: notificationLayout.isNotificationRuleHighlight(NotificationsManager.callInviteNotificationAction)
|
||||
enabled: NotificationsManager.callInviteNotificationAction !== PushNotificationAction.Unknown
|
||||
|
||||
notificationAction: NotificationsManager.callInviteNotificationAction
|
||||
onNotificationActionChanged: {
|
||||
if (notificationAction && NotificationsManager.callInviteNotificationAction != notificationAction) {
|
||||
NotificationsManager.callInviteNotificationAction = notificationAction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isNotificationRuleOn(action) {
|
||||
return action == PushNotificationAction.On ||
|
||||
action == PushNotificationAction.Noisy ||
|
||||
action == PushNotificationAction.Highlight ||
|
||||
action == PushNotificationAction.NoisyHighlight
|
||||
}
|
||||
|
||||
function isNotificationRuleNoisy(action) {
|
||||
return action == PushNotificationAction.Noisy ||
|
||||
action == PushNotificationAction.NoisyHighlight
|
||||
}
|
||||
|
||||
function isNotificationRuleHighlight(action) {
|
||||
return action == PushNotificationAction.Highlight ||
|
||||
action == PushNotificationAction.NoisyHighlight
|
||||
}
|
||||
}
|
||||
}
|
||||
182
src/qml/Settings/NotificationRuleItem.qml
Normal file
182
src/qml/Settings/NotificationRuleItem.qml
Normal file
@@ -0,0 +1,182 @@
|
||||
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
MobileForm.AbstractFormDelegate {
|
||||
id: notificationRuleItem
|
||||
|
||||
property var notificationAction: PushNotificationAction.Unkown
|
||||
property bool notificationsOn: false
|
||||
property bool notificationsOnModifiable: true
|
||||
property bool noisyOn: false
|
||||
property bool noisyModifiable: true
|
||||
property bool highlightOn: false
|
||||
property bool highlightable: false
|
||||
property bool deleteItem: false
|
||||
property bool deletable: false
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
onClicked: {
|
||||
notificationAction = nextNotificationRuleAction(notificationAction)
|
||||
}
|
||||
|
||||
contentItem : RowLayout {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
QQC2.Label {
|
||||
Layout.minimumWidth: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
|
||||
|
||||
text: notificationsOn ? "" : "●"
|
||||
color: Kirigami.Theme.textColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
background: Rectangle {
|
||||
visible: notificationsOn
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
||||
color: highlightOn ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.disabledTextColor
|
||||
opacity: highlightOn ? 1 : 0.3
|
||||
radius: height / 2
|
||||
}
|
||||
}
|
||||
QQC2.Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
text: notificationRuleItem.text
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
}
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
QQC2.Button {
|
||||
id: onButton
|
||||
|
||||
text: onButton.checked ? i18n("Disable notifications") : i18n("Enable notifications")
|
||||
Accessible.name: text
|
||||
icon.name: checked ? "notifications" : "notifications-disabled"
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
visible: notificationRuleItem.notificationsOnModifiable
|
||||
checkable: true
|
||||
checked: notificationRuleItem.notificationsOn
|
||||
enabled: notificationRuleItem.enabled
|
||||
down: checked
|
||||
onToggled: {
|
||||
notificationRuleItem.notificationAction = notificationRuleItem.notifcationRuleAction()
|
||||
}
|
||||
|
||||
QQC2.ToolTip {
|
||||
text: onButton.text
|
||||
delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
id: noisyButton
|
||||
|
||||
text: noisyButton.checked ? i18n("Mute notifications") : i18n("Unmute notifications")
|
||||
Accessible.name: text
|
||||
icon.name: checked ? "audio-volume-high" : "audio-volume-muted"
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
visible: notificationRuleItem.noisyModifiable
|
||||
checkable: true
|
||||
checked: notificationRuleItem.noisyOn
|
||||
enabled: (onButton.checked || !notificationRuleItem.notificationsOnModifiable) && notificationRuleItem.enabled
|
||||
down: checked
|
||||
onToggled: {
|
||||
notificationRuleItem.notificationAction = notificationRuleItem.notifcationRuleAction()
|
||||
}
|
||||
|
||||
QQC2.ToolTip {
|
||||
text: noisyButton.text
|
||||
delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
id: highlightButton
|
||||
|
||||
text: highlightButton.checked ? i18nc("As in clicking this button will switch off highlights for messages that match this rule", "Disable message highlights") : i18nc("As in clicking this button will switch on highlights for messages that match this rule", "Enable message highlights")
|
||||
Accessible.name: text
|
||||
icon.name: "draw-highlight"
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
visible: notificationRuleItem.highlightable
|
||||
checkable: true
|
||||
checked: notificationRuleItem.highlightOn
|
||||
enabled: (onButton.checked || !notificationRuleItem.notificationsOnModifiable) && notificationRuleItem.enabled
|
||||
down: checked
|
||||
onToggled: {
|
||||
notificationRuleItem.notificationAction = notificationRuleItem.notifcationRuleAction()
|
||||
}
|
||||
|
||||
QQC2.ToolTip {
|
||||
text: highlightButton.text
|
||||
delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
id: deleteButton
|
||||
|
||||
Accessible.name: i18n("Delete keyword")
|
||||
icon.name: "edit-delete-remove"
|
||||
|
||||
visible: notificationRuleItem.deletable
|
||||
|
||||
onClicked: {
|
||||
notificationRuleItem.deleteItem = !notificationRuleItem.deleteItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function notifcationRuleAction() {
|
||||
if (onButton.checked) {
|
||||
if (noisyButton.checked && highlightButton.checked) {
|
||||
return PushNotificationAction.NoisyHighlight
|
||||
} else if (noisyButton.checked) {
|
||||
return PushNotificationAction.Noisy
|
||||
} else if (highlightButton.checked) {
|
||||
return PushNotificationAction.Highlight
|
||||
} else {
|
||||
return PushNotificationAction.On
|
||||
}
|
||||
} else {
|
||||
return PushNotificationAction.Off
|
||||
}
|
||||
}
|
||||
|
||||
function nextNotificationRuleAction(action) {
|
||||
let finished = false
|
||||
|
||||
if (action == PushNotificationAction.NoisyHighlight) {
|
||||
action = PushNotificationAction.Off
|
||||
} else {
|
||||
action += 1
|
||||
}
|
||||
|
||||
while (!finished) {
|
||||
if (action == PushNotificationAction.Off && !notificationRuleItem.notificationsOnModifiable) {
|
||||
action = PushNotificationAction.On
|
||||
} else if (action == PushNotificationAction.Noisy && !notificationRuleItem.noisyModifiable) {
|
||||
action = PushNotificationAction.Highlight
|
||||
} else if (action == PushNotificationAction.Highlight && !notificationRuleItem.highlightable) {
|
||||
action = PushNotificationAction.Off
|
||||
} else {
|
||||
finished = true
|
||||
}
|
||||
}
|
||||
|
||||
return action
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,11 @@ Kirigami.CategorizedSettings {
|
||||
icon.name: "preferences-desktop-theme-global"
|
||||
page: Qt.resolvedUrl("AppearanceSettingsPage.qml")
|
||||
},
|
||||
Kirigami.SettingAction {
|
||||
text: i18n("Notifications")
|
||||
icon.name: "preferences-desktop-notification"
|
||||
page: Qt.resolvedUrl("GlobalNotificationsPage.qml")
|
||||
},
|
||||
Kirigami.SettingAction {
|
||||
text: i18n("Accounts")
|
||||
icon.name: "preferences-system-users"
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
<file alias="ColorScheme.qml">qml/Settings/ColorScheme.qml</file>
|
||||
<file alias="GeneralSettingsPage.qml">qml/Settings/GeneralSettingsPage.qml</file>
|
||||
<file alias="Emoticons.qml">qml/Settings/Emoticons.qml</file>
|
||||
<file alias="GlobalNotificationsPage.qml">qml/Settings/GlobalNotificationsPage.qml</file>
|
||||
<file alias="NotificationRuleItem.qml">qml/Settings/NotificationRuleItem.qml</file>
|
||||
<file alias="AppearanceSettingsPage.qml">qml/Settings/AppearanceSettingsPage.qml</file>
|
||||
<file alias="AccountsPage.qml">qml/Settings/AccountsPage.qml</file>
|
||||
<file alias="AccountEditorPage.qml">qml/Settings/AccountEditorPage.qml</file>
|
||||
|
||||
Reference in New Issue
Block a user