Move notification sounds (canberra dependency) into plugin, introduce libdino/NotificationEvents

This commit is contained in:
fiaxh 2018-03-02 13:13:15 +01:00
parent 08c8b9c6d6
commit a8ee61b34c
13 changed files with 130 additions and 75 deletions

View file

@ -38,6 +38,7 @@ SOURCES
src/service/message_storage.vala src/service/message_storage.vala
src/service/module_manager.vala src/service/module_manager.vala
src/service/muc_manager.vala src/service/muc_manager.vala
src/service/notification_events.vala
src/service/presence_manager.vala src/service/presence_manager.vala
src/service/roster_manager.vala src/service/roster_manager.vala
src/service/stream_interactor.vala src/service/stream_interactor.vala

View file

@ -37,6 +37,7 @@ public interface Dino.Application : GLib.Application {
ConversationManager.start(stream_interactor, db); ConversationManager.start(stream_interactor, db);
ChatInteraction.start(stream_interactor); ChatInteraction.start(stream_interactor);
FileManager.start(stream_interactor, db); FileManager.start(stream_interactor, db);
NotificationEvents.start(stream_interactor);
create_actions(); create_actions();

View file

@ -101,10 +101,6 @@ public class Conversation : Object {
return notify_setting != NotifySetting.DEFAULT ? notify_setting : get_notification_default_setting(stream_interactor); 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) { public NotifySetting get_notification_default_setting(StreamInteractor stream_interactor) {
Xmpp.XmppStream? stream = stream_interactor.get_stream(account); Xmpp.XmppStream? stream = stream_interactor.get_stream(account);
if (!Application.get_default().settings.notifications) return NotifySetting.OFF; if (!Application.get_default().settings.notifications) return NotifySetting.OFF;

View file

@ -10,7 +10,6 @@ public class Settings : Object {
send_typing_ = col_to_bool_or_default("send_typing", true); send_typing_ = col_to_bool_or_default("send_typing", true);
send_marker_ = col_to_bool_or_default("send_marker", true); send_marker_ = col_to_bool_or_default("send_marker", true);
notifications_ = col_to_bool_or_default("notifications", 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); convert_utf8_smileys_ = col_to_bool_or_default("convert_utf8_smileys", true);
current_width = col_to_int_or_default("window_width", 1200); 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_; private bool convert_utf8_smileys_;
public bool convert_utf8_smileys { public bool convert_utf8_smileys {
get { return convert_utf8_smileys_; } get { return convert_utf8_smileys_; }

View file

@ -0,0 +1,53 @@
using Gee;
using Dino.Entities;
using Xmpp;
namespace Dino {
public class NotificationEvents : StreamInteractionModule, Object {
public static ModuleIdentity<NotificationEvents> IDENTITY = new ModuleIdentity<NotificationEvents>("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);
}
}
}

View file

@ -9,7 +9,6 @@ find_packages(MAIN_PACKAGES REQUIRED
GModule GModule
GObject GObject
GTK3>=3.22 GTK3>=3.22
Canberra
) )
set(RESOURCE_LIST set(RESOURCE_LIST

View file

@ -53,18 +53,6 @@
<property name="height">1</property> <property name="height">1</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkCheckButton" id="sound_checkbutton">
<property name="label" translatable="yes">Play a sound when a new message arrives</property>
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child> <child>
<object class="GtkCheckButton" id="emoji_checkbutton"> <object class="GtkCheckButton" id="emoji_checkbutton">
<property name="label" translatable="yes">Convert smileys to emojis</property> <property name="label" translatable="yes">Convert smileys to emojis</property>
@ -72,7 +60,7 @@
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">4</property> <property name="top_attach">3</property>
<property name="width">1</property> <property name="width">1</property>
<property name="height">1</property> <property name="height">1</property>
</packing> </packing>

View file

@ -14,14 +14,11 @@ public class Notifications : Object {
private HashMap<Conversation, Notification> notifications = new HashMap<Conversation, Notification>(Conversation.hash_func, Conversation.equals_func); private HashMap<Conversation, Notification> notifications = new HashMap<Conversation, Notification>(Conversation.hash_func, Conversation.equals_func);
private Set<string>? active_conversation_ids = null; private Set<string>? active_conversation_ids = null;
private Set<string>? active_ids = new HashSet<string>(); private Set<string>? active_ids = new HashSet<string>();
private Canberra.Context sound_context;
public Notifications(StreamInteractor stream_interactor, Gtk.Window window) { public Notifications(StreamInteractor stream_interactor, Gtk.Window window) {
this.stream_interactor = stream_interactor; this.stream_interactor = stream_interactor;
this.window = window; this.window = window;
Canberra.Context.create(out sound_context);
stream_interactor.get_module(ChatInteraction.IDENTITY).focused_in.connect((focused_conversation) => { stream_interactor.get_module(ChatInteraction.IDENTITY).focused_in.connect((focused_conversation) => {
if (active_conversation_ids == null) { if (active_conversation_ids == null) {
Gee.List<Conversation> conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(); Gee.List<Conversation> conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations();
@ -44,18 +41,15 @@ public class Notifications : Object {
} }
public void start() { public void start() {
stream_interactor.get_module(MessageProcessor.IDENTITY).message_received.connect(on_message_received); stream_interactor.get_module(NotificationEvents.IDENTITY).notify_message.connect(notify_message);
stream_interactor.get_module(PresenceManager.IDENTITY).received_subscription_request.connect(on_received_subscription_request); stream_interactor.get_module(NotificationEvents.IDENTITY).notify_subscription_request.connect(notify_subscription_request);
} }
private void on_message_received(Entities.Message message, Conversation conversation) { private void notify_message(Entities.Message message, Conversation conversation) {
if (!should_notify_message(message, conversation)) return;
if (!notifications.has_key(conversation)) { if (!notifications.has_key(conversation)) {
notifications[conversation] = new Notification(""); notifications[conversation] = new Notification("");
notifications[conversation].set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id)); 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 display_name = Util.get_conversation_display_name(stream_interactor, conversation);
string text = message.body; string text = message.body;
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(conversation.counterpart, conversation.account)) { if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(conversation.counterpart, conversation.account)) {
@ -71,21 +65,12 @@ public class Notifications : Object {
active_conversation_ids.add(conversation.id.to_string()); active_conversation_ids.add(conversation.id.to_string());
window.urgency_hint = true; 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");
}
}
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 notification = new Notification(_("Subscription request"));
notification.set_body(jid.bare_jid.to_string()); notification.set_body(conversation.counterpart.to_string());
try { 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) { } } catch (Error e) { }
notification.set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id)); 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); 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"); 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 { 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()); Gdk.Pixbuf avatar = Gdk.pixbuf_get_from_surface(surface, 0, 0, surface.get_width(), surface.get_height());
uint8[] buffer; uint8[] buffer;

View file

@ -8,7 +8,6 @@ class SettingsDialog : Dialog {
[GtkChild] private CheckButton typing_checkbutton; [GtkChild] private CheckButton typing_checkbutton;
[GtkChild] private CheckButton marker_checkbutton; [GtkChild] private CheckButton marker_checkbutton;
[GtkChild] private CheckButton notification_checkbutton; [GtkChild] private CheckButton notification_checkbutton;
[GtkChild] private CheckButton sound_checkbutton;
[GtkChild] private CheckButton emoji_checkbutton; [GtkChild] private CheckButton emoji_checkbutton;
Dino.Entities.Settings settings = Dino.Application.get_default().settings; Dino.Entities.Settings settings = Dino.Application.get_default().settings;
@ -19,13 +18,11 @@ class SettingsDialog : Dialog {
typing_checkbutton.active = settings.send_typing; typing_checkbutton.active = settings.send_typing;
marker_checkbutton.active = settings.send_marker; marker_checkbutton.active = settings.send_marker;
notification_checkbutton.active = settings.notifications; notification_checkbutton.active = settings.notifications;
sound_checkbutton.active = settings.sound;
emoji_checkbutton.active = settings.convert_utf8_smileys; emoji_checkbutton.active = settings.convert_utf8_smileys;
typing_checkbutton.toggled.connect(() => { settings.send_typing = typing_checkbutton.active; } ); typing_checkbutton.toggled.connect(() => { settings.send_typing = typing_checkbutton.active; } );
marker_checkbutton.toggled.connect(() => { settings.send_marker = marker_checkbutton.active; } ); marker_checkbutton.toggled.connect(() => { settings.send_marker = marker_checkbutton.active; } );
notification_checkbutton.toggled.connect(() => { settings.notifications = notification_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; }); emoji_checkbutton.toggled.connect(() => { settings.convert_utf8_smileys = emoji_checkbutton.active; });
} }
} }

View file

@ -11,3 +11,7 @@ endif(PLUGIN_ENABLED_omemo)
if(PLUGIN_ENABLED_http-files) if(PLUGIN_ENABLED_http-files)
add_subdirectory(http-files) add_subdirectory(http-files)
endif(PLUGIN_ENABLED_http-files) endif(PLUGIN_ENABLED_http-files)
if(PLUGIN_ENABLED_notification-sound)
add_subdirectory(notification-sound)
endif(PLUGIN_ENABLED_notification-sound)

View file

@ -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})

View file

@ -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() { }
}
}

View file

@ -0,0 +1,3 @@
public Type register_plugin(Module module) {
return typeof (Dino.Plugins.NotificationSound.Plugin);
}