diff --git a/libdino/CMakeLists.txt b/libdino/CMakeLists.txt index 93ece7e9..62c73eca 100644 --- a/libdino/CMakeLists.txt +++ b/libdino/CMakeLists.txt @@ -38,6 +38,7 @@ SOURCES src/service/message_storage.vala src/service/module_manager.vala src/service/muc_manager.vala + src/service/notification_events.vala src/service/presence_manager.vala src/service/roster_manager.vala src/service/stream_interactor.vala diff --git a/libdino/src/application.vala b/libdino/src/application.vala index f6e651a4..4ea33fb7 100644 --- a/libdino/src/application.vala +++ b/libdino/src/application.vala @@ -37,6 +37,7 @@ public interface Dino.Application : GLib.Application { ConversationManager.start(stream_interactor, db); ChatInteraction.start(stream_interactor); FileManager.start(stream_interactor, db); + NotificationEvents.start(stream_interactor); create_actions(); diff --git a/libdino/src/entity/conversation.vala b/libdino/src/entity/conversation.vala index 0dfa64f2..9026e33f 100644 --- a/libdino/src/entity/conversation.vala +++ b/libdino/src/entity/conversation.vala @@ -101,10 +101,6 @@ public class Conversation : Object { return notify_setting != NotifySetting.DEFAULT ? notify_setting : get_notification_default_setting(stream_interactor); } - public bool get_sound_setting(StreamInteractor stream_interactor) { - return Application.get_default().settings.sound; - } - public NotifySetting get_notification_default_setting(StreamInteractor stream_interactor) { Xmpp.XmppStream? stream = stream_interactor.get_stream(account); if (!Application.get_default().settings.notifications) return NotifySetting.OFF; diff --git a/libdino/src/entity/settings.vala b/libdino/src/entity/settings.vala index 32d38c90..f94a92ca 100644 --- a/libdino/src/entity/settings.vala +++ b/libdino/src/entity/settings.vala @@ -10,7 +10,6 @@ public class Settings : Object { send_typing_ = col_to_bool_or_default("send_typing", true); send_marker_ = col_to_bool_or_default("send_marker", true); notifications_ = col_to_bool_or_default("notifications", true); - sound_ = col_to_bool_or_default("sound", true); convert_utf8_smileys_ = col_to_bool_or_default("convert_utf8_smileys", true); current_width = col_to_int_or_default("window_width", 1200); @@ -57,15 +56,6 @@ public class Settings : Object { } } - private bool sound_; - public bool sound { - get { return sound_; } - set { - db.settings.insert().or("REPLACE").value(db.settings.key, "sound").value(db.settings.value, value.to_string()).perform(); - sound_ = value; - } - } - private bool convert_utf8_smileys_; public bool convert_utf8_smileys { get { return convert_utf8_smileys_; } diff --git a/libdino/src/service/notification_events.vala b/libdino/src/service/notification_events.vala new file mode 100644 index 00000000..5db581ba --- /dev/null +++ b/libdino/src/service/notification_events.vala @@ -0,0 +1,53 @@ +using Gee; + +using Dino.Entities; +using Xmpp; + +namespace Dino { + +public class NotificationEvents : StreamInteractionModule, Object { + public static ModuleIdentity IDENTITY = new ModuleIdentity("notification_events"); + public string id { get { return IDENTITY.id; } } + + public signal void notify_message(Message message, Conversation conversation); + public signal void notify_subscription_request(Conversation conversation); + + private StreamInteractor stream_interactor; + + public static void start(StreamInteractor stream_interactor) { + NotificationEvents m = new NotificationEvents(stream_interactor); + stream_interactor.add_module(m); + } + + public NotificationEvents(StreamInteractor stream_interactor) { + this.stream_interactor = stream_interactor; + + stream_interactor.get_module(MessageProcessor.IDENTITY).message_received.connect(on_message_received); + stream_interactor.get_module(PresenceManager.IDENTITY).received_subscription_request.connect(on_received_subscription_request); + } + + private void on_message_received(Entities.Message message, Conversation conversation) { + if (!should_notify_message(message, conversation)) return; + if (stream_interactor.get_module(ChatInteraction.IDENTITY).is_active_focus()) return; + notify_message(message, conversation); + } + + private bool should_notify_message(Entities.Message message, Conversation conversation) { + Conversation.NotifySetting notify = conversation.get_notification_setting(stream_interactor); + if (notify == Conversation.NotifySetting.OFF) return false; + Jid? nick = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account); + if (notify == Conversation.NotifySetting.HIGHLIGHT && nick != null) { + return Regex.match_simple("""\b""" + Regex.escape_string(nick.resourcepart) + """\b""", message.body, RegexCompileFlags.CASELESS); + } + return true; + } + + private void on_received_subscription_request(Jid jid, Account account) { + Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(jid, account, Conversation.Type.CHAT); + if (stream_interactor.get_module(ChatInteraction.IDENTITY).is_active_focus(conversation)) return; + + notify_subscription_request(conversation); + } +} + +} diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 0ef6099d..58e1ab7d 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -9,7 +9,6 @@ find_packages(MAIN_PACKAGES REQUIRED GModule GObject GTK3>=3.22 - Canberra ) set(RESOURCE_LIST diff --git a/main/data/settings_dialog.ui b/main/data/settings_dialog.ui index 861d8b74..9d18bdc7 100644 --- a/main/data/settings_dialog.ui +++ b/main/data/settings_dialog.ui @@ -53,18 +53,6 @@ 1 - - - Play a sound when a new message arrives - True - - - 0 - 3 - 1 - 1 - - Convert smileys to emojis @@ -72,7 +60,7 @@ 0 - 4 + 3 1 1 diff --git a/main/src/ui/notifications.vala b/main/src/ui/notifications.vala index 2eb144e4..f7540a4d 100644 --- a/main/src/ui/notifications.vala +++ b/main/src/ui/notifications.vala @@ -14,14 +14,11 @@ public class Notifications : Object { private HashMap notifications = new HashMap(Conversation.hash_func, Conversation.equals_func); private Set? active_conversation_ids = null; private Set? active_ids = new HashSet(); - private Canberra.Context sound_context; public Notifications(StreamInteractor stream_interactor, Gtk.Window window) { this.stream_interactor = stream_interactor; this.window = window; - Canberra.Context.create(out sound_context); - stream_interactor.get_module(ChatInteraction.IDENTITY).focused_in.connect((focused_conversation) => { if (active_conversation_ids == null) { Gee.List conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(); @@ -44,48 +41,36 @@ public class Notifications : Object { } public void start() { - stream_interactor.get_module(MessageProcessor.IDENTITY).message_received.connect(on_message_received); - stream_interactor.get_module(PresenceManager.IDENTITY).received_subscription_request.connect(on_received_subscription_request); + stream_interactor.get_module(NotificationEvents.IDENTITY).notify_message.connect(notify_message); + stream_interactor.get_module(NotificationEvents.IDENTITY).notify_subscription_request.connect(notify_subscription_request); } - private void on_message_received(Entities.Message message, Conversation conversation) { - if (!should_notify_message(message, conversation)) return; - + private void notify_message(Entities.Message message, Conversation conversation) { if (!notifications.has_key(conversation)) { notifications[conversation] = new Notification(""); notifications[conversation].set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id)); } - if (!stream_interactor.get_module(ChatInteraction.IDENTITY).is_active_focus()) { - string display_name = Util.get_conversation_display_name(stream_interactor, conversation); - string text = message.body; - if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(conversation.counterpart, conversation.account)) { - string muc_occupant = Util.get_display_name(stream_interactor, message.from, conversation.account); - text = @"$muc_occupant: $text"; - } - notifications[conversation].set_title(display_name); - notifications[conversation].set_body(text); - try { - notifications[conversation].set_icon(get_pixbuf_icon((new AvatarGenerator(40, 40)).draw_conversation(stream_interactor, conversation))); - } catch (Error e) { } - window.get_application().send_notification(conversation.id.to_string(), notifications[conversation]); - active_conversation_ids.add(conversation.id.to_string()); - window.urgency_hint = true; - } - if (conversation.get_sound_setting(stream_interactor)) { - sound_context.play (0, - Canberra.PROP_EVENT_ID, "message-new-instant", - Canberra.PROP_EVENT_DESCRIPTION, "New Dino message"); + string display_name = Util.get_conversation_display_name(stream_interactor, conversation); + string text = message.body; + if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(conversation.counterpart, conversation.account)) { + string muc_occupant = Util.get_display_name(stream_interactor, message.from, conversation.account); + text = @"$muc_occupant: $text"; } + notifications[conversation].set_title(display_name); + notifications[conversation].set_body(text); + try { + notifications[conversation].set_icon(get_pixbuf_icon((new AvatarGenerator(40, 40)).draw_conversation(stream_interactor, conversation))); + } catch (Error e) { } + window.get_application().send_notification(conversation.id.to_string(), notifications[conversation]); + active_conversation_ids.add(conversation.id.to_string()); + window.urgency_hint = true; } - private void on_received_subscription_request(Jid jid, Account account) { - Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(jid, account, Conversation.Type.CHAT); - if (stream_interactor.get_module(ChatInteraction.IDENTITY).is_active_focus(conversation)) return; - + private void notify_subscription_request(Conversation conversation) { Notification notification = new Notification(_("Subscription request")); - notification.set_body(jid.bare_jid.to_string()); + notification.set_body(conversation.counterpart.to_string()); try { - notification.set_icon(get_pixbuf_icon((new AvatarGenerator(40, 40)).draw_jid(stream_interactor, jid, account))); + notification.set_icon(get_pixbuf_icon((new AvatarGenerator(40, 40)).draw_jid(stream_interactor, conversation.counterpart, conversation.account))); } catch (Error e) { } notification.set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id)); notification.add_button_with_target_value(_("Accept"), "app.accept-subscription", conversation.id); @@ -94,16 +79,6 @@ public class Notifications : Object { active_ids.add(conversation.id.to_string() + "-subscription"); } - private bool should_notify_message(Entities.Message message, Conversation conversation) { - Conversation.NotifySetting notify = conversation.get_notification_setting(stream_interactor); - if (notify == Conversation.NotifySetting.OFF) return false; - Jid? nick = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account); - if (notify == Conversation.NotifySetting.HIGHLIGHT && nick != null) { - return Regex.match_simple("""\b""" + Regex.escape_string(nick.resourcepart) + """\b""", message.body, RegexCompileFlags.CASELESS); - } - return true; - } - private Icon get_pixbuf_icon(Cairo.ImageSurface surface) throws Error { Gdk.Pixbuf avatar = Gdk.pixbuf_get_from_surface(surface, 0, 0, surface.get_width(), surface.get_height()); uint8[] buffer; diff --git a/main/src/ui/settings_dialog.vala b/main/src/ui/settings_dialog.vala index 58c86bde..e40b2993 100644 --- a/main/src/ui/settings_dialog.vala +++ b/main/src/ui/settings_dialog.vala @@ -8,7 +8,6 @@ class SettingsDialog : Dialog { [GtkChild] private CheckButton typing_checkbutton; [GtkChild] private CheckButton marker_checkbutton; [GtkChild] private CheckButton notification_checkbutton; - [GtkChild] private CheckButton sound_checkbutton; [GtkChild] private CheckButton emoji_checkbutton; Dino.Entities.Settings settings = Dino.Application.get_default().settings; @@ -19,13 +18,11 @@ class SettingsDialog : Dialog { typing_checkbutton.active = settings.send_typing; marker_checkbutton.active = settings.send_marker; notification_checkbutton.active = settings.notifications; - sound_checkbutton.active = settings.sound; emoji_checkbutton.active = settings.convert_utf8_smileys; typing_checkbutton.toggled.connect(() => { settings.send_typing = typing_checkbutton.active; } ); marker_checkbutton.toggled.connect(() => { settings.send_marker = marker_checkbutton.active; } ); notification_checkbutton.toggled.connect(() => { settings.notifications = notification_checkbutton.active; } ); - sound_checkbutton.toggled.connect(() => { settings.sound = sound_checkbutton.active; } ); emoji_checkbutton.toggled.connect(() => { settings.convert_utf8_smileys = emoji_checkbutton.active; }); } } diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 10506a86..79523b8f 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -11,3 +11,7 @@ endif(PLUGIN_ENABLED_omemo) if(PLUGIN_ENABLED_http-files) add_subdirectory(http-files) endif(PLUGIN_ENABLED_http-files) + +if(PLUGIN_ENABLED_notification-sound) + add_subdirectory(notification-sound) +endif(PLUGIN_ENABLED_notification-sound) diff --git a/plugins/notification-sound/CMakeLists.txt b/plugins/notification-sound/CMakeLists.txt new file mode 100644 index 00000000..85963d25 --- /dev/null +++ b/plugins/notification-sound/CMakeLists.txt @@ -0,0 +1,28 @@ +find_packages(NOTIFICATION_SOUND_PACKAGES REQUIRED + Canberra + Gee + GLib + GModule + GObject + GDKPixbuf2 +) + +vala_precompile(NOTIFICATION_SOUND_VALA_C +SOURCES + src/plugin.vala + src/register_plugin.vala +CUSTOM_VAPIS + ${CMAKE_BINARY_DIR}/exports/xmpp-vala.vapi + ${CMAKE_BINARY_DIR}/exports/dino.vapi + ${CMAKE_BINARY_DIR}/exports/qlite.vapi +PACKAGES + ${NOTIFICATION_SOUND_PACKAGES} +) + +add_definitions(${VALA_CFLAGS}) +add_library(notification-sound SHARED ${NOTIFICATION_SOUND_VALA_C}) +target_link_libraries(notification-sound libdino ${NOTIFICATION_SOUND_PACKAGES}) +set_target_properties(notification-sound PROPERTIES PREFIX "") +set_target_properties(notification-sound PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins/) + +install(TARGETS notification-sound ${PLUGIN_INSTALL}) diff --git a/plugins/notification-sound/src/plugin.vala b/plugins/notification-sound/src/plugin.vala new file mode 100644 index 00000000..ba251434 --- /dev/null +++ b/plugins/notification-sound/src/plugin.vala @@ -0,0 +1,20 @@ +namespace Dino.Plugins.NotificationSound { + +public class Plugin : RootInterface, Object { + + public Dino.Application app; + private Canberra.Context sound_context; + + public void registered(Dino.Application app) { + this.app = app; + Canberra.Context.create(out sound_context); + + app.stream_interactor.get_module(NotificationEvents.IDENTITY).notify_message.connect((message, conversation) => { + sound_context.play(0, Canberra.PROP_EVENT_ID, "message-new-instant", Canberra.PROP_EVENT_DESCRIPTION, "New Dino message"); + }); + } + + public void shutdown() { } +} + +} diff --git a/plugins/notification-sound/src/register_plugin.vala b/plugins/notification-sound/src/register_plugin.vala new file mode 100644 index 00000000..09204c0f --- /dev/null +++ b/plugins/notification-sound/src/register_plugin.vala @@ -0,0 +1,3 @@ +public Type register_plugin(Module module) { + return typeof (Dino.Plugins.NotificationSound.Plugin); +}