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(
 | 
			
		||||
    const QString& appName,
 | 
			
		||||
    QString appIcon,
 | 
			
		||||
| 
						 | 
				
			
			@ -147,17 +170,27 @@ void Notification::updateProperties(
 | 
			
		|||
	this->bImage = imagePath;
 | 
			
		||||
	this->bHints = hints;
 | 
			
		||||
 | 
			
		||||
	Qt::endPropertyUpdateGroup();
 | 
			
		||||
 | 
			
		||||
	bool actionsChanged = false;
 | 
			
		||||
	auto deletedActions = QVector<NotificationAction*>();
 | 
			
		||||
 | 
			
		||||
	if (actions.length() % 2 == 0) {
 | 
			
		||||
		int ai = 0;
 | 
			
		||||
		for (auto i = 0; i != actions.length(); i += 2) {
 | 
			
		||||
			ai = i / 2;
 | 
			
		||||
			const auto& identifier = actions.at(i);
 | 
			
		||||
			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;
 | 
			
		||||
 | 
			
		||||
			if (action && identifier == action->identifier()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -188,6 +221,8 @@ void Notification::updateProperties(
 | 
			
		|||
		                            << "sent an action set of an invalid length.";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Qt::endPropertyUpdateGroup();
 | 
			
		||||
 | 
			
		||||
	if (actionsChanged) emit this->actionsChanged();
 | 
			
		||||
 | 
			
		||||
	for (auto* action: deletedActions) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -107,6 +107,12 @@ class Notification
 | 
			
		|||
	///
 | 
			
		||||
	/// This image is often something like a profile picture in instant messaging applications.
 | 
			
		||||
	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.
 | 
			
		||||
	/// Many common hints are exposed via other properties.
 | 
			
		||||
	Q_PROPERTY(QVariantMap hints READ default NOTIFY hintsChanged BINDABLE bindableHints);
 | 
			
		||||
| 
						 | 
				
			
			@ -124,6 +130,12 @@ public:
 | 
			
		|||
	/// explicitly closed by the user.
 | 
			
		||||
	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(
 | 
			
		||||
	    const QString& appName,
 | 
			
		||||
	    QString appIcon,
 | 
			
		||||
| 
						 | 
				
			
			@ -158,6 +170,8 @@ public:
 | 
			
		|||
	[[nodiscard]] QBindable<bool> bindableTransient() const { return &this->bTransient; };
 | 
			
		||||
	[[nodiscard]] QBindable<QString> bindableDesktopEntry() const { return &this->bDesktopEntry; };
 | 
			
		||||
	[[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]] NotificationCloseReason::Enum closeReason() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -182,6 +196,8 @@ signals:
 | 
			
		|||
	void transientChanged();
 | 
			
		||||
	void desktopEntryChanged();
 | 
			
		||||
	void imageChanged();
 | 
			
		||||
	void hasInlineReplyChanged();
 | 
			
		||||
	void inlineReplyPlaceholderChanged();
 | 
			
		||||
	void hintsChanged();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +218,8 @@ private:
 | 
			
		|||
	Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bTransient, &Notification::transientChanged);
 | 
			
		||||
	Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bDesktopEntry, &Notification::desktopEntryChanged);
 | 
			
		||||
	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);
 | 
			
		||||
	// clang-format on
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,11 @@
 | 
			
		|||
			<arg name="actionKey" type="s" direction="out"/>
 | 
			
		||||
		</signal>
 | 
			
		||||
 | 
			
		||||
		<signal name="NotificationReplied">
 | 
			
		||||
			<arg name="id" type="u" direction="out"/>
 | 
			
		||||
			<arg name="replyText" type="s" direction="out"/>
 | 
			
		||||
		</signal>
 | 
			
		||||
 | 
			
		||||
		<signal name="ActivationToken">
 | 
			
		||||
			<arg name="id" type="u" direction="out"/>
 | 
			
		||||
			<arg name="activationToken" type="s" direction="out"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,6 +115,15 @@ void NotificationServerQml::setImageSupported(bool imageSupported) {
 | 
			
		|||
	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; }
 | 
			
		||||
 | 
			
		||||
void NotificationServerQml::setExtraHints(QVector<QString> extraHints) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,6 +65,8 @@ class NotificationServerQml: public PostReloadHook {
 | 
			
		|||
	Q_PROPERTY(bool actionIconsSupported READ actionIconsSupported WRITE setActionIconsSupported NOTIFY actionIconsSupportedChanged);
 | 
			
		||||
	/// If the notification server should advertise that it supports images. Defaults to false.
 | 
			
		||||
	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.
 | 
			
		||||
	QSDOC_TYPE_OVERRIDE(ObjectModel<qs::service::notifications::Notification>*);
 | 
			
		||||
	Q_PROPERTY(UntypedObjectModel* trackedNotifications READ trackedNotifications NOTIFY trackedNotificationsChanged);
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +105,9 @@ public:
 | 
			
		|||
	[[nodiscard]] bool imageSupported() const;
 | 
			
		||||
	void setImageSupported(bool imageSupported);
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] bool inlineReplySupported() const;
 | 
			
		||||
	void setInlineReplySupported(bool inlineReplySupported);
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] QVector<QString> extraHints() const;
 | 
			
		||||
	void setExtraHints(QVector<QString> extraHints);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -123,6 +128,7 @@ signals:
 | 
			
		|||
	void actionsSupportedChanged();
 | 
			
		||||
	void actionIconsSupportedChanged();
 | 
			
		||||
	void imageSupportedChanged();
 | 
			
		||||
	void inlineReplySupportedChanged();
 | 
			
		||||
	void extraHintsChanged();
 | 
			
		||||
	void trackedNotificationsChanged();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,6 +155,7 @@ QStringList NotificationServer::GetCapabilities() const {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (this->support.image) capabilities += "icon-static";
 | 
			
		||||
	if (this->support.inlineReply) capabilities += "inline-reply";
 | 
			
		||||
 | 
			
		||||
	capabilities += this->support.extraHints;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ struct NotificationServerSupport {
 | 
			
		|||
	bool actions = false;
 | 
			
		||||
	bool actionIcons = false;
 | 
			
		||||
	bool image = false;
 | 
			
		||||
	bool inlineReply = false;
 | 
			
		||||
	QVector<QString> extraHints;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,6 +61,7 @@ signals:
 | 
			
		|||
	// NOLINTBEGIN
 | 
			
		||||
	void NotificationClosed(quint32 id, quint32 reason);
 | 
			
		||||
	void ActionInvoked(quint32 id, QString action);
 | 
			
		||||
	void NotificationReplied(quint32 id, QString replyText);
 | 
			
		||||
	// NOLINTEND
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue