diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala index 9856e229..243aeb1c 100644 --- a/libdino/src/service/muc_manager.vala +++ b/libdino/src/service/muc_manager.vala @@ -13,6 +13,7 @@ public class MucManager : StreamInteractionModule, Object { public signal void left(Account account, Jid jid); public signal void subject_set(Account account, Jid jid, string? subject); public signal void room_name_set(Account account, Jid jid, string? room_name); + public signal void private_room_occupant_updated(Account account, Jid room, Jid occupant); public signal void bookmarks_updated(Account account, Gee.List conferences); private StreamInteractor stream_interactor; @@ -97,6 +98,19 @@ public class MucManager : StreamInteractionModule, Object { return false; } + //the term `private room` is a short hand for members-only+non-anonymous rooms + public bool is_private_room(Account account, Jid jid) { + XmppStream? stream = stream_interactor.get_stream(account); + if (stream == null) { + return false; + } + Xep.Muc.Flag? flag = stream.get_flag(Xep.Muc.Flag.IDENTITY); + if (flag == null) { + return false; + } + return flag.has_room_feature(jid, Xep.Muc.Feature.NON_ANONYMOUS) && flag.has_room_feature(jid, Xep.Muc.Feature.MEMBERS_ONLY); + } + public Gee.List? get_occupants(Jid jid, Account account) { if (is_groupchat(jid, account)) { Gee.List ret = new ArrayList(Jid.equals_func); @@ -203,6 +217,14 @@ public class MucManager : StreamInteractionModule, Object { return null; } + public Gee.List? get_other_offline_members(Jid jid, Account account) { + Gee.List? occupants = get_offline_members(jid, account); + if (occupants != null) { + occupants.remove(account.bare_jid); + } + return occupants; + } + public Jid? get_own_jid(Jid muc_jid, Account account) { Xep.Muc.Flag? flag = get_muc_flag(account); if (flag != null) { @@ -241,6 +263,11 @@ public class MucManager : StreamInteractionModule, Object { stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_name_set.connect( (stream, jid, room_name) => { room_name_set(account, jid, room_name); }); + stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).received_occupant_jid.connect( (stream, room, occupant) => { + if (is_private_room(account, room.bare_jid)) { + private_room_occupant_updated(account, room, occupant); + } + }); stream_interactor.module_manager.get_module(account, Xep.Bookmarks.Module.IDENTITY).received_conferences.connect( (stream, conferences) => { sync_autojoin_active(account, conferences); bookmarks_updated(account, conferences); diff --git a/main/src/ui/avatar_image.vala b/main/src/ui/avatar_image.vala index bf6cb9f4..f6140c26 100644 --- a/main/src/ui/avatar_image.vala +++ b/main/src/ui/avatar_image.vala @@ -194,6 +194,7 @@ public class AvatarImage : Misc { stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.disconnect(on_received_avatar); stream_interactor.connection_manager.connection_state_changed.disconnect(on_connection_changed); stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.disconnect(on_roster_updated); + stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.disconnect(on_occupant_updated); } } @@ -205,10 +206,16 @@ public class AvatarImage : Misc { stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.connect(on_received_avatar); stream_interactor.connection_manager.connection_state_changed.connect(on_connection_changed); stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect(on_roster_updated); + stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect(on_occupant_updated); } if (muc_manager.is_groupchat(jid_, account) && avatar_manager.get_avatar(account, jid_) == null) { // Groupchat without avatar - Gee.List? occupants = muc_manager.get_other_occupants(jid_, account); + Gee.List? occupants; + if (muc_manager.is_private_room(account, jid_)) { + occupants = muc_manager.get_other_offline_members(jid_, account); + } else { + occupants = muc_manager.get_other_occupants(jid_, account); + } jid = jid_; if (occupants == null || occupants.size == 0) { if (force_update || current_jids.length != 1 || !current_jids[0].equals(jid_) || gray != (allow_gray && (occupants == null || !is_self_online()))) { @@ -292,6 +299,12 @@ public class AvatarImage : Misc { set_jid(stream_interactor, this.jid, account, true); } + private void on_occupant_updated(Account account, Jid room, Jid occupant) { + if (!account.equals(this.account)) return; + if (!room.equals_bare(this.jid)) return; + set_jid(stream_interactor, this.jid, account, true); + } + private bool is_self_online() { return stream_interactor.connection_manager.get_state(account) == ConnectionManager.ConnectionState.CONNECTED; } diff --git a/main/src/ui/conversation_selector/conversation_row.vala b/main/src/ui/conversation_selector/conversation_row.vala index 6327e07d..992cf107 100644 --- a/main/src/ui/conversation_selector/conversation_row.vala +++ b/main/src/ui/conversation_selector/conversation_row.vala @@ -59,6 +59,11 @@ public class ConversationRow : ListBoxRow { update_name_label(); } }); + stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect((account, room, occupant) => { + if (conversation != null && conversation.counterpart.equals_bare(room.bare_jid) && conversation.account.equals(account)) { + update_name_label(); + } + }); break; case Conversation.Type.GROUPCHAT_PM: break; diff --git a/main/src/ui/conversation_titlebar/view.vala b/main/src/ui/conversation_titlebar/view.vala index 7ee47311..7ced9830 100644 --- a/main/src/ui/conversation_titlebar/view.vala +++ b/main/src/ui/conversation_titlebar/view.vala @@ -42,6 +42,12 @@ public class ConversationTitlebar : Gtk.HeaderBar { } }); + stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect((account, room, occupant) => { + if (conversation != null && conversation.counterpart.equals_bare(room.bare_jid) && conversation.account.equals(account)) { + update_title(); + } + }); + stream_interactor.get_module(MucManager.IDENTITY).subject_set.connect((account, jid, subject) => { if (conversation != null && conversation.counterpart.equals_bare(jid) && conversation.account.equals(account)) { update_subtitle(subject); diff --git a/main/src/ui/util/helper.vala b/main/src/ui/util/helper.vala index 2f2bb84d..da854513 100644 --- a/main/src/ui/util/helper.vala +++ b/main/src/ui/util/helper.vala @@ -60,10 +60,25 @@ public static string get_conversation_display_name(StreamInteractor stream_inter public static string get_display_name(StreamInteractor stream_interactor, Jid jid, Account account) { if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(jid, account)) { - string room_name = stream_interactor.get_module(MucManager.IDENTITY).get_room_name(account, jid); + MucManager muc_manager = stream_interactor.get_module(MucManager.IDENTITY); + string room_name = muc_manager.get_room_name(account, jid); if (room_name != null && room_name != jid.localpart) { return room_name; } + if (muc_manager.is_private_room(account, jid)) { + Gee.List? other_occupants = muc_manager.get_other_offline_members(jid, account); + if (other_occupants != null && other_occupants.size > 0) { + var builder = new StringBuilder (); + foreach(Jid occupant in other_occupants) { + + if (builder.len != 0) { + builder.append(", "); + } + builder.append(get_display_name(stream_interactor, occupant, account).split(" ")[0]); + } + return builder.str; + } + } return jid.bare_jid.to_string(); } else if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account)) { return jid.resourcepart; diff --git a/xmpp-vala/src/module/xep/0045_muc/module.vala b/xmpp-vala/src/module/xep/0045_muc/module.vala index 955ea89b..7b136d8c 100644 --- a/xmpp-vala/src/module/xep/0045_muc/module.vala +++ b/xmpp-vala/src/module/xep/0045_muc/module.vala @@ -381,6 +381,7 @@ public class Module : XmppStreamModule { if (jid_ != null && affiliation_ != null) { stream.get_flag(Flag.IDENTITY).set_offline_member(iq.from, jid_, parse_affiliation(affiliation_)); ret_jids.add(jid_); + received_occupant_jid(stream, iq.from, jid_); } } if (listener != null) listener(stream, ret_jids);