Add Notification Action to copy body security codes to clipboard (#217)
This commit is contained in:
@@ -33,6 +33,7 @@ Post your setup here: [Config flex 💪](https://github.com/ErikReider/SwayNotif
|
|||||||
- Restores previous Do not disturb value after restart
|
- Restores previous Do not disturb value after restart
|
||||||
- Click notification to execute default action
|
- Click notification to execute default action
|
||||||
- Show alternative notification actions
|
- Show alternative notification actions
|
||||||
|
- Copy detected 2FA codes to clipboard
|
||||||
- Customization through a CSS file
|
- Customization through a CSS file
|
||||||
- Trackpad/mouse gesture to close notification
|
- Trackpad/mouse gesture to close notification
|
||||||
- The same features as any other basic notification daemon
|
- The same features as any other basic notification daemon
|
||||||
|
@@ -275,5 +275,16 @@ namespace SwayNotificationCenter {
|
|||||||
surface,
|
surface,
|
||||||
(double) buffer_width / 2 / scale - width / 2, 0);
|
(double) buffer_width / 2 / scale - width / 2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public delegate bool FilterFunc (char character);
|
||||||
|
|
||||||
|
public static string filter_string (string body, FilterFunc func) {
|
||||||
|
string result = "";
|
||||||
|
foreach (char char in (char[]) body.data) {
|
||||||
|
if (!func (char)) continue;
|
||||||
|
result += char.to_string ();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ namespace SwayNotificationCenter {
|
|||||||
[GtkChild]
|
[GtkChild]
|
||||||
unowned Gtk.Button close_button;
|
unowned Gtk.Button close_button;
|
||||||
|
|
||||||
private Gtk.ButtonBox alt_actions_box;
|
private Gtk.ButtonBox alt_actions_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
|
||||||
|
|
||||||
[GtkChild]
|
[GtkChild]
|
||||||
unowned Gtk.Label summary;
|
unowned Gtk.Label summary;
|
||||||
@@ -65,6 +65,8 @@ namespace SwayNotificationCenter {
|
|||||||
|
|
||||||
private int carousel_empty_widget_index = 0;
|
private int carousel_empty_widget_index = 0;
|
||||||
|
|
||||||
|
private static Regex code_regex;
|
||||||
|
|
||||||
private static Regex tag_regex;
|
private static Regex tag_regex;
|
||||||
private static Regex tag_unescape_regex;
|
private static Regex tag_unescape_regex;
|
||||||
private static Regex img_tag_regex;
|
private static Regex img_tag_regex;
|
||||||
@@ -103,6 +105,8 @@ namespace SwayNotificationCenter {
|
|||||||
|
|
||||||
construct {
|
construct {
|
||||||
try {
|
try {
|
||||||
|
code_regex = new Regex ("(?<= |^)(\\d{3}(-| )\\d{3}|\\d{4,7})(?= |$|\\.|,)",
|
||||||
|
RegexCompileFlags.MULTILINE);
|
||||||
string joined_tags = string.joinv ("|", TAGS);
|
string joined_tags = string.joinv ("|", TAGS);
|
||||||
tag_regex = new Regex ("<(/?(?:%s))>".printf (joined_tags));
|
tag_regex = new Regex ("<(/?(?:%s))>".printf (joined_tags));
|
||||||
string unescaped = string.joinv ("|", UNESCAPE_CHARS);
|
string unescaped = string.joinv ("|", UNESCAPE_CHARS);
|
||||||
@@ -287,14 +291,35 @@ namespace SwayNotificationCenter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the first code found, else null */
|
||||||
|
private string ? parse_body_codes () {
|
||||||
|
string body = this.body.get_text ().strip ();
|
||||||
|
if (body.length == 0) return null;
|
||||||
|
|
||||||
|
MatchInfo info;
|
||||||
|
var result = code_regex.match (body, RegexMatchFlags.NOTEMPTY, out info);
|
||||||
|
string ? match = info.fetch (0);
|
||||||
|
if (!result || match == null) return null;
|
||||||
|
|
||||||
|
return Functions.filter_string (
|
||||||
|
match.strip (), (c) => c.isdigit () || c.isspace ()).strip ();
|
||||||
|
}
|
||||||
|
|
||||||
public void click_default_action () {
|
public void click_default_action () {
|
||||||
action_clicked (param.default_action, true);
|
action_clicked (param.default_action, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void click_alt_action (uint index) {
|
public void click_alt_action (uint index) {
|
||||||
if (param.actions.length == 0 || index >= param.actions.length) {
|
List<weak Gtk.Widget>? children = alt_actions_box.get_children ();
|
||||||
|
uint length = children.length ();
|
||||||
|
if (length == 0 || index >= length) return;
|
||||||
|
|
||||||
|
unowned Gtk.Widget button = children.nth_data (index);
|
||||||
|
if (button is Gtk.Button) {
|
||||||
|
((Gtk.Button) button).clicked ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Backup if the above fails
|
||||||
action_clicked (param.actions.index (index));
|
action_clicked (param.actions.index (index));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,12 +356,31 @@ namespace SwayNotificationCenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void set_actions () {
|
private void set_actions () {
|
||||||
if (param.actions.length > 0) {
|
// Check for security codes
|
||||||
|
string ? code = parse_body_codes ();
|
||||||
|
if (param.actions.length > 0 || code != null) {
|
||||||
var viewport = new Gtk.Viewport (null, null);
|
var viewport = new Gtk.Viewport (null, null);
|
||||||
var scroll = new Gtk.ScrolledWindow (null, null);
|
var scroll = new Gtk.ScrolledWindow (null, null);
|
||||||
alt_actions_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
|
|
||||||
alt_actions_box.set_homogeneous (true);
|
alt_actions_box.set_homogeneous (true);
|
||||||
alt_actions_box.set_layout (Gtk.ButtonBoxStyle.EXPAND);
|
alt_actions_box.set_layout (Gtk.ButtonBoxStyle.EXPAND);
|
||||||
|
|
||||||
|
// Add "Copy code" Action if available and copy it to clipboard when clicked
|
||||||
|
if (code != null && code.length > 0) {
|
||||||
|
string action_name = "COPY \"%s\"".printf (code);
|
||||||
|
var action_button = new Gtk.Button.with_label (action_name);
|
||||||
|
action_button.clicked.connect (() => {
|
||||||
|
// Copy to clipboard
|
||||||
|
get_clipboard (Gdk.SELECTION_CLIPBOARD).set_text (code, -1);
|
||||||
|
// Dismiss notification
|
||||||
|
action_clicked (null);
|
||||||
|
});
|
||||||
|
action_button
|
||||||
|
.get_style_context ().add_class ("notification-action");
|
||||||
|
action_button.set_can_focus (false);
|
||||||
|
alt_actions_box.add (action_button);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add notification specified actions
|
||||||
foreach (var action in param.actions.data) {
|
foreach (var action in param.actions.data) {
|
||||||
var action_button = new Gtk.Button.with_label (action.name);
|
var action_button = new Gtk.Button.with_label (action.name);
|
||||||
action_button.clicked.connect (() => action_clicked (action));
|
action_button.clicked.connect (() => action_clicked (action));
|
||||||
@@ -466,7 +510,7 @@ namespace SwayNotificationCenter {
|
|||||||
|
|
||||||
uint timeout;
|
uint timeout;
|
||||||
switch (param.urgency) {
|
switch (param.urgency) {
|
||||||
case UrgencyLevels.LOW :
|
case UrgencyLevels.LOW:
|
||||||
timeout = timeout_low_delay * 1000;
|
timeout = timeout_low_delay * 1000;
|
||||||
break;
|
break;
|
||||||
case UrgencyLevels.NORMAL:
|
case UrgencyLevels.NORMAL:
|
||||||
|
Reference in New Issue
Block a user