From 3dc4d7f1558bb574eb99dade9a05727604e2e2ca Mon Sep 17 00:00:00 2001 From: fiaxh Date: Thu, 4 Nov 2021 17:35:11 +0100 Subject: Add (disabled) multi-party call UI --- main/src/ui/call_window/call_window.vala | 262 ++++++++++++++++--------------- 1 file changed, 138 insertions(+), 124 deletions(-) (limited to 'main/src/ui/call_window/call_window.vala') diff --git a/main/src/ui/call_window/call_window.vala b/main/src/ui/call_window/call_window.vala index 3b3d4dc2..fab424bf 100644 --- a/main/src/ui/call_window/call_window.vala +++ b/main/src/ui/call_window/call_window.vala @@ -1,87 +1,155 @@ +using Gee; +using Xmpp; using Dino.Entities; using Gtk; namespace Dino.Ui { public class CallWindow : Gtk.Window { - public string counterpart_display_name { get; set; } - // TODO should find another place for this + public signal void menu_dump_dot(); + public CallWindowController controller; public Overlay overlay = new Overlay() { visible=true }; + public Grid grid = new Grid() { visible=true }; public EventBox event_box = new EventBox() { visible=true }; public CallBottomBar bottom_bar = new CallBottomBar() { visible=true }; public Revealer bottom_bar_revealer = new Revealer() { valign=Align.END, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true }; - public HeaderBar header_bar = new HeaderBar() { show_close_button=true, visible=true }; - public Revealer header_bar_revealer = new Revealer() { valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true }; - public Stack stack = new Stack() { visible=true }; - public Box own_video_box = new Box(Orientation.HORIZONTAL, 0) { expand=true, visible=true }; + public HeaderBar header_bar = new HeaderBar() { valign=Align.START, halign=Align.END, show_close_button=true, visible=true }; + public Revealer header_bar_revealer = new Revealer() { halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true }; + public Box own_video_box = new Box(Orientation.HORIZONTAL, 0) { halign=Align.END, valign=Align.END, visible=true }; + public Revealer invite_button_revealer = new Revealer() { margin_top=50, margin_right=30, halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200 }; + public Button invite_button = new Button.from_icon_name("dino-account-plus") { relief=ReliefStyle.NONE }; private Widget? own_video = null; - private Box? own_video_border = new Box(Orientation.HORIZONTAL, 0) { expand=true }; // hack to draw a border around our own video, since we apparently can't draw a border around the Gst widget + private HashMap participant_widgets = new HashMap(); + private ArrayList participants = new ArrayList(); private int own_video_width = 150; private int own_video_height = 100; - private bool hide_controll_elements = false; - private uint hide_controll_handler = 0; - private Widget? main_widget = null; + private bool hide_control_elements = false; + private uint hide_control_handler = 0; + public bool controls_active { get; set; default=true; } construct { + Util.force_css(header_bar, "* { background: none; border: 0; border-radius: 0; }"); header_bar.get_style_context().add_class("call-header-bar"); header_bar_revealer.add(header_bar); + bottom_bar_revealer.add(bottom_bar); + invite_button.get_style_context().add_class("black-element"); + invite_button_revealer.add(invite_button); + own_video_box.get_style_context().add_class("own-video"); this.get_style_context().add_class("dino-call-window"); - bottom_bar_revealer.add(bottom_bar); - + overlay.add(grid); overlay.add_overlay(own_video_box); - overlay.add_overlay(own_video_border); overlay.add_overlay(bottom_bar_revealer); overlay.add_overlay(header_bar_revealer); + overlay.add_overlay(invite_button_revealer); + overlay.get_child_position.connect(on_get_child_position); event_box.add(overlay); add(event_box); - - Util.force_css(own_video_border, "* { border: 1px solid #616161; background-color: transparent; }"); } public CallWindow() { - event_box.events |= Gdk.EventMask.POINTER_MOTION_MASK; - event_box.events |= Gdk.EventMask.ENTER_NOTIFY_MASK; - event_box.events |= Gdk.EventMask.LEAVE_NOTIFY_MASK; - - this.bind_property("counterpart-display-name", header_bar, "title", BindingFlags.SYNC_CREATE); - this.bind_property("counterpart-display-name", bottom_bar, "counterpart-display-name", BindingFlags.SYNC_CREATE); + this.bind_property("controls-active", bottom_bar_revealer, "reveal-child", BindingFlags.SYNC_CREATE); + this.bind_property("controls-active", header_bar_revealer, "reveal-child", BindingFlags.SYNC_CREATE); + this.bind_property("controls-active", invite_button_revealer, "reveal-child", BindingFlags.SYNC_CREATE); event_box.motion_notify_event.connect(reveal_control_elements); event_box.enter_notify_event.connect(reveal_control_elements); event_box.leave_notify_event.connect(reveal_control_elements); this.configure_event.connect(reveal_control_elements); // upon resizing - this.configure_event.connect(update_own_video_position); + + this.configure_event.connect(reposition_participant_widgets); this.set_titlebar(new OutsideHeaderBar(this.header_bar) { visible=true }); reveal_control_elements(); } - public void set_video_fallback(StreamInteractor stream_interactor, Conversation conversation) { - hide_controll_elements = false; + public void add_participant(string participant, ParticipantWidget participant_widget) { + participant_widget.visible = true; + this.bind_property("controls-active", participant_widget, "controls-active", BindingFlags.SYNC_CREATE); + this.bind_property("controls-active", participant_widget.encryption_button, "controls-active", BindingFlags.SYNC_CREATE); + + participants.add(participant); + participant_widgets[participant] = participant_widget; + grid.attach(participant_widget, 0, 0); + + reposition_participant_widgets(); + } + + public void remove_participant(string participant) { + participants.remove(participant); + grid.remove(participant_widgets[participant]); + participant_widgets.unset(participant); - Box box = new Box(Orientation.HORIZONTAL, 0) { visible=true }; - box.get_style_context().add_class("video-placeholder-box"); - AvatarImage avatar = new AvatarImage() { hexpand=true, vexpand=true, halign=Align.CENTER, valign=Align.CENTER, height=100, width=100, visible=true }; - avatar.set_conversation(stream_interactor, conversation); - box.add(avatar); + reposition_participant_widgets(); + } - set_new_main_widget(box); + public void set_video(string participant, Widget widget) { + participant_widgets[participant].set_video(widget); + hide_control_elements = true; + timeout_hide_control_elements(); } - public void set_video(Widget widget) { - hide_controll_elements = true; + public void set_placeholder(string participant, Conversation? conversation, StreamInteractor stream_interactor) { + participant_widgets[participant].set_placeholder(conversation, stream_interactor); + hide_control_elements = false; + foreach (ParticipantWidget participant_widget in participant_widgets.values) { + if (participant_widget.shows_video) { + hide_control_elements = true; + } + } - widget.visible = true; - set_new_main_widget(widget); + if (!hide_control_elements) { + reveal_control_elements(); + } + } + + private bool reposition_participant_widgets() { + int width, height; + this.get_size(out width,out height); + reposition_participant_widgets_rec(participants, width, height, 0, 0, 0, 0); + return false; + } + + private void reposition_participant_widgets_rec(ArrayList participants, int width, int height, int margin_top, int margin_right, int margin_bottom, int margin_left) { + if (participants.size == 0) return; + + if (participants.size == 1) { + participant_widgets[participants[0]].margin_top = margin_top; + participant_widgets[participants[0]].margin_end = margin_right; + participant_widgets[participants[0]].margin_bottom = margin_bottom; + participant_widgets[participants[0]].margin_start = margin_left; + + participant_widgets[participants[0]].on_lowest_row_changed(margin_bottom == 0); + participant_widgets[participants[0]].on_highest_row_changed(margin_top == 0); + return; + } + + ArrayList first_part = new ArrayList(); + ArrayList last_part = new ArrayList(); + + for (int i = 0; i < participants.size; i++) { + if (i < Math.ceil((double)participants.size / (double)2)) { + first_part.add(participants[i]); + } else { + last_part.add(participants[i]); + } + } + + if (width > height) { + reposition_participant_widgets_rec(first_part, width / 2, height, margin_top, margin_right + width / 2, margin_bottom, margin_left); + reposition_participant_widgets_rec(last_part, width / 2, height, margin_top, margin_right, margin_bottom, margin_left + width / 2); + } else { + reposition_participant_widgets_rec(first_part, width, height / 2, margin_top, margin_right, margin_bottom + height / 2, margin_left); + reposition_participant_widgets_rec(last_part, width, height / 2, margin_top + height / 2, margin_right, margin_bottom, margin_left); + } } public void set_own_video(Widget? widget_) { @@ -92,13 +160,7 @@ namespace Dino.Ui { own_video = new Box(Orientation.HORIZONTAL, 0) { expand=true }; } own_video.visible = true; - own_video.width_request = 150; - own_video.height_request = 100; own_video_box.add(own_video); - - own_video_border.visible = true; - - update_own_video_position(); } public void set_own_video_ratio(int width, int height) { @@ -109,78 +171,25 @@ namespace Dino.Ui { this.own_video_width = width * 100 / height; this.own_video_height = 100; } - - own_video.width_request = own_video_width; - own_video.height_request = own_video_height; - - update_own_video_position(); } public void unset_own_video() { own_video_box.foreach((widget) => { own_video_box.remove(widget); }); - - own_video_border.visible = false; - } - - public void set_test_video() { - hide_controll_elements = true; - - var pipeline = new Gst.Pipeline(null); - var src = Gst.ElementFactory.make("videotestsrc", null); - pipeline.add(src); - Gst.Video.Sink sink = (Gst.Video.Sink) Gst.ElementFactory.make("gtksink", null); - Gtk.Widget widget; - sink.get("widget", out widget); - widget.unparent(); - pipeline.add(sink); - src.link(sink); - widget.visible = true; - - pipeline.set_state(Gst.State.PLAYING); - - sink.get_static_pad("sink").notify["caps"].connect(() => { - int width, height; - sink.get_static_pad("sink").caps.get_structure(0).get_int("width", out width); - sink.get_static_pad("sink").caps.get_structure(0).get_int("height", out height); - widget.width_request = width; - widget.height_request = height; - }); - - set_new_main_widget(widget); } - private void set_new_main_widget(Widget widget) { - if (main_widget != null) overlay.remove(main_widget); - overlay.add(widget); - main_widget = widget; + public void set_status(string participant_id, string state) { + participant_widgets[participant_id].set_status(state); } - public void set_status(string state) { - switch (state) { - case "requested": - header_bar.subtitle = _("Calling…"); - break; - case "ringing": - header_bar.subtitle = _("Ringing…"); - break; - case "establishing": - header_bar.subtitle = _("Connecting…"); - break; - default: - header_bar.subtitle = null; - break; - } - } - - public void show_counterpart_ended(string? reason_name, string? reason_text) { - hide_controll_elements = false; + public void show_counterpart_ended(string who_terminated, string? reason_name, string? reason_text) { + hide_control_elements = false; reveal_control_elements(); string text = ""; if (reason_name == Xmpp.Xep.Jingle.ReasonElement.SUCCESS) { - text = _("%s ended the call").printf(counterpart_display_name); + text = _("%s ended the call").printf(who_terminated); } else if (reason_name == Xmpp.Xep.Jingle.ReasonElement.DECLINE || reason_name == Xmpp.Xep.Jingle.ReasonElement.BUSY) { - text = _("%s declined the call").printf(counterpart_display_name); + text = _("%s declined the call").printf(who_terminated); } else { text = "The call has been terminated: " + (reason_name ?? "") + " " + (reason_text ?? ""); } @@ -188,48 +197,53 @@ namespace Dino.Ui { bottom_bar.show_counterpart_ended(text); } - public bool reveal_control_elements() { + private bool reveal_control_elements() { if (!bottom_bar_revealer.child_revealed) { - bottom_bar_revealer.set_reveal_child(true); - header_bar_revealer.set_reveal_child(true); + controls_active = true; } - if (hide_controll_handler != 0) { - Source.remove(hide_controll_handler); - hide_controll_handler = 0; + timeout_hide_control_elements(); + return false; + } + + private void timeout_hide_control_elements() { + if (hide_control_handler != 0) { + Source.remove(hide_control_handler); + hide_control_handler = 0; } - if (!hide_controll_elements) { - return false; + if (!hide_control_elements) { + return; } - hide_controll_handler = Timeout.add_seconds(3, () => { - if (!hide_controll_elements) { + hide_control_handler = Timeout.add_seconds(3, () => { + if (!hide_control_elements) { return false; } if (bottom_bar.is_menu_active()) { - return true; + return false; } - header_bar_revealer.set_reveal_child(false); - bottom_bar_revealer.set_reveal_child(false); - hide_controll_handler = 0; + controls_active = false; + + hide_control_handler = 0; return false; }); - return false; } - private bool update_own_video_position() { - if (own_video == null) return false; - - int width, height; - this.get_size(out width,out height); - - own_video.margin_end = own_video.margin_bottom = own_video_border.margin_end = own_video_border.margin_bottom = 20; - own_video.margin_start = own_video_border.margin_start = width - own_video_width - 20; - own_video.margin_top = own_video_border.margin_top = height - own_video_height - 20; - + private bool on_get_child_position(Widget widget, out Gdk.Rectangle allocation) { + if (widget == own_video_box) { + int width, height; + this.get_size(out width,out height); + + allocation = Gdk.Rectangle(); + allocation.width = own_video_width; + allocation.height = own_video_height; + allocation.x = width - own_video_width - 20; + allocation.y = height - own_video_height - 20; + return true; + } return false; } } -- cgit v1.2.3-54-g00ecf From f0c7dd0682fec8d72c644d8e54896de7bdc40ddb Mon Sep 17 00:00:00 2001 From: fiaxh Date: Mon, 20 Dec 2021 00:15:05 +0100 Subject: UI + libdino: Improve MUJI calls from MUC - Move calls from ICE-thead onto main thread - Identify Call.ourpart as MUC nick if in MUC - Keep track of the initiator of a call --- libdino/src/entity/call.vala | 9 ++++---- libdino/src/service/call_peer_state.vala | 14 +++++++++---- libdino/src/service/call_state.vala | 9 ++++++-- libdino/src/service/call_store.vala | 9 +++++--- libdino/src/service/calls.vala | 24 ++++++++++++---------- libdino/src/service/content_item_store.vala | 4 ++-- libdino/src/service/muc_manager.vala | 2 +- main/data/call_widget.ui | 2 +- main/src/ui/application.vala | 18 ++++++++++++---- main/src/ui/call_window/call_window.vala | 2 +- .../ui/conversation_content_view/call_widget.vala | 2 +- main/src/ui/conversation_titlebar/call_entry.vala | 18 +++++++++------- main/src/ui/notifier_freedesktop.vala | 6 ++++-- 13 files changed, 75 insertions(+), 44 deletions(-) (limited to 'main/src/ui/call_window/call_window.vala') diff --git a/libdino/src/entity/call.vala b/libdino/src/entity/call.vala index 3b48f664..8e5bc246 100644 --- a/libdino/src/entity/call.vala +++ b/libdino/src/entity/call.vala @@ -20,9 +20,12 @@ namespace Dino.Entities { public int id { get; set; default=-1; } public Account account { get; set; } - public Jid counterpart { get; set; } // For backwards compatibility with db version 21. Not to be used anymore. + public Jid counterpart { get; set; } public Gee.List counterparts = new Gee.ArrayList(Jid.equals_bare_func); public Jid ourpart { get; set; } + public Jid proposer { + get { return direction == DIRECTION_OUTGOING ? ourpart : counterpart; } + } public bool direction { get; set; } public DateTime time { get; set; } public DateTime local_time { get; set; } @@ -58,7 +61,6 @@ namespace Dino.Entities { if (!counterparts.contains(peer)) { // Legacy: The first peer is also in the `call` table. Don't add twice. counterparts.add(peer); } - if (counterpart == null) counterpart = peer; } counterpart = db.get_jid_by_id(row[db.call.counterpart_id]); @@ -66,7 +68,6 @@ namespace Dino.Entities { if (counterpart_resource != null) counterpart = counterpart.with_resource(counterpart_resource); if (counterparts.is_empty) { counterparts.add(counterpart); - counterpart = counterpart; } notify.connect(on_update); @@ -107,8 +108,6 @@ namespace Dino.Entities { } public void add_peer(Jid peer) { - if (counterpart == null) counterpart = peer; - if (counterparts.contains(peer)) return; counterparts.add(peer); diff --git a/libdino/src/service/call_peer_state.vala b/libdino/src/service/call_peer_state.vala index 8c4b0930..09440371 100644 --- a/libdino/src/service/call_peer_state.vala +++ b/libdino/src/service/call_peer_state.vala @@ -127,8 +127,6 @@ public class Dino.PeerState : Object { } public void reject() { - call.state = Call.State.DECLINED; - if (session != null) { foreach (Xep.Jingle.Content content in session.contents) { content.reject(); @@ -299,7 +297,12 @@ public class Dino.PeerState : Object { debug(@"[%s] %s connecting content signals %s", call.account.bare_jid.to_string(), jid.to_string(), rtp_content_parameter.media); rtp_content_parameter.stream_created.connect((stream) => on_stream_created(rtp_content_parameter.media, stream)); - rtp_content_parameter.connection_ready.connect((status) => on_connection_ready(content, rtp_content_parameter.media)); + rtp_content_parameter.connection_ready.connect((status) => { + Idle.add(() => { + on_connection_ready(content, rtp_content_parameter.media); + return false; + }); + }); content.senders_modify_incoming.connect((content, proposed_senders) => { if (content.session.senders_include_us(content.senders) != content.session.senders_include_us(proposed_senders)) { @@ -342,7 +345,10 @@ public class Dino.PeerState : Object { if (media == "video" && stream.receiving) { counterpart_sends_video = true; video_content_parameter.connection_ready.connect((status) => { - counterpart_sends_video_updated(false); + Idle.add(() => { + counterpart_sends_video_updated(false); + return false; + }); }); } diff --git a/libdino/src/service/call_state.vala b/libdino/src/service/call_state.vala index 51563552..188a8321 100644 --- a/libdino/src/service/call_state.vala +++ b/libdino/src/service/call_state.vala @@ -126,7 +126,7 @@ public class Dino.CallState : Object { foreach (PeerState peer in peers_cpy) { peer.end(Xep.Jingle.ReasonElement.CANCEL); } - if (parent_muc != null) { + if (parent_muc != null && group_call != null) { XmppStream stream = stream_interactor.get_stream(call.account); if (stream == null) return; stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite_retract_to_peer(stream, parent_muc, group_call.muc_jid, message_type); @@ -242,7 +242,12 @@ public class Dino.CallState : Object { XmppStream stream = stream_interactor.get_stream(call.account); if (stream == null) return; - Jid muc_jid = stream_interactor.get_module(MucManager.IDENTITY).default_muc_server[call.account] ?? new Jid("chat.jabberfr.org"); + Jid? muc_jid = null; + if (muc_jid == null) { + warning("Failed to initiate group call: MUC server not known."); + return; + } + muc_jid = new Jid("%08x@".printf(Random.next_int()) + muc_jid.to_string()); // TODO longer? debug("[%s] Converting call to groupcall %s", call.account.bare_jid.to_string(), muc_jid.to_string()); diff --git a/libdino/src/service/call_store.vala b/libdino/src/service/call_store.vala index fa6e63ee..bfc8255f 100644 --- a/libdino/src/service/call_store.vala +++ b/libdino/src/service/call_store.vala @@ -30,7 +30,7 @@ namespace Dino { cache_call(call); } - public Call? get_call_by_id(int id) { + public Call? get_call_by_id(int id, Conversation conversation) { Call? call = calls_by_db_id[id]; if (call != null) { return call; @@ -38,14 +38,17 @@ namespace Dino { RowOption row_option = db.call.select().with(db.call.id, "=", id).row(); - return create_call_from_row_opt(row_option); + return create_call_from_row_opt(row_option, conversation); } - private Call? create_call_from_row_opt(RowOption row_opt) { + private Call? create_call_from_row_opt(RowOption row_opt, Conversation conversation) { if (!row_opt.is_present()) return null; try { Call call = new Call.from_row(db, row_opt.inner); + if (conversation.type_.is_muc_semantic()) { + call.ourpart = conversation.counterpart.with_resource(call.ourpart.resourcepart); + } cache_call(call); return call; } catch (InvalidJidError e) { diff --git a/libdino/src/service/calls.vala b/libdino/src/service/calls.vala index 629d8074..3e2181a5 100644 --- a/libdino/src/service/calls.vala +++ b/libdino/src/service/calls.vala @@ -39,9 +39,8 @@ namespace Dino { Call call = new Call(); call.direction = Call.DIRECTION_OUTGOING; call.account = conversation.account; - // TODO we should only do that for Conversation.Type.CHAT, but the database currently requires a counterpart from the start call.counterpart = conversation.counterpart; - call.ourpart = conversation.account.full_jid; + call.ourpart = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account) ?? conversation.account.full_jid; call.time = call.local_time = call.end_time = new DateTime.now_utc(); call.state = Call.State.RINGING; @@ -57,7 +56,7 @@ namespace Dino { PeerState peer_state = call_state.set_first_peer(conversation.counterpart); yield peer_state.initiate_call(conversation.counterpart); } else { - call_state.initiate_groupchat_call(conversation.counterpart); + call_state.initiate_groupchat_call.begin(conversation.counterpart); } conversation.last_active = call.time; @@ -213,24 +212,23 @@ namespace Dino { private PeerState create_received_call(Account account, Jid from, Jid to, bool video_requested) { Call call = new Call(); - Jid counterpart = null; if (from.equals_bare(account.bare_jid)) { // Call requested by another of our devices call.direction = Call.DIRECTION_OUTGOING; call.ourpart = from; call.state = Call.State.OTHER_DEVICE; - counterpart = to; + call.counterpart = to; } else { call.direction = Call.DIRECTION_INCOMING; call.ourpart = account.full_jid; call.state = Call.State.RINGING; - counterpart = from; + call.counterpart = from; } - call.add_peer(counterpart); + call.add_peer(call.counterpart); call.account = account; call.time = call.local_time = call.end_time = new DateTime.now_utc(); - Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(counterpart.bare_jid, account, Conversation.Type.CHAT); + Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(call.counterpart.bare_jid, account, Conversation.Type.CHAT); stream_interactor.get_module(CallStore.IDENTITY).add_call(call, conversation); @@ -238,7 +236,7 @@ namespace Dino { var call_state = new CallState(call, stream_interactor); connect_call_state_signals(call_state); - PeerState peer_state = call_state.set_first_peer(counterpart); + PeerState peer_state = call_state.set_first_peer(call.counterpart); call_state.we_should_send_video = video_requested; call_state.we_should_send_audio = true; @@ -283,7 +281,7 @@ namespace Dino { Call call = new Call(); call.direction = Call.DIRECTION_INCOMING; call.ourpart = account.full_jid; - call.add_peer(inviter_jid); // not rly + call.counterpart = inviter_jid; call.account = account; call.time = call.local_time = call.end_time = new DateTime.now_utc(); call.state = Call.State.RINGING; @@ -361,13 +359,14 @@ namespace Dino { if (from.equals(account.full_jid)) return; Call call = current_jmi_request_peer[account].call; + call.ourpart = from; call.state = Call.State.OTHER_DEVICE; remove_call_from_datastructures(call); } else if (from.equals_bare(current_jmi_request_peer[account].jid) && to.equals(account.full_jid)) { // Message from our peer // We proposed the call // We know the full jid of our peer now current_jmi_request_call[account].rename_peer(current_jmi_request_peer[account].jid, from); - current_jmi_request_peer[account].call_resource(from); + current_jmi_request_peer[account].call_resource.begin(from); } }); mi_module.session_rejected.connect((from, to, sid) => { @@ -378,6 +377,9 @@ namespace Dino { bool incoming_reject = call.direction == Call.DIRECTION_INCOMING && from.equals_bare(account.bare_jid); if (!outgoing_reject && !incoming_reject) return; + // We don't care if a single person in a group call rejected the call + if (incoming_reject && call_states[call].group_call != null) return; + call.state = Call.State.DECLINED; call_states[call].terminated(from, Xep.Jingle.ReasonElement.DECLINE, "JMI reject"); remove_call_from_datastructures(call); diff --git a/libdino/src/service/content_item_store.vala b/libdino/src/service/content_item_store.vala index e0102d24..7a8e38b8 100644 --- a/libdino/src/service/content_item_store.vala +++ b/libdino/src/service/content_item_store.vala @@ -69,7 +69,7 @@ public class ContentItemStore : StreamInteractionModule, Object { } break; case 3: - Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(foreign_id); + Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(foreign_id, conversation); if (call != null) { var call_item = new CallItem(call, conversation, row[db.content_item.id]); items.add(call_item); @@ -321,7 +321,7 @@ public class CallItem : ContentItem { public Conversation conversation; public CallItem(Call call, Conversation conversation, int id) { - base(id, TYPE, call.direction == Call.DIRECTION_OUTGOING ? conversation.account.bare_jid : conversation.counterpart, call.time, call.encryption, Message.Marked.NONE); + base(id, TYPE, call.proposer, call.time, call.encryption, Message.Marked.NONE); this.call = call; this.conversation = conversation; diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala index 8a317a08..05473647 100644 --- a/libdino/src/service/muc_manager.vala +++ b/libdino/src/service/muc_manager.vala @@ -424,7 +424,7 @@ public class MucManager : StreamInteractionModule, Object { foreach (Xep.ServiceDiscovery.Identity identity in identities) { if (identity.category == Xep.ServiceDiscovery.Identity.CATEGORY_CONFERENCE) { default_muc_server[account] = item.jid; - print(@"$(account.bare_jid) Default MUC: $(item.jid)\n"); + debug("[%s] Default MUC: %s", account.bare_jid.to_string(), item.jid.to_string()); return; } } diff --git a/main/data/call_widget.ui b/main/data/call_widget.ui index 8e2ee36c..0c5d8bfa 100644 --- a/main/data/call_widget.ui +++ b/main/data/call_widget.ui @@ -98,7 +98,7 @@ 10 - 5 + 7 True diff --git a/main/src/ui/application.vala b/main/src/ui/application.vala index 9f48caec..ecbea85e 100644 --- a/main/src/ui/application.vala +++ b/main/src/ui/application.vala @@ -206,9 +206,14 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application { }); add_action(open_shortcuts_action); - SimpleAction accept_call_action = new SimpleAction("accept-call", VariantType.INT32); + SimpleAction accept_call_action = new SimpleAction("accept-call", new VariantType.tuple(new VariantType[]{VariantType.INT32, VariantType.INT32})); accept_call_action.activate.connect((variant) => { - Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(variant.get_int32()); + int conversation_id = variant.get_child_value(0).get_int32(); + Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_by_id(conversation_id); + if (conversation == null) return; + + int call_id = variant.get_child_value(1).get_int32(); + Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(call_id, conversation); CallState? call_state = stream_interactor.get_module(Calls.IDENTITY).call_states[call]; if (call_state == null) return; @@ -220,9 +225,14 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application { }); add_action(accept_call_action); - SimpleAction deny_call_action = new SimpleAction("reject-call", VariantType.INT32); + SimpleAction deny_call_action = new SimpleAction("reject-call", new VariantType.tuple(new VariantType[]{VariantType.INT32, VariantType.INT32})); deny_call_action.activate.connect((variant) => { - Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(variant.get_int32()); + int conversation_id = variant.get_child_value(0).get_int32(); + Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_by_id(conversation_id); + if (conversation == null) return; + + int call_id = variant.get_child_value(1).get_int32(); + Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(call_id, conversation); CallState? call_state = stream_interactor.get_module(Calls.IDENTITY).call_states[call]; if (call_state == null) return; diff --git a/main/src/ui/call_window/call_window.vala b/main/src/ui/call_window/call_window.vala index fab424bf..c610444f 100644 --- a/main/src/ui/call_window/call_window.vala +++ b/main/src/ui/call_window/call_window.vala @@ -20,7 +20,7 @@ namespace Dino.Ui { public Revealer header_bar_revealer = new Revealer() { halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true }; public Box own_video_box = new Box(Orientation.HORIZONTAL, 0) { halign=Align.END, valign=Align.END, visible=true }; public Revealer invite_button_revealer = new Revealer() { margin_top=50, margin_right=30, halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200 }; - public Button invite_button = new Button.from_icon_name("dino-account-plus") { relief=ReliefStyle.NONE }; + public Button invite_button = new Button.from_icon_name("dino-account-plus") { relief=ReliefStyle.NONE, visible=false }; private Widget? own_video = null; private HashMap participant_widgets = new HashMap(); private ArrayList participants = new ArrayList(); diff --git a/main/src/ui/conversation_content_view/call_widget.vala b/main/src/ui/conversation_content_view/call_widget.vala index a7d37afd..a2c8c0c2 100644 --- a/main/src/ui/conversation_content_view/call_widget.vala +++ b/main/src/ui/conversation_content_view/call_widget.vala @@ -86,7 +86,7 @@ namespace Dino.Ui { private void update_counterparts() { if (call.state != Call.State.IN_PROGRESS && call.state != Call.State.ENDED) return; - if (call.counterparts.size <= 1) return; + if (call.counterparts.size <= 1 && conversation.type_ == Conversation.Type.CHAT) return; multiparty_peer_box.foreach((widget) => { multiparty_peer_box.remove(widget); }); diff --git a/main/src/ui/conversation_titlebar/call_entry.vala b/main/src/ui/conversation_titlebar/call_entry.vala index 3fa399a6..3b3a5b39 100644 --- a/main/src/ui/conversation_titlebar/call_entry.vala +++ b/main/src/ui/conversation_titlebar/call_entry.vala @@ -115,13 +115,17 @@ namespace Dino.Ui { return; } - Conversation conv_bak = conversation; - bool audio_works = yield stream_interactor.get_module(Calls.IDENTITY).can_do_audio_calls_async(conversation); - bool video_works = yield stream_interactor.get_module(Calls.IDENTITY).can_do_video_calls_async(conversation); - if (conv_bak != conversation) return; - - visible = audio_works; - video_button.visible = video_works; + if (conversation.type_ == Conversation.Type.CHAT) { + Conversation conv_bak = conversation; + bool audio_works = yield stream_interactor.get_module(Calls.IDENTITY).can_do_audio_calls_async(conversation); + bool video_works = yield stream_interactor.get_module(Calls.IDENTITY).can_do_video_calls_async(conversation); + if (conv_bak != conversation) return; + + visible = audio_works; + video_button.visible = video_works; + } else { + visible = false; + } } public new void unset_conversation() { } diff --git a/main/src/ui/notifier_freedesktop.vala b/main/src/ui/notifier_freedesktop.vala index 83e9bf57..e8e2ba1d 100644 --- a/main/src/ui/notifier_freedesktop.vala +++ b/main/src/ui/notifier_freedesktop.vala @@ -141,10 +141,12 @@ public class Dino.Ui.FreeDesktopNotifier : NotificationProvider, Object { GLib.Application.get_default().activate_action("open-conversation", new Variant.int32(conversation.id)); }); add_action_listener(notification_id, "reject", () => { - GLib.Application.get_default().activate_action("reject-call", new Variant.int32(call.id)); + var variant = new Variant.tuple(new Variant[] {new Variant.int32(conversation.id), new Variant.int32(call.id)}); + GLib.Application.get_default().activate_action("reject-call", variant); }); add_action_listener(notification_id, "accept", () => { - GLib.Application.get_default().activate_action("accept-call", new Variant.int32(call.id)); + var variant = new Variant.tuple(new Variant[] {new Variant.int32(conversation.id), new Variant.int32(call.id)}); + GLib.Application.get_default().activate_action("accept-call", variant); }); } catch (Error e) { warning("Failed showing subscription request notification: %s", e.message); -- cgit v1.2.3-54-g00ecf