diff --git a/data/chat.tox.venom.desktop.in b/data/chat.tox.venom.desktop.in index 4c88f1e..3de1506 100644 --- a/data/chat.tox.venom.desktop.in +++ b/data/chat.tox.venom.desktop.in @@ -10,3 +10,8 @@ Categories=InstantMessaging;Network; DBusActivatable=true StartupNotify=true X-GNOME-UsesNotifications=true +Actions=preferences; + +[Desktop Action preferences] +Name=Preferences +Exec=venom --preferences \ No newline at end of file diff --git a/src/core/Application.vala b/src/core/Application.vala index ef592bc..1c21803 100644 --- a/src/core/Application.vala +++ b/src/core/Application.vala @@ -27,12 +27,15 @@ namespace Venom { { "show-filetransfers", on_show_filetransfers, null, null, null }, { "show-conferences", on_show_conferences, null, null, null }, { "show-add-contact", on_show_add_contact, null, null, null }, - { "show-contact", on_show_contact, "s", null, null } + { "show-contact", on_show_contact, "s", null, null }, + { "show-contact-info", on_show_contact_info, "s", null, null }, + { "mute-contact", on_mute_contact, "s", null, null } }; private const OptionEntry[] option_entries = { { "loglevel", 'l', 0, OptionArg.INT, ref loglevel, N_("Set level of messages to log"), N_("") }, { "version", 'V', 0, OptionArg.NONE, null, N_("Display version number"), null }, + { "preferences", 'p', 0, OptionArg.NONE, null, N_("Show preferences"), null }, { null } }; @@ -50,7 +53,7 @@ namespace Venom { public Application() { Object( application_id: R.constants.app_id(), - flags: ApplicationFlags.HANDLES_OPEN + flags: ApplicationFlags.HANDLES_OPEN | ApplicationFlags.HANDLES_COMMAND_LINE ); add_main_option_entries(option_entries); add_action_entries(app_entries, this); @@ -67,7 +70,10 @@ namespace Venom { err_widget.add_page(widget_factory.createSettingsWidget(null, settings_database, node_database), "settings", _("Settings")); var log_view = new Gtk.TextView(); log_view.editable = false; - log_view.buffer.set_text(logger.get_log()); + log_view.monospace = true; + Gtk.TextIter iter; + log_view.buffer.get_start_iter(out iter); + log_view.buffer.insert_markup(ref iter, logger.get_log(), -1); err_widget.add_page(log_view, "log", _("Log")); err_widget.on_retry.connect(() => { window.destroy(); @@ -164,6 +170,16 @@ namespace Venom { release(); } + public override int command_line(GLib.ApplicationCommandLine command_line) { + if (command_line.get_options_dict().contains("preferences")) { + on_show_preferences(); + return 0; + } + + activate(); + return 0; + } + protected override int handle_local_options(GLib.VariantDict options) { if (options.contains("version")) { stdout.printf("%s %s\n", Environment.get_application_name(), Config.VERSION); @@ -207,6 +223,23 @@ namespace Venom { on_active_window((win) => win.on_show_contact(parameter.get_string())); } + public void on_mute_contact(GLib.SimpleAction action, GLib.Variant? parameter) { + logger.d("on_mute_contact"); + if (parameter == null || parameter.get_string() == "") { + return; + } + on_active_window((win) => win.on_mute_contact(parameter.get_string())); + } + + public void on_show_contact_info(GLib.SimpleAction action, GLib.Variant? parameter) { + logger.d("on_show_contact_info"); + activate(); + if (parameter == null || parameter.get_string() == "") { + return; + } + on_active_window((win) => win.on_show_contact_info(parameter.get_string())); + } + public void on_show_filetransfers() { logger.d("on_show_filetransfers"); activate(); diff --git a/src/core/Identicon.vala b/src/core/Identicon.vala index 44d3ae7..c5c7454 100644 --- a/src/core/Identicon.vala +++ b/src/core/Identicon.vala @@ -28,7 +28,7 @@ namespace Venom { private Cairo.Surface surface; public static Gdk.Pixbuf generate_pixbuf(uint8[] public_key, int size = 120) { - var identicon = new Identicon(public_key); + var identicon = new Identicon(public_key, size); identicon.draw(); return identicon.get_pixbuf(); } diff --git a/src/core/Logger.vala b/src/core/Logger.vala index d2fd167..ded78a1 100644 --- a/src/core/Logger.vala +++ b/src/core/Logger.vala @@ -38,6 +38,12 @@ namespace Venom { public const string FATAL = TermColor.MAGENTA; } + namespace PangoHelper { + public static string insert_span(string attributes, string content) { + return @"$content"; + } + } + public enum LogLevel { DEBUG, INFO, @@ -61,6 +67,23 @@ namespace Venom { assert_not_reached(); } } + + public string to_markup() { + switch(this) { + case DEBUG: + return "DEBUG"; + case INFO: + return PangoHelper.insert_span("foreground=\"green\"", "INFO "); + case WARNING: + return PangoHelper.insert_span("foreground=\"yellow\"", "WARN "); + case ERROR: + return PangoHelper.insert_span("foreground=\"red\"", "ERROR"); + case FATAL: + return PangoHelper.insert_span("foreground=\"magenta\"", "FATAL"); + default: + assert_not_reached(); + } + } } public class Logger : ILogger, Object { @@ -136,7 +159,7 @@ namespace Venom { } public void log(LogLevel level, string message) { - log_builder.append("%s\n".printf(message)); + log_builder.append("[%s] %s\n".printf(level.to_markup(), message)); if (level < displayed_level) { return; diff --git a/src/core/Message.vala b/src/core/Message.vala index 32794f1..b95eb3c 100644 --- a/src/core/Message.vala +++ b/src/core/Message.vala @@ -35,6 +35,7 @@ namespace Venom { public abstract bool received { get; set; } public abstract string get_sender_plain(); + public abstract string get_sender_full(); public abstract string get_sender_id(); public abstract string get_conversation_id(); public abstract string get_message_plain(); @@ -82,6 +83,10 @@ namespace Venom { } } + public string get_sender_full() { + return get_sender_plain(); + } + public string get_sender_id() { return (from == null) ? to.get_id() : from.get_id(); } diff --git a/src/core/NotificationListener.vala b/src/core/NotificationListener.vala index 26bb070..c76e8ef 100644 --- a/src/core/NotificationListener.vala +++ b/src/core/NotificationListener.vala @@ -83,10 +83,15 @@ namespace Venom { return; } - var notification = new Notification(_("New message from %s").printf(message.get_sender_plain())); + var title = _("New message from %s").printf(message.get_sender_full()); + var contact_id = new GLib.Variant.string(message.get_conversation_id()); + + var notification = new Notification(title); notification.set_body(message.get_message_plain()); notification.set_icon(scale_icon(message.get_sender_image())); - notification.set_default_action_and_target_value("app.show-contact", new GLib.Variant.string(message.get_conversation_id())); + notification.set_default_action_and_target_value("app.show-contact", contact_id); + notification.add_button_with_target_value(_("Show details"), "app.show-contact-info", contact_id); + notification.add_button_with_target_value(_("Mute conversation"), "app.mute-contact", contact_id); app.send_notification(message_id, notification); play_sound("message-new-instant"); diff --git a/src/tox/Conference.vala b/src/tox/Conference.vala index a40a3ae..1beec97 100644 --- a/src/tox/Conference.vala +++ b/src/tox/Conference.vala @@ -64,7 +64,7 @@ namespace Venom { return true; } - public Gdk.Pixbuf get_image() { + private Gdk.Pixbuf get_default_image() { if (default_image == null) { try { default_image = Gtk.IconTheme.get_default().load_icon(R.icons.default_groupchat, 48, 0); @@ -75,6 +75,49 @@ namespace Venom { return default_image; } + public Gdk.Pixbuf get_image() { + if (peers.size < 1) { + return get_default_image(); + } + + var size = 120; + var surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, size, size); + var ctx = new Cairo.Context(surface); + var count = uint.min(peers.size, 5); + var offset = 90.0 / count; + var radius = size * 0.1f; + var deg = Math.PI / 180.0; + + for(var i = 0; i < count; i++) { + var peer = peers.get(i); + + var identicon = round_corners(Identicon.generate_pixbuf(Tools.hexstring_to_bin(peer.peer_key))); + var identicon_surf = Gdk.cairo_surface_create_from_pixbuf(identicon, 1, null); + + ctx.save(); + ctx.translate(offset * i, 0); + ctx.set_source_surface(identicon_surf, 0, 0); + ctx.paint(); + + if (i > 0) { + ctx.new_sub_path(); + ctx.arc(size - radius, radius, radius, -90 * deg, 0); + ctx.arc(size - radius, size - radius, radius, 0, 90 * deg); + ctx.arc(radius, size - radius, radius, 90 * deg, 180 * deg); + ctx.arc(radius, radius, radius, 180 * deg, 270 * deg); + ctx.close_path(); + + ctx.set_source_rgba(0, 0, 0, 0.25); + ctx.set_line_width(5); + ctx.stroke(); + } + + ctx.restore(); + } + + return Gdk.pixbuf_get_from_surface(surface, 0, 0, size, size); + } + public unowned Gee.Map get_peers() { return peers; } diff --git a/src/tox/ConferenceMessage.vala b/src/tox/ConferenceMessage.vala index f7a919c..257eff0 100644 --- a/src/tox/ConferenceMessage.vala +++ b/src/tox/ConferenceMessage.vala @@ -27,13 +27,17 @@ namespace Venom { public bool is_action { get; set; } public bool received { get; set; } - public uint32 conference_number { get; protected set; } public string message { get; protected set; } public string peer_name { get; protected set; } public string peer_key { get; protected set; } - private ConferenceMessage(uint32 conference_number, MessageDirection direction, string message, GLib.DateTime timestamp) { - this.conference_number = conference_number; + public unowned IContact from { get; protected set; } + public unowned IContact to { get; protected set; } + + private unowned IContact conference; + + private ConferenceMessage(IContact conference, MessageDirection direction, string message, GLib.DateTime timestamp) { + this.conference = conference; this.message_direction = direction; this.message = message; this.timestamp = timestamp; @@ -41,12 +45,12 @@ namespace Venom { this.is_action = false; } - public ConferenceMessage.outgoing(uint32 conference_number, string message, GLib.DateTime timestamp = new GLib.DateTime.now_local()) { - this(conference_number, MessageDirection.OUTGOING, message, timestamp); + public ConferenceMessage.outgoing(IContact conference, string message, GLib.DateTime timestamp = new GLib.DateTime.now_local()) { + this(conference, MessageDirection.OUTGOING, message, timestamp); } - public ConferenceMessage.incoming(uint32 conference_number, string peer_key, string peer_name, string message, GLib.DateTime timestamp = new GLib.DateTime.now_local()) { - this(conference_number, MessageDirection.INCOMING, message, timestamp); + public ConferenceMessage.incoming(IContact conference, string peer_key, string peer_name, string message, GLib.DateTime timestamp = new GLib.DateTime.now_local()) { + this(conference, MessageDirection.INCOMING, message, timestamp); this.peer_key = peer_key; this.peer_name = peer_name; } @@ -59,8 +63,12 @@ namespace Venom { } } + public string get_sender_full() { + return _("%s in %s").printf(get_sender_plain(), conference.get_name_string()); + } + public string get_conversation_id() { - return @"tox.conference.$conference_number"; + return conference.get_id(); } public string get_sender_id() { diff --git a/src/tox/ToxAdapterConferenceListener.vala b/src/tox/ToxAdapterConferenceListener.vala index 3505a6e..d48f1ee 100644 --- a/src/tox/ToxAdapterConferenceListener.vala +++ b/src/tox/ToxAdapterConferenceListener.vala @@ -187,7 +187,7 @@ namespace Venom { var contact = conferences.@get(conference_number) as Conference; var conversation = conversations.@get(contact); var peer = contact.get_peers().@get(peer_number); - var msg = new ConferenceMessage.incoming(conference_number, peer.peer_key, peer.peer_name, message); + var msg = new ConferenceMessage.incoming(contact, peer.peer_key, peer.peer_name, message); notification_listener.on_unread_message(msg, contact); contact.unread_messages++; contact.changed(); @@ -198,7 +198,7 @@ namespace Venom { logger.d("on_conference_message_sent"); var contact = conferences.@get(conference_number) as Conference; var conversation = conversations.@get(contact); - var msg = new ConferenceMessage.outgoing(conference_number, message); + var msg = new ConferenceMessage.outgoing(contact, message); msg.received = true; conversation.append(msg); } diff --git a/src/ui/conference_window.ui b/src/ui/conference_window.ui index 81d150c..7a091c7 100644 --- a/src/ui/conference_window.ui +++ b/src/ui/conference_window.ui @@ -137,7 +137,7 @@ along with Venom. If not, see . Show details win.conference-info - + True False 22 diff --git a/src/ui/contact_list_widget.ui b/src/ui/contact_list_widget.ui index 4482640..8859b54 100644 --- a/src/ui/contact_list_widget.ui +++ b/src/ui/contact_list_widget.ui @@ -1,5 +1,5 @@ -