Add support for custom actions on notification

This commit is contained in:
LAGonauta 2020-11-26 18:50:03 -03:00
parent 08f2391acc
commit d8bb9897a4
6 changed files with 186 additions and 90 deletions

View file

@ -6,9 +6,40 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef void(*dinoWinToastLibNotificationCallback)(int conv_id, void* userdata); typedef enum {
DINOWINTOASTLIB_API int dinoWinToastLibInit(); Reason_Activated = 0,
DINOWINTOASTLIB_API int dinoWinToastLibShowMessage(dino_wintoasttemplate templ, int conv_id, dinoWinToastLibNotificationCallback click_callback, void* callback_target); Reason_ApplicationHidden,
Reason_TimedOut
} dinoWinToastLib_Notification_Reason;
typedef void(*dinoWinToastLib_Notification_Callback_Simple)(void* userdata);
typedef void(*dinoWinToastLib_Notification_Callback_ActivatedWithActionIndex)(int action_id, void* userdata);
typedef void(*dinoWinToastLib_Notification_Callback_Dismissed)(dinoWinToastLib_Notification_Reason reason, void* userdata);
typedef struct {
dinoWinToastLib_Notification_Callback_Simple activated;
void* activated_context;
void(*activated_free)(void*);
dinoWinToastLib_Notification_Callback_ActivatedWithActionIndex activatedWithIndex;
void* activatedWithIndex_context;
void(*activatedWithIndex_free)(void*);
dinoWinToastLib_Notification_Callback_Dismissed dismissed;
void* dismissed_context;
void(*dismissed_free)(void*);
dinoWinToastLib_Notification_Callback_Simple failed;
void* failed_context;
void(*failed_free)(void*);
} dinoWinToastLib_Notification_Callbacks;
DINOWINTOASTLIB_API dinoWinToastLib_Notification_Callbacks* dinoWinToastLib_NewCallbacks();
DINOWINTOASTLIB_API void dinoWinToastLib_DestroyCallbacks(dinoWinToastLib_Notification_Callbacks* callbacks);
DINOWINTOASTLIB_API int dinoWinToastLib_Init();
DINOWINTOASTLIB_API int dinoWinToastLib_ShowMessage(dino_wintoasttemplate templ, dinoWinToastLib_Notification_Callbacks* callbacks);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View file

