From 2631a9bdbaf9a40f329f05c55c6e2ea38efeb10c Mon Sep 17 00:00:00 2001 From: Anmol Date: Wed, 22 Apr 2020 23:34:03 +0530 Subject: voice handling in moderated groups (#788) --- main/CMakeLists.txt | 1 + main/src/ui/application.vala | 8 +++++ main/src/ui/chat_input/chat_input_controller.vala | 35 +++++++++++++++++++++- main/src/ui/contact_details/dialog.vala | 1 + .../ui/contact_details/permissions_provider.vala | 29 ++++++++++++++++++ main/src/ui/contact_details/settings_provider.vala | 1 + main/src/ui/notifications.vala | 23 ++++++++++++++ main/src/ui/occupant_menu/view.vala | 21 +++++++++++++ 8 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 main/src/ui/contact_details/permissions_provider.vala (limited to 'main') diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 2a247ba9..f0fa550a 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -132,6 +132,7 @@ SOURCES src/ui/contact_details/blocking_provider.vala src/ui/contact_details/settings_provider.vala + src/ui/contact_details/permissions_provider.vala src/ui/contact_details/dialog.vala src/ui/contact_details/muc_config_form_provider.vala diff --git a/main/src/ui/application.vala b/main/src/ui/application.vala index 8738cd53..90c83562 100644 --- a/main/src/ui/application.vala +++ b/main/src/ui/application.vala @@ -138,6 +138,14 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application { }); add_action(accept_muc_invite_action); + SimpleAction accept_voice_request_action = new SimpleAction("accept-voice-request", VariantType.INT32); + accept_voice_request_action.activate.connect((variant) => { + Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_by_id(variant.get_int32()); + if (conversation == null) return; + stream_interactor.get_module(MucManager.IDENTITY).change_role(conversation.account, conversation.counterpart, conversation.nickname, "participant"); + }); + add_action(accept_voice_request_action); + SimpleAction loop_conversations_action = new SimpleAction("loop_conversations", null); loop_conversations_action.activate.connect(() => { window.loop_conversations(false); }); add_action(loop_conversations_action); diff --git a/main/src/ui/chat_input/chat_input_controller.vala b/main/src/ui/chat_input/chat_input_controller.vala index fb7f88b1..55196ea4 100644 --- a/main/src/ui/chat_input/chat_input_controller.vala +++ b/main/src/ui/chat_input/chat_input_controller.vala @@ -5,6 +5,7 @@ using Gtk; using Dino.Entities; namespace Dino.Ui { +private const string OPEN_CONVERSATION_DETAILS_URI = "x-dino:open-conversation-details"; public class ChatInputController : Object { @@ -38,8 +39,19 @@ public class ChatInputController : Object { chat_text_view_controller.send_text.connect(send_text); chat_input.encryption_widget.encryption_changed.connect(on_encryption_changed); - + chat_input.file_button.clicked.connect(() => file_picker_selected()); + + stream_interactor.get_module(MucManager.IDENTITY).received_occupant_role.connect(update_moderated_input_status); + stream_interactor.get_module(MucManager.IDENTITY).room_info_updated.connect(update_moderated_input_status); + + status_description_label.activate_link.connect((uri) => { + if (uri == OPEN_CONVERSATION_DETAILS_URI){ + ContactDetails.Dialog contact_details_dialog = new ContactDetails.Dialog(stream_interactor, conversation); + contact_details_dialog.present(); + } + return true; + }); } public void set_conversation(Conversation conversation) { @@ -51,6 +63,10 @@ public class ChatInputController : Object { chat_input.initialize_for_conversation(conversation); chat_text_view_controller.initialize_for_conversation(conversation); + + Xmpp.Jid? own_jid = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account); + + update_moderated_input_status(conversation.account, own_jid); } public void set_file_upload_active(bool active) { @@ -69,6 +85,10 @@ public class ChatInputController : Object { input_field_status = status; chat_input.set_input_state(status.message_type); + + if (status.contains_markup) status_description_label.use_markup = true; + else status_description_label.use_markup = false; + status_description_label.label = status.message; chat_input.file_button.sensitive = status.input_state == Plugins.InputFieldStatus.InputState.NORMAL; @@ -147,6 +167,19 @@ public class ChatInputController : Object { stream_interactor.get_module(ChatInteraction.IDENTITY).on_message_cleared(conversation); } } + + private void update_moderated_input_status(Account account, Xmpp.Jid jid) { + Xmpp.Jid? own_jid = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account); + if (conversation.type_ == conversation.Type.GROUPCHAT){ + if (stream_interactor.get_module(MucManager.IDENTITY).is_moderated_room(conversation.account, conversation.counterpart) && + stream_interactor.get_module(MucManager.IDENTITY).get_role(own_jid, conversation.account)==Xmpp.Xep.Muc.Role.VISITOR) { + set_input_field_status(new Plugins.InputFieldStatus(_("This conference does not allow you to send messages. %s").printf("" + _("Request permission") + ""), + Plugins.InputFieldStatus.MessageType.ERROR, Plugins.InputFieldStatus.InputState.NO_SEND, true)); + } else { + reset_input_field_status(); + } + } + } private bool on_text_input_key_press(EventKey event) { if (event.keyval == Gdk.Key.Up && chat_input.chat_text_view.text_view.buffer.text == "") { diff --git a/main/src/ui/contact_details/dialog.vala b/main/src/ui/contact_details/dialog.vala index ba9213a8..cf85e691 100644 --- a/main/src/ui/contact_details/dialog.vala +++ b/main/src/ui/contact_details/dialog.vala @@ -46,6 +46,7 @@ public class Dialog : Gtk.Dialog { app.plugin_registry.register_contact_details_entry(new SettingsProvider(stream_interactor)); app.plugin_registry.register_contact_details_entry(new BlockingProvider(stream_interactor)); app.plugin_registry.register_contact_details_entry(new MucConfigFormProvider(stream_interactor)); + app.plugin_registry.register_contact_details_entry(new PermissionsProvider(stream_interactor)); foreach (Plugins.ContactDetailsProvider provider in app.plugin_registry.contact_details_entries) { provider.populate(conversation, contact_details, Plugins.WidgetType.GTK); diff --git a/main/src/ui/contact_details/permissions_provider.vala b/main/src/ui/contact_details/permissions_provider.vala new file mode 100644 index 00000000..1a8649a8 --- /dev/null +++ b/main/src/ui/contact_details/permissions_provider.vala @@ -0,0 +1,29 @@ +using Gtk; + +using Dino.Entities; + +namespace Dino.Ui.ContactDetails { + +public class PermissionsProvider : Plugins.ContactDetailsProvider, Object { + public string id { get { return "permissions"; } } + + private StreamInteractor stream_interactor; + + public PermissionsProvider(StreamInteractor stream_interactor) { + this.stream_interactor = stream_interactor; + } + + public void populate(Conversation conversation, Plugins.ContactDetails contact_details, Plugins.WidgetType type) { + if (type != Plugins.WidgetType.GTK) return; + + Xmpp.Jid? own_jid = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account); + if (stream_interactor.get_module(MucManager.IDENTITY).get_role(own_jid, conversation.account)==Xmpp.Xep.Muc.Role.VISITOR){ + Button voice_request = new Button() {visible=true, label=_("Request")}; + voice_request.clicked.connect(()=>stream_interactor.get_module(MucManager.IDENTITY).request_voice(conversation.account, conversation.counterpart)); + contact_details.add(_("Permissions"), _("Request permission to send messages"), "", voice_request); + + } + } +} + +} diff --git a/main/src/ui/contact_details/settings_provider.vala b/main/src/ui/contact_details/settings_provider.vala index adc2e371..262029a2 100644 --- a/main/src/ui/contact_details/settings_provider.vala +++ b/main/src/ui/contact_details/settings_provider.vala @@ -45,6 +45,7 @@ public class SettingsProvider : Plugins.ContactDetailsProvider, Object { combobox.append("on", get_notify_setting_string(Conversation.NotifySetting.ON)); combobox.append("off", get_notify_setting_string(Conversation.NotifySetting.OFF)); contact_details.add(DETAILS_HEADLINE_ROOM, _("Notifications"), "", combobox); + combobox.active_id = get_notify_setting_id(conversation.notify_setting); combobox.changed.connect(() => { conversation.notify_setting = get_notify_setting(combobox.active_id); } ); } diff --git a/main/src/ui/notifications.vala b/main/src/ui/notifications.vala index 7b45a46e..dc73bda5 100644 --- a/main/src/ui/notifications.vala +++ b/main/src/ui/notifications.vala @@ -43,6 +43,7 @@ public class Notifications : Object { stream_interactor.get_module(NotificationEvents.IDENTITY).notify_subscription_request.connect(notify_subscription_request); stream_interactor.get_module(NotificationEvents.IDENTITY).notify_connection_error.connect(notify_connection_error); stream_interactor.get_module(NotificationEvents.IDENTITY).notify_muc_invite.connect(on_invite_received); + stream_interactor.get_module(NotificationEvents.IDENTITY).notify_voice_request.connect(on_voice_request_received); } private async void notify_content_item(ContentItem content_item, Conversation conversation) { @@ -140,6 +141,28 @@ public class Notifications : Object { notification.add_button_with_target_value(_("Accept"), "app.open-muc-join", group_conversation.id); GLib.Application.get_default().send_notification(null, notification); } + + private async void on_voice_request_received(Account account, Jid room_jid, Jid from_jid, string? nick, string? role, string? label) { + Conversation? direct_conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(room_jid, account, Conversation.Type.GROUPCHAT); + if (direct_conversation == null) return; + string display_name = Util.get_participant_display_name(stream_interactor, direct_conversation, from_jid); + string display_room = room_jid.bare_jid.to_string(); + Notification notification = new Notification(_("Permission request")); + string body = _("%s requests the permission to write in %s").printf(display_name, display_room); + notification.set_body(body); + + try { + Cairo.ImageSurface jid_avatar = (yield Util.get_conversation_avatar_drawer(stream_interactor, direct_conversation)).size(40, 40).draw_image_surface(); + notification.set_icon(get_pixbuf_icon(jid_avatar)); + } catch (Error e) { } + + Conversation group_conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(room_jid, account, Conversation.Type.GROUPCHAT); + group_conversation.nickname = nick; + notification.set_default_action_and_target_value("app.accept-voice-request", new Variant.int32(group_conversation.id)); + notification.add_button_with_target_value(_("Deny"), "app.deny-voice-request", group_conversation.id); + notification.add_button_with_target_value(_("Accept"), "app.accept-voice-request", group_conversation.id); + GLib.Application.get_default().send_notification(null, notification); + } 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()); diff --git a/main/src/ui/occupant_menu/view.vala b/main/src/ui/occupant_menu/view.vala index 958a4aa3..a512ff24 100644 --- a/main/src/ui/occupant_menu/view.vala +++ b/main/src/ui/occupant_menu/view.vala @@ -97,6 +97,21 @@ public class View : Popover { outer_box.add(kick_button); kick_button.clicked.connect(kick_button_clicked); } + if (stream_interactor.get_module(MucManager.IDENTITY).is_moderated_room(conversation.account, conversation.counterpart) && role == Xmpp.Xep.Muc.Role.MODERATOR){ + if (stream_interactor.get_module(MucManager.IDENTITY).get_role(selected_jid, conversation.account) == Xmpp.Xep.Muc.Role.VISITOR) { + ModelButton voice_button = new ModelButton() { active=true, text=_("Grant write permission"), visible=true }; + outer_box.add(voice_button); + voice_button.clicked.connect(() => + voice_button_clicked("participant")); + } + else if (stream_interactor.get_module(MucManager.IDENTITY).get_role(selected_jid, conversation.account) == Xmpp.Xep.Muc.Role.PARTICIPANT){ + ModelButton voice_button = new ModelButton() { active=true, text=_("Revoke write permission"), visible=true }; + outer_box.add(voice_button); + voice_button.clicked.connect(() => + voice_button_clicked("visitor")); + } + + } if (jid_menu != null) jid_menu.destroy(); stack.add_named(outer_box, "menu"); @@ -119,6 +134,12 @@ public class View : Popover { stream_interactor.get_module(MucManager.IDENTITY).kick(conversation.account, conversation.counterpart, selected_jid.resourcepart); } + + private void voice_button_clicked(string role) { + if (selected_jid == null) return; + + stream_interactor.get_module(MucManager.IDENTITY).change_role(conversation.account, conversation.counterpart, selected_jid.resourcepart, role); + } } } -- cgit v1.2.3-70-g09d2