From 8d1c6c29be7018c74ec3f8ea05f5849eac5b4069 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Thu, 8 Apr 2021 12:07:04 +0200 Subject: Display+store call encryption info --- main/src/ui/call_window/call_bottom_bar.vala | 53 ++++++++++++++-- .../src/ui/call_window/call_window_controller.vala | 4 ++ .../content_populator.vala | 1 + .../conversation_item_skeleton.vala | 74 +++++++++++++--------- 4 files changed, 97 insertions(+), 35 deletions(-) (limited to 'main/src/ui') diff --git a/main/src/ui/call_window/call_bottom_bar.vala b/main/src/ui/call_window/call_bottom_bar.vala index bc800485..c6375ea2 100644 --- a/main/src/ui/call_window/call_bottom_bar.vala +++ b/main/src/ui/call_window/call_bottom_bar.vala @@ -1,5 +1,6 @@ using Dino.Entities; using Gtk; +using Pango; public class Dino.Ui.CallBottomBar : Gtk.Box { @@ -24,6 +25,10 @@ public class Dino.Ui.CallBottomBar : Gtk.Box { private MenuButton video_settings_button = new MenuButton() { halign=Align.END, valign=Align.END }; public VideoSettingsPopover? video_settings_popover; + private EventBox encryption_event_box = new EventBox() { visible=true }; + private MenuButton encryption_button = new MenuButton() { relief=ReliefStyle.NONE, height_request=30, width_request=30, margin_start=20, margin_bottom=25, halign=Align.START, valign=Align.END }; + private Image encryption_image = new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON) { visible=true }; + private Label label = new Label("") { margin=20, halign=Align.CENTER, valign=Align.CENTER, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true, visible=true }; private Stack stack = new Stack() { visible=true }; @@ -31,11 +36,9 @@ public class Dino.Ui.CallBottomBar : Gtk.Box { Object(orientation:Orientation.HORIZONTAL, spacing:0); Overlay default_control = new Overlay() { visible=true }; - Image encryption_image = new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON) { margin_start=20, margin_bottom=25, halign=Align.START, valign=Align.END, visible=true }; - encryption_image.tooltip_text = _("Unencrypted"); - encryption_image.get_style_context().add_class("unencrypted-box"); - - default_control.add_overlay(encryption_image); + encryption_button.add(encryption_image); + encryption_button.get_style_context().add_class("encryption-box"); + default_control.add_overlay(encryption_button); Box main_buttons = new Box(Orientation.HORIZONTAL, 20) { margin_start=40, margin_end=40, margin=20, halign=Align.CENTER, hexpand=true, visible=true }; @@ -87,6 +90,33 @@ public class Dino.Ui.CallBottomBar : Gtk.Box { this.get_style_context().add_class("call-bottom-bar"); } + public void set_encryption(Xmpp.Xep.Jingle.ContentEncryption? encryption) { + encryption_button.visible = true; + + Popover popover = new Popover(encryption_button); + + if (encryption == null) { + encryption_image.set_from_icon_name("changes-allow-symbolic", IconSize.BUTTON); + encryption_button.get_style_context().add_class("unencrypted"); + + popover.add(new Label("This call isn't encrypted.") { margin=10, visible=true } ); + } else { + encryption_image.set_from_icon_name("changes-prevent-symbolic", IconSize.BUTTON); + encryption_button.get_style_context().remove_class("unencrypted"); + + Grid encryption_info_grid = new Grid() { margin=10, row_spacing=3, column_spacing=5, visible=true }; + encryption_info_grid.attach(new Label("This call is end-to-end encrypted.") { use_markup=true, xalign=0, visible=true }, 1, 1, 2, 1); + encryption_info_grid.attach(new Label("Peer key") { xalign=0, visible=true }, 1, 2, 1, 1); + encryption_info_grid.attach(new Label("Your key") { xalign=0, visible=true }, 1, 3, 1, 1); + encryption_info_grid.attach(new Label("" + format_fingerprint(encryption.peer_key) + "") { use_markup=true, max_width_chars=25, ellipsize=EllipsizeMode.MIDDLE, xalign=0, hexpand=true, visible=true }, 2, 2, 1, 1); + encryption_info_grid.attach(new Label("" + format_fingerprint(encryption.our_key) + "") { use_markup=true, max_width_chars=25, ellipsize=EllipsizeMode.MIDDLE, xalign=0, hexpand=true, visible=true }, 2, 3, 1, 1); + + popover.add(encryption_info_grid); + } + + encryption_button.set_popover(popover); + } + public AudioSettingsPopover? show_audio_device_choices(bool show) { audio_settings_button.visible = show; if (audio_settings_popover != null) audio_settings_popover.visible = false; @@ -160,6 +190,17 @@ public class Dino.Ui.CallBottomBar : Gtk.Box { } public bool is_menu_active() { - return video_settings_button.active || audio_settings_button.active; + return video_settings_button.active || audio_settings_button.active || encryption_button.active; + } + + private string format_fingerprint(uint8[] fingerprint) { + var sb = new StringBuilder(); + for (int i = 0; i < fingerprint.length; i++) { + sb.append("%02x".printf(fingerprint[i])); + if (i < fingerprint.length - 1) { + sb.append(":"); + } + } + return sb.str; } } \ No newline at end of file diff --git a/main/src/ui/call_window/call_window_controller.vala b/main/src/ui/call_window/call_window_controller.vala index 09c8f88c..f66a37e1 100644 --- a/main/src/ui/call_window/call_window_controller.vala +++ b/main/src/ui/call_window/call_window_controller.vala @@ -67,6 +67,10 @@ public class Dino.Ui.CallWindowController : Object { call_window.set_status("ringing"); } }); + calls.encryption_updated.connect((call, encryption) => { + if (!this.call.equals(call)) return; + call_window.bottom_bar.set_encryption(encryption); + }); own_video.resolution_changed.connect((width, height) => { if (width == 0 || height == 0) return; diff --git a/main/src/ui/conversation_content_view/content_populator.vala b/main/src/ui/conversation_content_view/content_populator.vala index d7ce9ce5..ef859bde 100644 --- a/main/src/ui/conversation_content_view/content_populator.vala +++ b/main/src/ui/conversation_content_view/content_populator.vala @@ -88,6 +88,7 @@ public abstract class ContentMetaItem : Plugins.MetaConversationItem { this.mark = content_item.mark; content_item.bind_property("mark", this, "mark"); + content_item.bind_property("encryption", this, "encryption"); this.can_merge = true; this.requires_avatar = true; diff --git a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala index c0099bf4..bcb6864e 100644 --- a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala +++ b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala @@ -104,7 +104,7 @@ public class ItemMetaDataHeader : Box { [GtkChild] public Label dot_label; [GtkChild] public Label time_label; public Image received_image = new Image() { opacity=0.4 }; - public Image? unencrypted_image = null; + public Widget? encryption_image = null; public static IconSize ICON_SIZE_HEADER = Gtk.icon_size_register("im.dino.Dino.HEADER_ICON", 17, 12); @@ -124,50 +124,66 @@ public class ItemMetaDataHeader : Box { update_name_label(); name_label.style_updated.connect(update_name_label); + conversation.notify["encryption"].connect(update_unencrypted_icon); + item.notify["encryption"].connect(update_encryption_icon); + update_encryption_icon(); + + this.add(received_image); + + if (item.time != null) { + update_time(); + } + + item.bind_property("mark", this, "item-mark"); + this.notify["item-mark"].connect_after(update_received_mark); + update_received_mark(); + } + + private void update_encryption_icon() { Application app = GLib.Application.get_default() as Application; ContentMetaItem ci = item as ContentMetaItem; - if (ci != null) { + if (item.encryption != Encryption.NONE && ci != null) { + Widget? widget = null; foreach(var e in app.plugin_registry.encryption_list_entries) { if (e.encryption == item.encryption) { - Object? w = e.get_encryption_icon(conversation, ci.content_item); - if (w != null) { - this.add(w as Widget); - } else { - Image image = new Image.from_icon_name("dino-changes-prevent-symbolic", ICON_SIZE_HEADER) { opacity=0.4, visible = true }; - this.add(image); - } + widget = e.get_encryption_icon(conversation, ci.content_item) as Widget; break; } } + if (widget == null) { + widget = new Image.from_icon_name("dino-changes-prevent-symbolic", ICON_SIZE_HEADER) { opacity=0.4, visible = true }; + } + update_encryption_image(widget); } if (item.encryption == Encryption.NONE) { - conversation.notify["encryption"].connect(update_unencrypted_icon); update_unencrypted_icon(); } + } - this.add(received_image); - - if (item.time != null) { - update_time(); + private void update_unencrypted_icon() { + if (item.encryption != Encryption.NONE) return; + + if (conversation.encryption != Encryption.NONE && encryption_image == null) { + Image image = new Image() { opacity=0.4, visible = true }; + image.set_from_icon_name("dino-changes-allowed-symbolic", ICON_SIZE_HEADER); + image.tooltip_text = _("Unencrypted"); + update_encryption_image(image); + Util.force_error_color(image); + } else if (conversation.encryption == Encryption.NONE && encryption_image != null) { + update_encryption_image(null); } - - item.bind_property("mark", this, "item-mark"); - this.notify["item-mark"].connect_after(update_received_mark); - update_received_mark(); } - private void update_unencrypted_icon() { - if (conversation.encryption != Encryption.NONE && unencrypted_image == null) { - unencrypted_image = new Image() { opacity=0.4, visible = true }; - unencrypted_image.set_from_icon_name("dino-changes-allowed-symbolic", ICON_SIZE_HEADER); - unencrypted_image.tooltip_text = _("Unencrypted"); - this.add(unencrypted_image); - this.reorder_child(unencrypted_image, 3); - Util.force_error_color(unencrypted_image); - } else if (conversation.encryption == Encryption.NONE && unencrypted_image != null) { - this.remove(unencrypted_image); - unencrypted_image = null; + private void update_encryption_image(Widget? widget) { + if (encryption_image != null) { + this.remove(encryption_image); + encryption_image = null; + } + if (widget != null) { + this.add(widget); + this.reorder_child(widget, 3); + encryption_image = widget; } } -- cgit v1.2.3-70-g09d2