@ -9,33 +9,33 @@ extern "C" {
typedef void* dino_wintoasttemplate; typedef void* dino_wintoasttemplate;
typedef enum { typedef enum {
System, Duration_System,
Short, Duration_Short,
Long Duration_Long
} dino_wintoasttemplate_duration; } dino_wintoasttemplate_duration;
typedef enum { typedef enum {
Default = 0, AudioOption_Default = 0,
Silent = 1, AudioOption_Silent = 1,
Loop = 2 AudioOption_Loop = 2
} dino_wintoasttemplate_audiooption; } dino_wintoasttemplate_audiooption;
typedef enum { typedef enum {
FirstLine = 0, TextField_FirstLine = 0,
SecondLine, TextField_SecondLine,
ThirdLine TextField_ThirdLine
} dino_wintoasttemplate_textfield; } dino_wintoasttemplate_textfield;
typedef enum { typedef enum {
ImageAndText01 = 0, TemplateType_ImageAndText01 = 0,
ImageAndText02, TemplateType_ImageAndText02,
ImageAndText03, TemplateType_ImageAndText03,
ImageAndText04, TemplateType_ImageAndText04,
Text01, TemplateType_Text01,
Text02, TemplateType_Text02,
Text03, TemplateType_Text03,
Text04, TemplateType_Text04,
WinToastTemplateTypeCount TemplateType_WinToastTemplateTypeCount
} dino_wintoasttemplate_wintoasttemplatetype; } dino_wintoasttemplate_wintoasttemplatetype;
DINOWINTOASTLIB_API dino_wintoasttemplate dino_wintoasttemplate_new(dino_wintoasttemplate_wintoasttemplatetype templ); DINOWINTOASTLIB_API dino_wintoasttemplate dino_wintoasttemplate_new(dino_wintoasttemplate_wintoasttemplatetype templ);

View file

@ -2,6 +2,7 @@ using Dino;
using Dino.Entities; using Dino.Entities;
using DinoWinToast; using DinoWinToast;
using Xmpp; using Xmpp;
using Gee;
namespace Dino.Plugins.WindowsNotification { namespace Dino.Plugins.WindowsNotification {
public class WindowsNotificationProvider : NotificationProvider, Object { public class WindowsNotificationProvider : NotificationProvider, Object {
@ -50,33 +51,37 @@ namespace Dino.Plugins.WindowsNotification {
string summary = _("Subscription request"); string summary = _("Subscription request");
string body = Markup.escape_text(conversation.counterpart.to_string()); string body = Markup.escape_text(conversation.counterpart.to_string());
if (!show_message(summary, body, get_avatar(conversation), conversation.id, stub)) { // missing actions DinoWinToastTemplate template;
var image_path = get_avatar(conversation);
if (image_path != null) {
template = new DinoWinToastTemplate(TemplateType.ImageAndText02);
template.setImagePath(image_path);
} else {
template = new DinoWinToastTemplate(TemplateType.Text02);
}
template.setTextField(summary, TextField.FirstLine);
template.setTextField(body, TextField.SecondLine);
template.addAction(_("Accept"));
template.addAction(_("Deny"));
var callbacks = new Callbacks();
callbacks.activated = () => {
app.activate_action("open-conversation", conversation.id);
};
callbacks.activatedWithIndex = (index) => {
if (index == 0) {
app.activate_action("accept-subscription", conversation.id);
} else if (index == 1) {
app.activate_action("deny-subscription", conversation.id);
}
};
if (!ShowMessage(template, callbacks) == 0) {
warning("Failed showing subscription request notification"); warning("Failed showing subscription request notification");
} }
// HashTable<string, Variant> hash_table = new HashTable<string, Variant>(null, null);
// hash_table["image-data"] = yield get_conversation_icon(conversation);
// string[] actions = new string[] {"default", "Open conversation", "accept", _("Accept"), "deny", _("Deny")};
// try {
// uint32 notification_id = dbus_notifications.notify("Dino", 0, "", summary, body, actions, hash_table, 0);
// if (!conversation_notifications.has_key(conversation)) {
// conversation_notifications[conversation] = new ArrayList<uint32>();
// }
// conversation_notifications[conversation].add(notification_id);
// add_action_listener(notification_id, "default", () => {
// GLib.Application.get_default().activate_action("open-conversation", new Variant.int32(conversation.id));
// });
// add_action_listener(notification_id, "accept", () => {
// GLib.Application.get_default().activate_action("accept-subscription", new Variant.int32(conversation.id));
// });
// add_action_listener(notification_id, "deny", () => {
// GLib.Application.get_default().activate_action("deny-subscription", new Variant.int32(conversation.id));
// });
// } catch (Error e) {
// warning("Failed showing subscription request notification: %s", e.message);
// }
} }
public async void notify_connection_error(Account account, ConnectionManager.ConnectionError error) { public async void notify_connection_error(Account account, ConnectionManager.ConnectionError error) {
@ -97,7 +102,7 @@ namespace Dino.Plugins.WindowsNotification {
break; break;
} }
if (!show_message(summary, body, null, 0, stub)) { if (!show_message(summary, body, null, null)) {
warning("Failed showing connection error notification"); warning("Failed showing connection error notification");
} }
} }
@ -109,15 +114,39 @@ namespace Dino.Plugins.WindowsNotification {
string summary = _("Invitation to %s").printf(display_room); string summary = _("Invitation to %s").printf(display_room);
string body = _("%s invited you to %s").printf(inviter_display_name, display_room); string body = _("%s invited you to %s").printf(inviter_display_name, display_room);
DinoWinToastTemplate template;
var image_path = get_avatar(conversation);
if (image_path != null) {
template = new DinoWinToastTemplate(TemplateType.ImageAndText02);
template.setImagePath(image_path);
} else {
template = new DinoWinToastTemplate(TemplateType.Text02);
}
template.setTextField(summary, TextField.FirstLine);
template.setTextField(body, TextField.SecondLine);
template.addAction(_("Accept"));
template.addAction(_("Deny"));
Conversation group_conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(room_jid, account, Conversation.Type.GROUPCHAT); Conversation group_conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(room_jid, account, Conversation.Type.GROUPCHAT);
if (!show_message(summary, body, get_avatar(direct_conversation), group_conversation.id, stub)) { // action not enabled yet var callbacks = new Callbacks();
callbacks.activated = () => {
app.activate_action("open-muc-join", group_conversation.id);
};
callbacks.activatedWithIndex = (index) => {
if (index == 0) {
app.activate_action("deny-invite", group_conversation.id);
} else if (index == 1) {
app.activate_action("open-muc-join", group_conversation.id);
}
};
if (!ShowMessage(template, callbacks)) {
warning("Failed showing muc invite notification"); warning("Failed showing muc invite notification");
} }
// HashTable<string, Variant> hash_table = new HashTable<string, Variant>(null, null);
// hash_table["image-data"] = yield get_conversation_icon(direct_conversation);
// string[] actions = new string[] {"default", "", "reject", _("Reject"), "accept", _("Accept")};
// try { // try {
// uint32 notification_id = dbus_notifications.notify("Dino", 0, "", summary, body, actions, hash_table, 0); // uint32 notification_id = dbus_notifications.notify("Dino", 0, "", summary, body, actions, hash_table, 0);
@ -137,32 +166,38 @@ namespace Dino.Plugins.WindowsNotification {
} }
public async void notify_voice_request(Conversation conversation, Jid from_jid) { public async void notify_voice_request(Conversation conversation, Jid from_jid) {
string display_name = Dino.get_participant_display_name(stream_interactor, conversation, from_jid); string display_name = Dino.get_participant_display_name(stream_interactor, conversation, from_jid);
string display_room = Dino.get_conversation_display_name(stream_interactor, conversation, _("%s from %s")); string display_room = Dino.get_conversation_display_name(stream_interactor, conversation, _("%s from %s"));
string summary = _("Permission request"); string summary = _("Permission request");
string body = _("%s requests the permission to write in %s").printf(display_name, display_room); string body = _("%s requests the permission to write in %s").printf(display_name, display_room);
if (!show_message(summary, body, get_avatar(conversation), conversation.id, stub)) { // missing actions DinoWinToastTemplate template;
var image_path = get_avatar(conversation);
if (image_path != null) {
template = new DinoWinToastTemplate(TemplateType.ImageAndText02);
template.setImagePath(image_path);
} else {
template = new DinoWinToastTemplate(TemplateType.Text02);
}
template.setTextField(summary, TextField.FirstLine);
template.setTextField(body, TextField.SecondLine);
template.addAction(_("Accept"));
template.addAction(_("Deny"));
var callbacks = new Callbacks();
callbacks.activatedWithIndex = (index) => {
if (index == 0) {
app.activate_action("deny-invite", conversation.id);
} else if (index == 1) {
app.activate_action("open-muc-join", conversation.id);
}
};
if (!ShowMessage(template, callbacks) == 0) {
warning("Failed showing voice request notification"); warning("Failed showing voice request notification");
} }
// HashTable<string, Variant> hash_table = new HashTable<string, Variant>(null, null);
// hash_table["image-data"] = yield get_conversation_icon(conversation);
// string[] actions = new string[] {"deny", _("Deny"), "accept", _("Accept")};
// try {
// uint32 notification_id = dbus_notifications.notify("Dino", 0, "", summary, body, actions, hash_table, 0);
// add_action_listener(notification_id, "accept", () => {
// GLib.Application.get_default().activate_action("deny-invite", new Variant.int32(conversation.id));
// });
// add_action_listener(notification_id, "deny", () => {
// GLib.Application.get_default().activate_action("open-muc-join", new Variant.int32(conversation.id));
// });
// } catch (Error e) {
// warning("Failed showing voice request notification: %s", e.message);
// }
} }
public async void retract_content_item_notifications() { public async void retract_content_item_notifications() {
@ -185,7 +220,7 @@ namespace Dino.Plugins.WindowsNotification {
// content_notifications.unset(conversation); // content_notifications.unset(conversation);
} }
private bool show_message(string sender, string message, string? image_path, int conv_id, NotificationCallback callback) { private bool show_message(string sender, string message, string? image_path, Callbacks? callbacks = null) {
DinoWinToastTemplate template; DinoWinToastTemplate template;
if (image_path != null) { if (image_path != null) {
template = new DinoWinToastTemplate(TemplateType.ImageAndText02); template = new DinoWinToastTemplate(TemplateType.ImageAndText02);
@ -196,7 +231,10 @@ namespace Dino.Plugins.WindowsNotification {
template.setTextField(sender, TextField.FirstLine); template.setTextField(sender, TextField.FirstLine);
template.setTextField(message, TextField.SecondLine); template.setTextField(message, TextField.SecondLine);
return ShowMessage(template, conv_id, callback) == 0; if (callbacks != null) {
return ShowMessage(template, callbacks) == 0;
}
return ShowMessage(template, new Callbacks()) == 0;
} }
private async void notify_content_item(Conversation conversation, string conversation_display_name, string? participant_display_name, string body_) { private async void notify_content_item(Conversation conversation, string conversation_display_name, string? participant_display_name, string body_) {
@ -206,18 +244,13 @@ namespace Dino.Plugins.WindowsNotification {
} }
var avatar = get_avatar(conversation); var avatar = get_avatar(conversation);
if (!show_message(conversation_display_name, body, avatar, conversation.id, onclick_callback)) { var callbacks = new Callbacks();
callbacks.activated = () => app.activate_action("open-conversation", conversation.id);
if (!show_message(conversation_display_name, body, avatar, callbacks)) {
warning("Failed showing content item notification"); warning("Failed showing content item notification");
} }
} }
private void onclick_callback(int conv_id) {
this.app.activate_action("open-conversation", conv_id);
}
private void stub(int conv_id) {
}
private string? get_avatar(Conversation conversation) { private string? get_avatar(Conversation conversation) {
var avatar_manager = app.stream_interactor.get_module(AvatarManager.IDENTITY); var avatar_manager = app.stream_interactor.get_module(AvatarManager.IDENTITY);
return avatar_manager.get_avatar_filepath(conversation.account, conversation.counterpart); return avatar_manager.get_avatar_filepath(conversation.account, conversation.counterpart);

View file

@ -1,13 +1,45 @@
[CCode (cheader_filename = "DinoWinToastLib.h")] [CCode (cheader_filename = "DinoWinToastLib.h")]
namespace DinoWinToast { namespace DinoWinToast {
[CCode (cname = "dinoWinToastLibNotificationCallback", has_target = true)] [CCode (cname = "dinoWinToastLib_Notification_Reason", cprefix = "Reason_")]
public delegate void NotificationCallback(int conv_id); public enum Reason {
Activated,
ApplicationHidden,
TimedOut
}
[CCode (cname = "dinoWinToastLibInit")] [CCode (cname = "dinoWinToastLib_Notification_Callback_Simple", has_target = true)]
public delegate void NotificationCallbackSimple();
[CCode (cname = "dinoWinToastLib_Notification_Callback_ActivatedWithActionIndex", has_target = true)]
public delegate void NotificationCallbackWithActionIndex(int actionId);
[CCode (cname = "dinoWinToastLib_Notification_Callback_Dismissed", has_target = true)]
public delegate void NotificationCallbackDismissed(Reason reason);
[CCode (cname = "dinoWinToastLib_Notification_Callbacks", free_function = "dinoWinToastLib_DestroyCallbacks")]
[Compact]
public class Callbacks {
[CCode (delegate_target_cname = "activated_context", destroy_notify_cname = "activated_free")]
public NotificationCallbackSimple activated;
[CCode (delegate_target_cname = "activatedWithIndex_context", destroy_notify_cname = "activatedWithIndex_free")]
public NotificationCallbackWithActionIndex activatedWithIndex;
[CCode (delegate_target_cname = "dismissed_context", destroy_notify_cname = "dismissed_free")]
public NotificationCallbackDismissed dismissed;
[CCode (delegate_target_cname = "failed_context", destroy_notify_cname = "failed_free")]
public NotificationCallbackSimple failed;
[CCode (cname = "dinoWinToastLib_NewCallbacks")]
public Callbacks();
}
[CCode (cname = "dinoWinToastLib_Init")]
public int Init(); public int Init();
[CCode (cname = "dinoWinToastLibShowMessage")] [CCode (cname = "dinoWinToastLib_ShowMessage")]
public int ShowMessage(DinoWinToastTemplate templ, int conv_id, NotificationCallback callback); public int ShowMessage(DinoWinToastTemplate templ, Callbacks callbacks);
} }

View file

@ -1,27 +1,27 @@
[CCode (cheader_filename = "DinoWinToastTemplate.h")] [CCode (cheader_filename = "DinoWinToastTemplate.h")]
namespace DinoWinToast { namespace DinoWinToast {
[CCode (cname = "dino_wintoasttemplate_duration", cprefix = "")] [CCode (cname = "dino_wintoasttemplate_duration", cprefix = "Duration_")]
public enum Duration { public enum Duration {
System, System,
Short, Short,
Long Long
} }
[CCode (cname = "dino_wintoasttemplate_audiooption", cprefix = "")] [CCode (cname = "dino_wintoasttemplate_audiooption", cprefix = "AudioOption_")]
public enum AudioOption { public enum AudioOption {
Default, Default,
Silent, Silent,
Loop Loop
} }
[CCode (cname = "dino_wintoasttemplate_textfield", cprefix = "")] [CCode (cname = "dino_wintoasttemplate_textfield", cprefix = "TextField_")]
public enum TextField { public enum TextField {
FirstLine, FirstLine,
SecondLine, SecondLine,
ThirdLine ThirdLine
} }
[CCode (cname = "dino_wintoasttemplate_wintoasttemplatetype", cprefix = "")] [CCode (cname = "dino_wintoasttemplate_wintoasttemplatetype", cprefix = "TemplateType_")]
public enum TemplateType { public enum TemplateType {
ImageAndText01, ImageAndText01,
ImageAndText02, ImageAndText02,