forked from quickshell/quickshell
service/notifications: add inline-reply action support
Signed-off-by: ipg0 <pyromancy00@gmail.com>
This commit is contained in:
parent
3dfb7d8827
commit
c40074dd56
7 changed files with 79 additions and 3 deletions
|
@ -78,6 +78,29 @@ void Notification::close(NotificationCloseReason::Enum reason) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Notification::sendInlineReply(const QString& replyText) {
|
||||||
|
if (!NotificationServer::instance()->support.inlineReply) {
|
||||||
|
qCritical() << "Inline reply support disabled on server";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->bHasInlineReply) {
|
||||||
|
qCritical() << "Cannot send reply to notification without inline-reply action";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->isRetained()) {
|
||||||
|
qCritical() << "Cannot send reply to destroyed notification" << this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationServer::instance()->NotificationReplied(this->id(), replyText);
|
||||||
|
|
||||||
|
if (!this->bindableResident().value()) {
|
||||||
|
this->close(NotificationCloseReason::Dismissed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Notification::updateProperties(
|
void Notification::updateProperties(
|
||||||
const QString& appName,
|
const QString& appName,
|
||||||
QString appIcon,
|
QString appIcon,
|
||||||
|
@ -147,17 +170,27 @@ void Notification::updateProperties(
|
||||||
this->bImage = imagePath;
|
this->bImage = imagePath;
|
||||||
this->bHints = hints;
|
this->bHints = hints;
|
||||||
|
|
||||||
Qt::endPropertyUpdateGroup();
|
|
||||||
|
|
||||||
bool actionsChanged = false;
|
bool actionsChanged = false;
|
||||||
auto deletedActions = QVector<NotificationAction*>();
|
auto deletedActions = QVector<NotificationAction*>();
|
||||||
|
|
||||||
if (actions.length() % 2 == 0) {
|
if (actions.length() % 2 == 0) {
|
||||||
int ai = 0;
|
int ai = 0;
|
||||||
for (auto i = 0; i != actions.length(); i += 2) {
|
for (auto i = 0; i != actions.length(); i += 2) {
|
||||||
ai = i / 2;
|
|
||||||
const auto& identifier = actions.at(i);
|
const auto& identifier = actions.at(i);
|
||||||
const auto& text = actions.at(i + 1);
|
const auto& text = actions.at(i + 1);
|
||||||
|
|
||||||
|
if (identifier == "inline-reply" && NotificationServer::instance()->support.inlineReply) {
|
||||||
|
if (this->bHasInlineReply) {
|
||||||
|
qCWarning(logNotifications) << this << '(' << appName << ')'
|
||||||
|
<< "sent an action set with duplicate inline-reply actions.";
|
||||||
|
} else {
|
||||||
|
this->bHasInlineReply = true;
|
||||||
|
this->bInlineReplyPlaceholder = text;
|
||||||
|
}
|
||||||
|
// skip inserting this action into action list
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
auto* action = ai < this->mActions.length() ? this->mActions.at(ai) : nullptr;
|
auto* action = ai < this->mActions.length() ? this->mActions.at(ai) : nullptr;
|
||||||
|
|
||||||
if (action && identifier == action->identifier()) {
|
if (action && identifier == action->identifier()) {
|
||||||
|
@ -188,6 +221,8 @@ void Notification::updateProperties(
|
||||||
<< "sent an action set of an invalid length.";
|
<< "sent an action set of an invalid length.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Qt::endPropertyUpdateGroup();
|
||||||
|
|
||||||
if (actionsChanged) emit this->actionsChanged();
|
if (actionsChanged) emit this->actionsChanged();
|
||||||
|
|
||||||
for (auto* action: deletedActions) {
|
for (auto* action: deletedActions) {
|
||||||
|
|
|
@ -107,6 +107,12 @@ class Notification
|
||||||
///
|
///
|
||||||
/// This image is often something like a profile picture in instant messaging applications.
|
/// This image is often something like a profile picture in instant messaging applications.
|
||||||
Q_PROPERTY(QString image READ default NOTIFY imageChanged BINDABLE bindableImage);
|
Q_PROPERTY(QString image READ default NOTIFY imageChanged BINDABLE bindableImage);
|
||||||
|
/// If true, the notification has an inline reply action.
|
||||||
|
///
|
||||||
|
/// A quick reply text field should be displayed and the reply can be sent using @@sendInlineReply().
|
||||||
|
Q_PROPERTY(bool hasInlineReply READ default NOTIFY hasInlineReplyChanged BINDABLE bindableHasInlineReply);
|
||||||
|
/// The placeholder text/button caption for the inline reply.
|
||||||
|
Q_PROPERTY(QString inlineReplyPlaceholder READ default NOTIFY inlineReplyPlaceholderChanged BINDABLE bindableInlineReplyPlaceholder);
|
||||||
/// All hints sent by the client application as a javascript object.
|
/// All hints sent by the client application as a javascript object.
|
||||||
/// Many common hints are exposed via other properties.
|
/// Many common hints are exposed via other properties.
|
||||||
Q_PROPERTY(QVariantMap hints READ default NOTIFY hintsChanged BINDABLE bindableHints);
|
Q_PROPERTY(QVariantMap hints READ default NOTIFY hintsChanged BINDABLE bindableHints);
|
||||||
|
@ -124,6 +130,12 @@ public:
|
||||||
/// explicitly closed by the user.
|
/// explicitly closed by the user.
|
||||||
Q_INVOKABLE void dismiss();
|
Q_INVOKABLE void dismiss();
|
||||||
|
|
||||||
|
/// Send an inline reply to the notification with an inline reply action.
|
||||||
|
/// > [!WARNING] This method can only be called if
|
||||||
|
/// > @@hasInlineReply is true
|
||||||
|
/// > and the server has @@NotificationServer.inlineReplySupported set to true.
|
||||||
|
Q_INVOKABLE void sendInlineReply(const QString& replyText);
|
||||||
|
|
||||||
void updateProperties(
|
void updateProperties(
|
||||||
const QString& appName,
|
const QString& appName,
|
||||||
QString appIcon,
|
QString appIcon,
|
||||||
|
@ -158,6 +170,8 @@ public:
|
||||||
[[nodiscard]] QBindable<bool> bindableTransient() const { return &this->bTransient; };
|
[[nodiscard]] QBindable<bool> bindableTransient() const { return &this->bTransient; };
|
||||||
[[nodiscard]] QBindable<QString> bindableDesktopEntry() const { return &this->bDesktopEntry; };
|
[[nodiscard]] QBindable<QString> bindableDesktopEntry() const { return &this->bDesktopEntry; };
|
||||||
[[nodiscard]] QBindable<QString> bindableImage() const { return &this->bImage; };
|
[[nodiscard]] QBindable<QString> bindableImage() const { return &this->bImage; };
|
||||||
|
[[nodiscard]] QBindable<bool> bindableHasInlineReply() const { return &this->bHasInlineReply; };
|
||||||
|
[[nodiscard]] QBindable<QString> bindableInlineReplyPlaceholder() const { return &this->bInlineReplyPlaceholder; };
|
||||||
[[nodiscard]] QBindable<QVariantMap> bindableHints() const { return &this->bHints; };
|
[[nodiscard]] QBindable<QVariantMap> bindableHints() const { return &this->bHints; };
|
||||||
|
|
||||||
[[nodiscard]] NotificationCloseReason::Enum closeReason() const;
|
[[nodiscard]] NotificationCloseReason::Enum closeReason() const;
|
||||||
|
@ -182,6 +196,8 @@ signals:
|
||||||
void transientChanged();
|
void transientChanged();
|
||||||
void desktopEntryChanged();
|
void desktopEntryChanged();
|
||||||
void imageChanged();
|
void imageChanged();
|
||||||
|
void hasInlineReplyChanged();
|
||||||
|
void inlineReplyPlaceholderChanged();
|
||||||
void hintsChanged();
|
void hintsChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -202,6 +218,8 @@ private:
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bTransient, &Notification::transientChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bTransient, &Notification::transientChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bDesktopEntry, &Notification::desktopEntryChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bDesktopEntry, &Notification::desktopEntryChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bImage, &Notification::imageChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bImage, &Notification::imageChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bHasInlineReply, &Notification::hasInlineReplyChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bInlineReplyPlaceholder, &Notification::inlineReplyPlaceholderChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Notification, QVariantMap, bHints, &Notification::hintsChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(Notification, QVariantMap, bHints, &Notification::hintsChanged);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,11 @@
|
||||||
<arg name="actionKey" type="s" direction="out"/>
|
<arg name="actionKey" type="s" direction="out"/>
|
||||||
</signal>
|
</signal>
|
||||||
|
|
||||||
|
<signal name="NotificationReplied">
|
||||||
|
<arg name="id" type="u" direction="out"/>
|
||||||
|
<arg name="replyText" type="s" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
|
||||||
<signal name="ActivationToken">
|
<signal name="ActivationToken">
|
||||||
<arg name="id" type="u" direction="out"/>
|
<arg name="id" type="u" direction="out"/>
|
||||||
<arg name="activationToken" type="s" direction="out"/>
|
<arg name="activationToken" type="s" direction="out"/>
|
||||||
|
|
|
@ -115,6 +115,15 @@ void NotificationServerQml::setImageSupported(bool imageSupported) {
|
||||||
emit this->imageSupportedChanged();
|
emit this->imageSupportedChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NotificationServerQml::inlineReplySupported() const { return this->support.inlineReply; }
|
||||||
|
|
||||||
|
void NotificationServerQml::setInlineReplySupported(bool inlineReplySupported) {
|
||||||
|
if (inlineReplySupported == this->support.inlineReply) return;
|
||||||
|
this->support.inlineReply = inlineReplySupported;
|
||||||
|
this->updateSupported();
|
||||||
|
emit this->inlineReplySupportedChanged();
|
||||||
|
}
|
||||||
|
|
||||||
QVector<QString> NotificationServerQml::extraHints() const { return this->support.extraHints; }
|
QVector<QString> NotificationServerQml::extraHints() const { return this->support.extraHints; }
|
||||||
|
|
||||||
void NotificationServerQml::setExtraHints(QVector<QString> extraHints) {
|
void NotificationServerQml::setExtraHints(QVector<QString> extraHints) {
|
||||||
|
|
|
@ -65,6 +65,8 @@ class NotificationServerQml: public PostReloadHook {
|
||||||
Q_PROPERTY(bool actionIconsSupported READ actionIconsSupported WRITE setActionIconsSupported NOTIFY actionIconsSupportedChanged);
|
Q_PROPERTY(bool actionIconsSupported READ actionIconsSupported WRITE setActionIconsSupported NOTIFY actionIconsSupportedChanged);
|
||||||
/// If the notification server should advertise that it supports images. Defaults to false.
|
/// If the notification server should advertise that it supports images. Defaults to false.
|
||||||
Q_PROPERTY(bool imageSupported READ imageSupported WRITE setImageSupported NOTIFY imageSupportedChanged);
|
Q_PROPERTY(bool imageSupported READ imageSupported WRITE setImageSupported NOTIFY imageSupportedChanged);
|
||||||
|
/// If the notification server should advertise that it supports inline replies. Defaults to false.
|
||||||
|
Q_PROPERTY(bool inlineReplySupported READ inlineReplySupported WRITE setInlineReplySupported NOTIFY inlineReplySupportedChanged);
|
||||||
/// All notifications currently tracked by the server.
|
/// All notifications currently tracked by the server.
|
||||||
QSDOC_TYPE_OVERRIDE(ObjectModel<qs::service::notifications::Notification>*);
|
QSDOC_TYPE_OVERRIDE(ObjectModel<qs::service::notifications::Notification>*);
|
||||||
Q_PROPERTY(UntypedObjectModel* trackedNotifications READ trackedNotifications NOTIFY trackedNotificationsChanged);
|
Q_PROPERTY(UntypedObjectModel* trackedNotifications READ trackedNotifications NOTIFY trackedNotificationsChanged);
|
||||||
|
@ -103,6 +105,9 @@ public:
|
||||||
[[nodiscard]] bool imageSupported() const;
|
[[nodiscard]] bool imageSupported() const;
|
||||||
void setImageSupported(bool imageSupported);
|
void setImageSupported(bool imageSupported);
|
||||||
|
|
||||||
|
[[nodiscard]] bool inlineReplySupported() const;
|
||||||
|
void setInlineReplySupported(bool inlineReplySupported);
|
||||||
|
|
||||||
[[nodiscard]] QVector<QString> extraHints() const;
|
[[nodiscard]] QVector<QString> extraHints() const;
|
||||||
void setExtraHints(QVector<QString> extraHints);
|
void setExtraHints(QVector<QString> extraHints);
|
||||||
|
|
||||||
|
@ -123,6 +128,7 @@ signals:
|
||||||
void actionsSupportedChanged();
|
void actionsSupportedChanged();
|
||||||
void actionIconsSupportedChanged();
|
void actionIconsSupportedChanged();
|
||||||
void imageSupportedChanged();
|
void imageSupportedChanged();
|
||||||
|
void inlineReplySupportedChanged();
|
||||||
void extraHintsChanged();
|
void extraHintsChanged();
|
||||||
void trackedNotificationsChanged();
|
void trackedNotificationsChanged();
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,7 @@ QStringList NotificationServer::GetCapabilities() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->support.image) capabilities += "icon-static";
|
if (this->support.image) capabilities += "icon-static";
|
||||||
|
if (this->support.inlineReply) capabilities += "inline-reply";
|
||||||
|
|
||||||
capabilities += this->support.extraHints;
|
capabilities += this->support.extraHints;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ struct NotificationServerSupport {
|
||||||
bool actions = false;
|
bool actions = false;
|
||||||
bool actionIcons = false;
|
bool actionIcons = false;
|
||||||
bool image = false;
|
bool image = false;
|
||||||
|
bool inlineReply = false;
|
||||||
QVector<QString> extraHints;
|
QVector<QString> extraHints;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,6 +61,7 @@ signals:
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
void NotificationClosed(quint32 id, quint32 reason);
|
void NotificationClosed(quint32 id, quint32 reason);
|
||||||
void ActionInvoked(quint32 id, QString action);
|
void ActionInvoked(quint32 id, QString action);
|
||||||
|
void NotificationReplied(quint32 id, QString replyText);
|
||||||
// NOLINTEND
|
// NOLINTEND
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue