Add inline replies to notifications (#221)

This commit is contained in:
Erik Reider 2023-05-29 15:08:51 +02:00 committed by GitHub
parent 4aefd3aabd
commit ba4a2665fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 355 additions and 40 deletions

View File

@ -56,6 +56,7 @@ Post your setup here: [Config flex 💪](https://github.com/ErikReider/SwayNotif
- Keyboard shortcuts - Keyboard shortcuts
- Notification body markup with image support - Notification body markup with image support
- Inline replies
- A panel to view previous notifications - A panel to view previous notifications
- Show album art for notifications like Spotify - Show album art for notifications like Spotify
- Do not disturb - Do not disturb

View File

@ -11,6 +11,7 @@
"control-center-margin-right": 0, "control-center-margin-right": 0,
"control-center-margin-left": 0, "control-center-margin-left": 0,
"notification-2fa-action": true, "notification-2fa-action": true,
"notification-inline-replies": false,
"notification-icon-size": 64, "notification-icon-size": 64,
"notification-body-image-height": 100, "notification-body-image-height": 100,
"notification-body-image-width": 200, "notification-body-image-width": 200,

View File

@ -555,6 +555,12 @@ namespace SwayNotificationCenter {
*/ */
public bool notification_2fa_action { get; set; default = true; } 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. * Notification icon size, in pixels.
*/ */

View File

@ -80,6 +80,11 @@
"description": "If each notification should display a 'COPY \"1234\"' action", "description": "If each notification should display a 'COPY \"1234\"' action",
"default": true "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": { "notification-icon-size": {
"type": "integer", "type": "integer",
"description": "The notification icon size (in pixels)", "description": "The notification icon size (in pixels)",

View File

@ -133,6 +133,14 @@ namespace SwayNotificationCenter {
// sometimes being passed through to unfucused application // sometimes being passed through to unfucused application
// Ex: Firefox in a fullscreen YouTube video // Ex: Firefox in a fullscreen YouTube video
this.key_release_event.connect ((w, event_key) => { 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) { if (event_key.type == Gdk.EventType.KEY_RELEASE) {
switch (Gdk.keyval_name (event_key.keyval)) { switch (Gdk.keyval_name (event_key.keyval)) {
case "Escape": case "Escape":
@ -145,6 +153,7 @@ namespace SwayNotificationCenter {
}); });
this.key_press_event.connect ((w, event_key) => { 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) { if (event_key.type == Gdk.EventType.KEY_PRESS) {
var children = list_box.get_children (); var children = list_box.get_children ();
Notification noti = (Notification) Notification noti = (Notification)
@ -205,7 +214,7 @@ namespace SwayNotificationCenter {
} }
navigate_list (list_position); navigate_list (list_position);
} }
return true; return false;
}); });
// Switches the stack page depending on the // Switches the stack page depending on the
@ -464,7 +473,9 @@ namespace SwayNotificationCenter {
public void add_notification (NotifyParams param, public void add_notification (NotifyParams param,
NotiDaemon noti_daemon) { 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) => { noti.grab_focus.connect ((w) => {
uint i = list_box.get_children ().index (w); uint i = list_box.get_children ().index (w);
if (list_position != uint.MAX && list_position != i) { if (list_position != uint.MAX && list_position != i) {

View File

@ -3,6 +3,8 @@ namespace SwayNotificationCenter {
static string ? style_path; static string ? style_path;
static string ? config_path; static string ? config_path;
static uint layer_shell_protocol_version = 3;
static Settings self_settings; static Settings self_settings;
public void main (string[] args) { public void main (string[] args) {
@ -40,6 +42,10 @@ namespace SwayNotificationCenter {
ConfigModel.init (config_path); ConfigModel.init (config_path);
Functions.load_css (style_path); Functions.load_css (style_path);
if (ConfigModel.instance.layer_shell) {
layer_shell_protocol_version = GtkLayerShell.get_protocol_version ();
}
swaync_daemon = new SwayncDaemon (); swaync_daemon = new SwayncDaemon ();
Bus.own_name (BusType.SESSION, "org.erikreider.swaync.cc", Bus.own_name (BusType.SESSION, "org.erikreider.swaync.cc",
BusNameOwnerFlags.NONE, BusNameOwnerFlags.NONE,

View File

@ -113,6 +113,7 @@ namespace SwayNotificationCenter {
"synchronous", "synchronous",
"private-synchronous", "private-synchronous",
"x-canonical-private-synchronous", "x-canonical-private-synchronous",
"inline-reply",
}; };
} }
@ -339,5 +340,8 @@ namespace SwayNotificationCenter {
* support the concept of being able to "invoke" a notification. * support the concept of being able to "invoke" a notification.
*/ */
public signal void ActionInvoked (uint32 id, string action_key); 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);
} }
} }

View File

@ -102,6 +102,10 @@ namespace SwayNotificationCenter {
private int priv_value { private get; private set; } private int priv_value { private get; private set; }
public bool has_synch { public 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 // Custom hints
/** Disables scripting for notification */ /** Disables scripting for notification */
public bool swaync_no_script { get; set; } public bool swaync_no_script { get; set; }
@ -133,30 +137,12 @@ namespace SwayNotificationCenter {
this.replaces = false; this.replaces = false;
this.has_synch = false; this.has_synch = false;
s_hints (); parse_hints ();
Array<Action> ac_array = new Array<Action> (); parse_actions (actions);
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 != "") {
if (action.identifier.down () == "default") {
default_action = action;
} else {
ac_array.append_val (action);
}
}
i++;
}
}
this.actions = ac_array;
} }
private void s_hints () { private void parse_hints () {
foreach (var hint in hints.get_keys ()) { foreach (var hint in hints.get_keys ()) {
Variant hint_value = hints[hint]; Variant hint_value = hints[hint];
switch (hint) { switch (hint) {
@ -239,12 +225,46 @@ namespace SwayNotificationCenter {
urgency = UrgencyLevels.from_value (hint_value.get_byte ()); urgency = UrgencyLevels.from_value (hint_value.get_byte ());
} }
break; 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 () { 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 ("applied_id", applied_id.to_string ());
params.set ("app_name", app_name); params.set ("app_name", app_name);
@ -280,6 +300,8 @@ namespace SwayNotificationCenter {
_actions += "\n\t" + _action.to_string (); _actions += "\n\t" + _action.to_string ();
} }
params.set ("actions", string.joinv ("", _actions)); params.set ("actions", string.joinv ("", _actions));
params.set ("inline-reply", inline_reply == null
? null : inline_reply.to_string ());
string[] result = {}; string[] result = {};
foreach (var k in params.get_keys ()) { foreach (var k in params.get_keys ()) {

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 --> <!-- Generated with glade 3.40.0 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk+" version="3.24"/>
<requires lib="libhandy" version="1.2"/> <requires lib="libhandy" version="1.2"/>
@ -45,10 +45,10 @@
<property name="can-focus">False</property> <property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkButton" id="default_button"> <object class="GtkEventBox" id="default_action">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</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> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property> <property name="visible">True</property>
@ -192,6 +192,49 @@
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </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> <style>
<class name="notification-content"/> <class name="notification-content"/>
</style> </style>

View File

@ -1,4 +1,7 @@
namespace SwayNotificationCenter { namespace SwayNotificationCenter {
public enum NotificationType { CONTROL_CENTER, POPUP }
[GtkTemplate (ui = "/org/erikreider/sway-notification-center/notification/notification.ui")] [GtkTemplate (ui = "/org/erikreider/sway-notification-center/notification/notification.ui")]
public class Notification : Gtk.ListBoxRow { public class Notification : Gtk.ListBoxRow {
[GtkChild] [GtkChild]
@ -10,7 +13,11 @@ namespace SwayNotificationCenter {
unowned Gtk.EventBox event_box; unowned Gtk.EventBox event_box;
[GtkChild] [GtkChild]
unowned Gtk.Button default_button; unowned Gtk.EventBox default_action;
/** The default_action gesture. Allows clicks while not in swipe gesture. */
private Gtk.GestureMultiPress gesture;
[GtkChild] [GtkChild]
unowned Gtk.ProgressBar progress_bar; unowned Gtk.ProgressBar progress_bar;
@ -36,6 +43,17 @@ namespace SwayNotificationCenter {
[GtkChild] [GtkChild]
unowned Gtk.Image body_image; unowned Gtk.Image body_image;
// Inline Reply
[GtkChild]
unowned Gtk.Box inline_reply_box;
[GtkChild]
unowned Gtk.Entry inline_reply_entry;
[GtkChild]
unowned Gtk.Button inline_reply_button;
private bool default_action_down = false;
private bool default_action_in = false;
public static Gtk.IconSize icon_size = Gtk.IconSize.INVALID; public static Gtk.IconSize icon_size = Gtk.IconSize.INVALID;
private int notification_icon_size { get; default = ConfigModel.instance.notification_icon_size; } private int notification_icon_size { get; default = ConfigModel.instance.notification_icon_size; }
@ -55,6 +73,12 @@ namespace SwayNotificationCenter {
public NotifyParams param { get; construct; } public NotifyParams param { get; construct; }
public NotiDaemon noti_daemon { get; construct; } public NotiDaemon noti_daemon { get; construct; }
public NotificationType notification_type {
get;
construct;
default = NotificationType.POPUP;
}
public uint timeout_delay { get; construct; } public uint timeout_delay { get; construct; }
public uint timeout_low_delay { get; construct; } public uint timeout_low_delay { get; construct; }
public uint timeout_critical_delay { get; construct; } public uint timeout_critical_delay { get; construct; }
@ -63,6 +87,8 @@ namespace SwayNotificationCenter {
public int number_of_body_lines { get; construct; default = 10; } public int number_of_body_lines { get; construct; default = 10; }
public bool has_inline_reply { get; private set; default = false; }
private int carousel_empty_widget_index = 0; private int carousel_empty_widget_index = 0;
private static Regex code_regex; private static Regex code_regex;
@ -83,18 +109,23 @@ namespace SwayNotificationCenter {
/** Show a non-timed notification */ /** Show a non-timed notification */
public Notification.regular (NotifyParams param, public Notification.regular (NotifyParams param,
NotiDaemon noti_daemon) { NotiDaemon noti_daemon,
Object (noti_daemon: noti_daemon, param: param); NotificationType notification_type) {
Object (noti_daemon: noti_daemon,
param: param,
notification_type: notification_type);
} }
/** Show a timed notification */ /** Show a timed notification */
public Notification.timed (NotifyParams param, public Notification.timed (NotifyParams param,
NotiDaemon noti_daemon, NotiDaemon noti_daemon,
NotificationType notification_type,
uint timeout, uint timeout,
uint timeout_low, uint timeout_low,
uint timeout_critical) { uint timeout_critical) {
Object (noti_daemon: noti_daemon, Object (noti_daemon: noti_daemon,
param: param, param: param,
notification_type: notification_type,
is_timed: true, is_timed: true,
timeout_delay: timeout, timeout_delay: timeout,
timeout_low_delay: timeout_low, timeout_low_delay: timeout_low,
@ -116,6 +147,54 @@ namespace SwayNotificationCenter {
stderr.printf ("Invalid regex: %s", e.message); stderr.printf ("Invalid regex: %s", e.message);
} }
// Build the default_action gesture. Makes clickes compatible with
// the Hdy Swipe gesture unlike a regular ::button_release_event
gesture = new Gtk.GestureMultiPress (default_action);
gesture.set_touch_only (false);
gesture.set_exclusive (true);
gesture.set_button (Gdk.BUTTON_PRIMARY);
gesture.set_propagation_phase (Gtk.PropagationPhase.BUBBLE);
gesture.pressed.connect ((_gesture, _n_press, _x, _y) => {
default_action_in = true;
default_action_down = true;
default_action_update_state ();
});
gesture.released.connect ((gesture, _n_press, _x, _y) => {
// Emit released
if (!default_action_down) return;
default_action_down = false;
if (default_action_in) {
click_default_action ();
}
Gdk.EventSequence ? sequence = gesture.get_current_sequence ();
if (sequence == null) {
default_action_in = false;
default_action_update_state ();
}
});
gesture.update.connect ((gesture, sequence) => {
Gtk.GestureSingle gesture_single = (Gtk.GestureSingle) gesture;
if (sequence != gesture_single.get_current_sequence ()) return;
Gtk.Allocation allocation;
double x, y;
default_action.get_allocation (out allocation);
gesture.get_point (sequence, out x, out y);
bool in_button = (x >= 0 && y >= 0 && x < allocation.width && y < allocation.height);
if (default_action_in != in_button) {
default_action_in = in_button;
default_action_update_state ();
}
});
gesture.cancel.connect ((_gesture, _sequence) => {
if (default_action_down) {
default_action_down = false;
default_action_update_state ();
}
});
this.transition_time = ConfigModel.instance.transition_time; this.transition_time = ConfigModel.instance.transition_time;
build_noti (); build_noti ();
@ -125,6 +204,18 @@ namespace SwayNotificationCenter {
} }
} }
private void default_action_update_state () {
bool pressed = default_action_in && default_action_down;
Gtk.StateFlags flags = default_action.get_state_flags () &
~(Gtk.StateFlags.PRELIGHT | Gtk.StateFlags.ACTIVE);
if (default_action_in) flags |= Gtk.StateFlags.PRELIGHT;
if (pressed) flags |= Gtk.StateFlags.ACTIVE;
default_action.set_state_flags (flags, true);
}
private void on_size_allocation (Gtk.Allocation _ignored) { private void on_size_allocation (Gtk.Allocation _ignored) {
// Force recomputing the allocated size of the wrapped GTK label in the body. // Force recomputing the allocated size of the wrapped GTK label in the body.
// `queue_resize` alone DOES NOT WORK because it does not properly invalidate // `queue_resize` alone DOES NOT WORK because it does not properly invalidate
@ -151,13 +242,31 @@ namespace SwayNotificationCenter {
return true; return true;
}); });
default_button.clicked.connect (click_default_action); // Adds CSS :hover selector to EventBox
default_action.enter_notify_event.connect ((event) => {
if (event.detail != Gdk.NotifyType.INFERIOR
&& event.window == default_action.get_window ()) {
default_action_in = true;
default_action_update_state ();
}
return true;
});
default_action.leave_notify_event.connect ((event) => {
if (event.detail != Gdk.NotifyType.INFERIOR
&& event.window == default_action.get_window ()) {
default_action_in = false;
default_action_update_state ();
}
return true;
});
default_action.unmap.connect (() => default_action_in = false);
close_revealer.set_transition_duration (this.transition_time); close_revealer.set_transition_duration (this.transition_time);
close_button.clicked.connect (() => close_notification ()); close_button.clicked.connect (() => close_notification ());
this.event_box.enter_notify_event.connect (() => { this.event_box.enter_notify_event.connect ((event) => {
close_revealer.set_reveal_child (true); close_revealer.set_reveal_child (true);
remove_noti_timeout (); remove_noti_timeout ();
return false; return false;
@ -207,6 +316,7 @@ namespace SwayNotificationCenter {
set_body (); set_body ();
set_icon (); set_icon ();
set_inline_reply ();
set_actions (); set_actions ();
set_style_urgency (); set_style_urgency ();
@ -311,7 +421,7 @@ namespace SwayNotificationCenter {
} }
public void click_alt_action (uint index) { public void click_alt_action (uint index) {
List<weak Gtk.Widget>? children = alt_actions_box.get_children (); List<weak Gtk.Widget> ? children = alt_actions_box.get_children ();
uint length = children.length (); uint length = children.length ();
if (length == 0 || index >= length) return; if (length == 0 || index >= length) return;
@ -356,6 +466,54 @@ namespace SwayNotificationCenter {
} }
} }
private void set_inline_reply () {
// Only show inline replies in popup notifications if the compositor
// supports ON_DEMAND layer shell keyboard interactivity
if (!ConfigModel.instance.notification_inline_replies
|| (ConfigModel.instance.layer_shell
&& layer_shell_protocol_version < 4
&& notification_type == NotificationType.POPUP)) {
return;
}
if (param.inline_reply == null) return;
has_inline_reply = true;
inline_reply_box.show ();
inline_reply_entry.set_placeholder_text (
param.inline_reply_placeholder ?? "Enter Text");
// Set reply Button sensitivity to disabled if Entry text is empty
inline_reply_entry.bind_property (
"text",
inline_reply_button, "sensitive",
BindingFlags.SYNC_CREATE,
(binding, srcval, ref targetval) => {
targetval.set_boolean (((string) srcval).strip ().length > 0);
return true;
},
null);
inline_reply_entry.key_release_event.connect ((w, event_key) => {
switch (Gdk.keyval_name (event_key.keyval)) {
case "Return":
inline_reply_button.clicked ();
return true;
default:
return false;
}
});
inline_reply_button.set_label (param.inline_reply.name ?? "Reply");
inline_reply_button.clicked.connect (() => {
string text = inline_reply_entry.get_text ().strip ();
if (text.length == 0) return;
noti_daemon.NotificationReplied (param.applied_id, text);
// Dismiss notification without activating Action
action_clicked (null);
});
}
private void set_actions () { private void set_actions () {
// Check for security codes // Check for security codes
string ? code = parse_body_codes (); string ? code = parse_body_codes ();
@ -543,6 +701,7 @@ namespace SwayNotificationCenter {
/** Forces the EventBox to reload its style_context #27 */ /** Forces the EventBox to reload its style_context #27 */
public void reload_style_context () { public void reload_style_context () {
event_box.get_style_context ().changed (); event_box.get_style_context ().changed ();
default_action.get_style_context ().changed ();
} }
} }
} }

View File

@ -40,6 +40,8 @@ namespace SwayNotificationCenter {
private double last_upper = 0; private double last_upper = 0;
Gee.HashSet<uint32> inline_reply_notifications = new Gee.HashSet<uint32> ();
private const int MAX_HEIGHT = 600; private const int MAX_HEIGHT = 600;
private NotificationWindow () { private NotificationWindow () {
@ -158,6 +160,7 @@ namespace SwayNotificationCenter {
public delegate bool remove_iter_func (Notification notification); public delegate bool remove_iter_func (Notification notification);
public void close_all_notifications (remove_iter_func ? func = null) { public void close_all_notifications (remove_iter_func ? func = null) {
inline_reply_notifications.clear ();
if (!this.get_realized ()) return; if (!this.get_realized ()) return;
foreach (var w in box.get_children ()) { foreach (var w in box.get_children ()) {
Notification notification = (Notification) w; Notification notification = (Notification) w;
@ -170,6 +173,17 @@ namespace SwayNotificationCenter {
private void remove_notification (Notification ? noti, bool replaces) { private void remove_notification (Notification ? noti, bool replaces) {
// Remove notification and its destruction timeout // Remove notification and its destruction timeout
if (noti != null) { if (noti != null) {
#if HAVE_LATEST_GTK_LAYER_SHELL
if (noti.has_inline_reply) {
inline_reply_notifications.remove (noti.param.applied_id);
if (inline_reply_notifications.size == 0
&& GtkLayerShell.get_keyboard_mode (this)
!= GtkLayerShell.KeyboardMode.NONE) {
GtkLayerShell.set_keyboard_mode (
this, GtkLayerShell.KeyboardMode.NONE);
}
}
#endif
noti.remove_noti_timeout (); noti.remove_noti_timeout ();
noti.destroy (); noti.destroy ();
} }
@ -188,9 +202,21 @@ namespace SwayNotificationCenter {
NotiDaemon noti_daemon) { NotiDaemon noti_daemon) {
var noti = new Notification.timed (param, var noti = new Notification.timed (param,
noti_daemon, noti_daemon,
NotificationType.POPUP,
ConfigModel.instance.timeout, ConfigModel.instance.timeout,
ConfigModel.instance.timeout_low, ConfigModel.instance.timeout_low,
ConfigModel.instance.timeout_critical); ConfigModel.instance.timeout_critical);
#if HAVE_LATEST_GTK_LAYER_SHELL
if (noti.has_inline_reply) {
inline_reply_notifications.add (param.applied_id);
if (GtkLayerShell.get_keyboard_mode (this)
!= GtkLayerShell.KeyboardMode.ON_DEMAND) {
GtkLayerShell.set_keyboard_mode (
this, GtkLayerShell.KeyboardMode.ON_DEMAND);
}
}
#endif
if (list_reverse) { if (list_reverse) {
box.pack_start (noti); box.pack_start (noti);

View File

@ -6,11 +6,15 @@
@define-color noti-border-color rgba(255, 255, 255, 0.15); @define-color noti-border-color rgba(255, 255, 255, 0.15);
@define-color noti-bg rgb(48, 48, 48); @define-color noti-bg rgb(48, 48, 48);
@define-color noti-bg-darker rgb(38, 38, 38);
@define-color noti-bg-hover rgb(56, 56, 56); @define-color noti-bg-hover rgb(56, 56, 56);
@define-color noti-bg-focus rgba(68, 68, 68, 0.6); @define-color noti-bg-focus rgba(68, 68, 68, 0.6);
@define-color noti-close-bg rgba(255, 255, 255, 0.1); @define-color noti-close-bg rgba(255, 255, 255, 0.1);
@define-color noti-close-bg-hover rgba(255, 255, 255, 0.15); @define-color noti-close-bg-hover rgba(255, 255, 255, 0.15);
@define-color text-color rgb(255, 255, 255);
@define-color text-color-disabled rgb(150, 150, 150);
@define-color bg-selected rgb(0, 128, 255); @define-color bg-selected rgb(0, 128, 255);
.notification-row { .notification-row {
@ -58,7 +62,7 @@
.close-button { .close-button {
background: @noti-close-bg; background: @noti-close-bg;
color: white; color: @text-color;
text-shadow: none; text-shadow: none;
padding: 0; padding: 0;
border-radius: 100%; border-radius: 100%;
@ -84,7 +88,8 @@
box-shadow: none; box-shadow: none;
background: @noti-bg; background: @noti-bg;
border: 1px solid @noti-border-color; border: 1px solid @noti-border-color;
color: white; color: @text-color;
transition: all 0.15s ease-in-out;
} }
.notification-default-action:hover, .notification-default-action:hover,
@ -119,6 +124,32 @@
border-right: 1px solid @noti-border-color; border-right: 1px solid @noti-border-color;
} }
.inline-reply {
margin-top: 8px;
}
.inline-reply-entry {
background: @noti-bg-darker;
color: @text-color;
caret-color: @text-color;
border: 1px solid @noti-border-color;
border-radius: 12px;
}
.inline-reply-button {
margin-left: 4px;
background: @noti-bg;
border: 1px solid @noti-border-color;
border-radius: 12px;
color: @text-color;
}
.inline-reply-button:disabled {
background: initial;
color: @text-color-disabled;
border: 1px solid transparent;
}
.inline-reply-button:hover {
background: @noti-bg-hover;
}
.image { .image {
} }
@ -132,7 +163,7 @@
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
background: transparent; background: transparent;
color: white; color: @text-color;
text-shadow: none; text-shadow: none;
} }
@ -140,7 +171,7 @@
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
background: transparent; background: transparent;
color: white; color: @text-color;
text-shadow: none; text-shadow: none;
margin-right: 18px; margin-right: 18px;
} }
@ -149,7 +180,7 @@
font-size: 15px; font-size: 15px;
font-weight: normal; font-weight: normal;
background: transparent; background: transparent;
color: white; color: @text-color;
text-shadow: none; text-shadow: none;
} }
@ -183,7 +214,7 @@
} }
.widget-title > button { .widget-title > button {
font-size: initial; font-size: initial;
color: white; color: @text-color;
text-shadow: none; text-shadow: none;
background: @noti-bg; background: @noti-bg;
border: 1px solid @noti-border-color; border: 1px solid @noti-border-color;
@ -318,7 +349,7 @@
} }
.widget-inhibitors > button { .widget-inhibitors > button {
font-size: initial; font-size: initial;
color: white; color: @text-color;
text-shadow: none; text-shadow: none;
background: @noti-bg; background: @noti-bg;
border: 1px solid @noti-border-color; border: 1px solid @noti-border-color;