display groups w/o name by list of members

For members-only, non-anonymous groups that do not have a name set we now
show an automatically generated name that is generated from the list of members
(offline, and online). Only the first name (before the first space) is used
to keep the generated name short.

The term *private room* is coined as a short hand for members only&non-anon group
chats.

This commit also uses the offline members list instead of the online member list
to generate avatar tiles (also only in members-only, non-anon groups.)
This commit is contained in:
Daniel Gultsch 2018-12-04 10:21:24 +01:00 committed by fiaxh
parent 965f4da75a
commit d8e0ab406c
6 changed files with 69 additions and 2 deletions

View File

@ -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<Xep.Bookmarks.Conference> 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<Jid>? get_occupants(Jid jid, Account account) {
if (is_groupchat(jid, account)) {
Gee.List<Jid> ret = new ArrayList<Jid>(Jid.equals_func);
@ -203,6 +217,14 @@ public class MucManager : StreamInteractionModule, Object {
return null;
}
public Gee.List<Jid>? get_other_offline_members(Jid jid, Account account) {
Gee.List<Jid>? 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);

View File

@ -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<Jid>? occupants = muc_manager.get_other_occupants(jid_, account);
Gee.List<Jid>? 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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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<Jid>? 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;

View File

@ -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);