Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inline replies to notifications #221

Merged
merged 11 commits into from
May 29, 2023
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Post your setup here: [Config flex 💪](https://github.com/ErikReider/SwayNotif

- Keyboard shortcuts
- Notification body markup with image support
- Inline replies
- A panel to view previous notifications
- Show album art for notifications like Spotify
- Do not disturb
Expand Down
1 change: 1 addition & 0 deletions src/config.json.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"control-center-margin-right": 0,
"control-center-margin-left": 0,
"notification-2fa-action": true,
"notification-inline-replies": false,
"notification-icon-size": 64,
"notification-body-image-height": 100,
"notification-body-image-width": 200,
Expand Down
6 changes: 6 additions & 0 deletions src/configModel/configModel.vala
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,12 @@ namespace SwayNotificationCenter {
*/
public bool notification_2fa_action { get; set; default = true; }

/**
* If notifications should display a text field to reply if the
* sender requests it.
*/
public bool notification_inline_replies { get; set; default = false; }

/**
* Notification icon size, in pixels.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/configSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@
"description": "If each notification should display a 'COPY \"1234\"' action",
"default": true
},
"notification-inline-replies": {
"type": "boolean",
"description": "If notifications should display a text field to reply if the sender requests it. NOTE: Replying in popup notifications is only available if the compositor supports GTK Layer-Shell ON_DEMAND keyboard interactivity.",
"default": false
},
"notification-icon-size": {
"type": "integer",
"description": "The notification icon size (in pixels)",
Expand Down
15 changes: 13 additions & 2 deletions src/controlCenter/controlCenter.vala
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ namespace SwayNotificationCenter {
// sometimes being passed through to unfucused application
// Ex: Firefox in a fullscreen YouTube video
this.key_release_event.connect ((w, event_key) => {
if (this.get_focus () is Gtk.Entry) {
switch (Gdk.keyval_name (event_key.keyval)) {
case "Escape":
this.set_focus (null);
return true;
}
return false;
}
if (event_key.type == Gdk.EventType.KEY_RELEASE) {
switch (Gdk.keyval_name (event_key.keyval)) {
case "Escape":
Expand All @@ -145,6 +153,7 @@ namespace SwayNotificationCenter {
});

this.key_press_event.connect ((w, event_key) => {
if (this.get_focus () is Gtk.Entry) return false;
if (event_key.type == Gdk.EventType.KEY_PRESS) {
var children = list_box.get_children ();
Notification noti = (Notification)
Expand Down Expand Up @@ -205,7 +214,7 @@ namespace SwayNotificationCenter {
}
navigate_list (list_position);
}
return true;
return false;
});

// Switches the stack page depending on the
Expand Down Expand Up @@ -464,7 +473,9 @@ namespace SwayNotificationCenter {

public void add_notification (NotifyParams param,
NotiDaemon noti_daemon) {
var noti = new Notification.regular (param, noti_daemon);
var noti = new Notification.regular (param,
noti_daemon,
NotificationType.CONTROL_CENTER);
noti.grab_focus.connect ((w) => {
uint i = list_box.get_children ().index (w);
if (list_position != uint.MAX && list_position != i) {
Expand Down
6 changes: 6 additions & 0 deletions src/main.vala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ namespace SwayNotificationCenter {
static string ? style_path;
static string ? config_path;

static uint layer_shell_protocol_version = 3;

static Settings self_settings;

public void main (string[] args) {
Expand Down Expand Up @@ -40,6 +42,10 @@ namespace SwayNotificationCenter {
ConfigModel.init (config_path);
Functions.load_css (style_path);

if (ConfigModel.instance.layer_shell) {
layer_shell_protocol_version = GtkLayerShell.get_protocol_version ();
}

swaync_daemon = new SwayncDaemon ();
Bus.own_name (BusType.SESSION, "org.erikreider.swaync.cc",
BusNameOwnerFlags.NONE,
Expand Down
4 changes: 4 additions & 0 deletions src/notiDaemon/notiDaemon.vala
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ namespace SwayNotificationCenter {
"synchronous",
"private-synchronous",
"x-canonical-private-synchronous",
"inline-reply",
};
}

Expand Down Expand Up @@ -339,5 +340,8 @@ namespace SwayNotificationCenter {
* support the concept of being able to "invoke" a notification.
*/
public signal void ActionInvoked (uint32 id, string action_key);

/** To be used by the non-standard "inline-reply" capability */
public signal void NotificationReplied (uint32 id, string text);
}
}
66 changes: 44 additions & 22 deletions src/notiModel/notiModel.vala
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ namespace SwayNotificationCenter {
private int priv_value { private get; private set; }
public bool has_synch { public get; private set; }

/** Inline-replies */
public Action ? inline_reply { get; set; }
public string ? inline_reply_placeholder { get; set; }

// Custom hints
/** Disables scripting for notification */
public bool swaync_no_script { get; set; }
Expand Down Expand Up @@ -133,30 +137,12 @@ namespace SwayNotificationCenter {
this.replaces = false;
this.has_synch = false;

s_hints ();

Array<Action> ac_array = new Array<Action> ();
if (actions.length > 1 && actions.length % 2 == 0) {
for (int i = 0; i < actions.length; i++) {
var action = new Action ();
action.identifier = actions[i];
action.name = actions[i + 1];
if (action.name != null && action.identifier != null
&& action.name != "" && action.identifier != "") {
parse_hints ();

if (action.identifier.down () == "default") {
default_action = action;
} else {
ac_array.append_val (action);
}
}
i++;
}
}
this.actions = ac_array;
parse_actions (actions);
}

private void s_hints () {
private void parse_hints () {
foreach (var hint in hints.get_keys ()) {
Variant hint_value = hints[hint];
switch (hint) {
Expand Down Expand Up @@ -239,12 +225,46 @@ namespace SwayNotificationCenter {
urgency = UrgencyLevels.from_value (hint_value.get_byte ());
}
break;
case "x-kde-reply-placeholder-text":
if (hint_value.is_of_type (VariantType.STRING)) {
inline_reply_placeholder = hint_value.get_string ();
}
break;
}
}
}

private void parse_actions (string[] actions) {
Array<Action> parsed_actions = new Array<Action> ();
if (actions.length > 1 && actions.length % 2 == 0) {
for (int i = 0; i < actions.length; i++) {
var action = new Action ();
action.identifier = actions[i];
action.name = actions[i + 1];
if (action.name != null && action.identifier != null
&& action.name != "" && action.identifier != "") {

string id = action.identifier.down ();
switch (id) {
case "default":
default_action = action;
break;
case "inline-reply":
inline_reply = action;
break;
default:
parsed_actions.append_val (action);
break;
}
}
i++;
}
}
this.actions = parsed_actions;
}

public string to_string () {
var params = new HashTable<string, string ? > (str_hash, str_equal);
var params = new HashTable<string, string ?> (str_hash, str_equal);

params.set ("applied_id", applied_id.to_string ());
params.set ("app_name", app_name);
Expand Down Expand Up @@ -280,6 +300,8 @@ namespace SwayNotificationCenter {
_actions += "\n\t" + _action.to_string ();
}
params.set ("actions", string.joinv ("", _actions));
params.set ("inline-reply", inline_reply == null
? null : inline_reply.to_string ());

string[] result = {};
foreach (var k in params.get_keys ()) {
Expand Down
49 changes: 46 additions & 3 deletions src/notification/notification.ui
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<!-- Generated with glade 3.40.0 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<requires lib="libhandy" version="1.2"/>
Expand Down Expand Up @@ -45,10 +45,10 @@
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkButton" id="default_button">
<object class="GtkEventBox" id="default_action">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="receives-default">False</property>
<property name="events">GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
Expand Down Expand Up @@ -192,6 +192,49 @@
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="inline_reply_box">
<property name="can-focus">False</property>
<child>
<object class="GtkEntry" id="inline_reply_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="input-hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_EMOJI | GTK_INPUT_HINT_NONE</property>
<style>
<class name="inline-reply-entry"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="inline_reply_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<style>
<class name="inline-reply-button"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="inline-reply"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<style>
<class name="notification-content"/>
</style>
Expand Down
Loading