parent
de3af0ae24
commit
e330e60f83
|
@ -142,8 +142,8 @@ public class MucManager : StreamInteractionModule, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool is_groupchat(Jid jid, Account account) {
|
public bool is_groupchat(Jid jid, Account account) {
|
||||||
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account);
|
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account, Conversation.Type.GROUPCHAT);
|
||||||
return !jid.is_full() && conversation != null && conversation.type_ == Conversation.Type.GROUPCHAT;
|
return !jid.is_full() && conversation != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool is_groupchat_occupant(Jid jid, Account account) {
|
public bool is_groupchat_occupant(Jid jid, Account account) {
|
||||||
|
|
|
@ -133,27 +133,29 @@ public class SearchProcessor : StreamInteractionModule, Object {
|
||||||
.order_by(db.conversation.last_active, "DESC");
|
.order_by(db.conversation.last_active, "DESC");
|
||||||
foreach(Row chat in chats) {
|
foreach(Row chat in chats) {
|
||||||
if (suggestions.size == 0) {
|
if (suggestions.size == 0) {
|
||||||
suggestions.add(new SearchSuggestion(new Account.from_row(db, chat), new Jid(chat[db.jid.bare_jid]), "from:"+chat[db.jid.bare_jid], after_prev_space, next_space));
|
suggestions.add(new SearchSuggestion(new Conversation.from_row(db, chat), new Jid(chat[db.jid.bare_jid]), "from:"+chat[db.jid.bare_jid], after_prev_space, next_space));
|
||||||
}
|
}
|
||||||
suggestions.add(new SearchSuggestion(new Account.from_row(db, chat), new Jid(chat[db.account.bare_jid]), "from:"+chat[db.account.bare_jid], after_prev_space, next_space));
|
suggestions.add(new SearchSuggestion(new Conversation.from_row(db, chat), new Jid(chat[db.account.bare_jid]), "from:"+chat[db.account.bare_jid], after_prev_space, next_space));
|
||||||
}
|
}
|
||||||
return suggestions;
|
return suggestions;
|
||||||
}
|
}
|
||||||
if (current_in != null) {
|
if (current_in != null) {
|
||||||
// All members of the MUC with history
|
// All members of the MUC with history
|
||||||
QueryBuilder msgs = db.message.select()
|
QueryBuilder msgs = db.message.select()
|
||||||
.select_string(@"account.*, $(db.message.counterpart_resource)")
|
.select_string(@"account.*, $(db.message.counterpart_resource), conversation.*")
|
||||||
.join_with(db.jid, db.jid.id, db.message.counterpart_id)
|
.join_with(db.jid, db.jid.id, db.message.counterpart_id)
|
||||||
.join_with(db.account, db.account.id, db.message.account_id)
|
.join_with(db.account, db.account.id, db.message.account_id)
|
||||||
|
.join_on(db.conversation, @"$(db.conversation.account_id)=$(db.account.id) AND $(db.conversation.jid_id)=$(db.jid.id)")
|
||||||
.with(db.jid.bare_jid, "=", current_in)
|
.with(db.jid.bare_jid, "=", current_in)
|
||||||
.with(db.account.enabled, "=", true)
|
.with(db.account.enabled, "=", true)
|
||||||
.with(db.message.type_, "=", Message.Type.GROUPCHAT)
|
.with(db.message.type_, "=", Message.Type.GROUPCHAT)
|
||||||
|
.with(db.conversation.type_, "=", Conversation.Type.GROUPCHAT)
|
||||||
.with(db.message.counterpart_resource, "LIKE", @"%$current_from%")
|
.with(db.message.counterpart_resource, "LIKE", @"%$current_from%")
|
||||||
.group_by({db.message.counterpart_resource})
|
.group_by({db.message.counterpart_resource})
|
||||||
.order_by_name(@"MAX($(db.message.time))", "DESC")
|
.order_by_name(@"MAX($(db.message.time))", "DESC")
|
||||||
.limit(5);
|
.limit(5);
|
||||||
foreach(Row msg in msgs) {
|
foreach(Row msg in msgs) {
|
||||||
suggestions.add(new SearchSuggestion(new Account.from_row(db, msg), new Jid(current_in).with_resource(msg[db.message.counterpart_resource]), "from:"+msg[db.message.counterpart_resource], after_prev_space, next_space));
|
suggestions.add(new SearchSuggestion(new Conversation.from_row(db, msg), new Jid(current_in).with_resource(msg[db.message.counterpart_resource]), "from:"+msg[db.message.counterpart_resource], after_prev_space, next_space));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: auto complete from
|
// TODO: auto complete from
|
||||||
|
@ -179,7 +181,7 @@ public class SearchProcessor : StreamInteractionModule, Object {
|
||||||
.order_by(db.conversation.last_active, "DESC")
|
.order_by(db.conversation.last_active, "DESC")
|
||||||
.limit(limit);
|
.limit(limit);
|
||||||
foreach(Row chat in chats) {
|
foreach(Row chat in chats) {
|
||||||
suggestions.add(new SearchSuggestion(new Account.from_row(db, chat), new Jid(chat[db.jid.bare_jid]), "with:"+chat[db.jid.bare_jid], after_prev_space, next_space) { order = chat[db.conversation.last_active]});
|
suggestions.add(new SearchSuggestion(new Conversation.from_row(db, chat), new Jid(chat[db.jid.bare_jid]), "with:"+chat[db.jid.bare_jid], after_prev_space, next_space) { order = chat[db.conversation.last_active]});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Groupchat PM
|
// Groupchat PM
|
||||||
|
@ -193,7 +195,7 @@ public class SearchProcessor : StreamInteractionModule, Object {
|
||||||
.order_by(db.conversation.last_active, "DESC")
|
.order_by(db.conversation.last_active, "DESC")
|
||||||
.limit(limit - suggestions.size);
|
.limit(limit - suggestions.size);
|
||||||
foreach(Row chat in chats) {
|
foreach(Row chat in chats) {
|
||||||
suggestions.add(new SearchSuggestion(new Account.from_row(db, chat), new Jid(chat[db.jid.bare_jid]).with_resource(chat[db.conversation.resource]), "with:"+chat[db.jid.bare_jid]+"/"+chat[db.conversation.resource], after_prev_space, next_space) { order = chat[db.conversation.last_active]});
|
suggestions.add(new SearchSuggestion(new Conversation.from_row(db, chat), new Jid(chat[db.jid.bare_jid]).with_resource(chat[db.conversation.resource]), "with:"+chat[db.jid.bare_jid]+"/"+chat[db.conversation.resource], after_prev_space, next_space) { order = chat[db.conversation.last_active]});
|
||||||
}
|
}
|
||||||
suggestions.sort((a, b) => (int)(b.order - a.order));
|
suggestions.sort((a, b) => (int)(b.order - a.order));
|
||||||
}
|
}
|
||||||
|
@ -216,7 +218,7 @@ public class SearchProcessor : StreamInteractionModule, Object {
|
||||||
.order_by(db.conversation.last_active, "DESC")
|
.order_by(db.conversation.last_active, "DESC")
|
||||||
.limit(limit);
|
.limit(limit);
|
||||||
foreach(Row chat in groupchats) {
|
foreach(Row chat in groupchats) {
|
||||||
suggestions.add(new SearchSuggestion(new Account.from_row(db, chat), new Jid(chat[db.jid.bare_jid]), "in:"+chat[db.jid.bare_jid], after_prev_space, next_space));
|
suggestions.add(new SearchSuggestion(new Conversation.from_row(db, chat), new Jid(chat[db.jid.bare_jid]), "in:"+chat[db.jid.bare_jid], after_prev_space, next_space));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Other auto complete?
|
// Other auto complete?
|
||||||
|
@ -244,15 +246,16 @@ public class SearchProcessor : StreamInteractionModule, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SearchSuggestion : Object {
|
public class SearchSuggestion : Object {
|
||||||
public Account account { get; private set; }
|
public Account account { get { return conversation.account; } }
|
||||||
|
public Conversation conversation { get; private set; }
|
||||||
public Jid? jid { get; private set; }
|
public Jid? jid { get; private set; }
|
||||||
public string completion { get; private set; }
|
public string completion { get; private set; }
|
||||||
public int start_index { get; private set; }
|
public int start_index { get; private set; }
|
||||||
public int end_index { get; private set; }
|
public int end_index { get; private set; }
|
||||||
public long order { get; set; }
|
public long order { get; set; }
|
||||||
|
|
||||||
public SearchSuggestion(Account account, Jid? jid, string completion, int start_index, int end_index) {
|
public SearchSuggestion(Conversation conversation, Jid? jid, string completion, int start_index, int end_index) {
|
||||||
this.account = account;
|
this.conversation = conversation;
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
this.completion = completion;
|
this.completion = completion;
|
||||||
this.start_index = start_index;
|
this.start_index = start_index;
|
||||||
|
|
|
@ -58,6 +58,13 @@ public class StreamInteractor : Object {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T? get<T>() {
|
||||||
|
foreach (StreamInteractionModule module in modules) {
|
||||||
|
if (module.get_type() == typeof(T)) return (T?) module;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void on_stream_opened(Account account, XmppStream stream) {
|
private void on_stream_opened(Account account, XmppStream stream) {
|
||||||
stream.stream_negotiated.connect( (stream) => {
|
stream.stream_negotiated.connect( (stream) => {
|
||||||
stream_negotiated(account, stream);
|
stream_negotiated(account, stream);
|
||||||
|
|
|
@ -91,7 +91,7 @@ SOURCES
|
||||||
src/main.vala
|
src/main.vala
|
||||||
|
|
||||||
src/ui/application.vala
|
src/ui/application.vala
|
||||||
src/ui/avatar_generator.vala
|
src/ui/avatar_drawer.vala
|
||||||
src/ui/avatar_image.vala
|
src/ui/avatar_image.vala
|
||||||
src/ui/chat_input_controller.vala
|
src/ui/chat_input_controller.vala
|
||||||
src/ui/conversation_list_titlebar.vala
|
src/ui/conversation_list_titlebar.vala
|
||||||
|
|
|
@ -118,7 +118,7 @@ internal class ConferenceListRow : ListRow {
|
||||||
via_label.visible = false;
|
via_label.visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
image.set_jid(stream_interactor, jid, account);
|
image.set_conversation(stream_interactor, new Conversation(jid, account, Conversation.Type.GROUPCHAT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@ public class ListRow : ListBoxRow {
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
|
||||||
string display_name = Util.get_display_name(stream_interactor, jid, account);
|
Conversation conv = new Conversation(jid, account, Conversation.Type.CHAT);
|
||||||
|
string display_name = Util.get_conversation_display_name(stream_interactor, conv);
|
||||||
if (show_account && stream_interactor.get_accounts().size > 1) {
|
if (show_account && stream_interactor.get_accounts().size > 1) {
|
||||||
via_label.label = @"via $(account.bare_jid)";
|
via_label.label = @"via $(account.bare_jid)";
|
||||||
this.has_tooltip = true;
|
this.has_tooltip = true;
|
||||||
|
@ -33,7 +34,7 @@ public class ListRow : ListBoxRow {
|
||||||
via_label.visible = false;
|
via_label.visible = false;
|
||||||
}
|
}
|
||||||
name_label.label = display_name;
|
name_label.label = display_name;
|
||||||
image.set_jid(stream_interactor, jid, account);
|
image.set_conversation(stream_interactor, conv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
192
main/src/ui/avatar_drawer.vala
Normal file
192
main/src/ui/avatar_drawer.vala
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
using Cairo;
|
||||||
|
using Gee;
|
||||||
|
using Gdk;
|
||||||
|
using Gtk;
|
||||||
|
using Xmpp.Util;
|
||||||
|
|
||||||
|
namespace Dino.Ui {
|
||||||
|
|
||||||
|
public class AvatarDrawer {
|
||||||
|
public const string GRAY = "555753";
|
||||||
|
|
||||||
|
private Gee.List<AvatarTile> tiles = new ArrayList<AvatarTile>();
|
||||||
|
private int height = 35;
|
||||||
|
private int width = 35;
|
||||||
|
private bool gray;
|
||||||
|
private int base_factor = 1;
|
||||||
|
private string font_family = "Sans";
|
||||||
|
|
||||||
|
public AvatarDrawer size(int height, int width = height) {
|
||||||
|
this.height = height;
|
||||||
|
this.width = width;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AvatarDrawer grayscale() {
|
||||||
|
this.gray = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AvatarDrawer tile(Pixbuf? image, string? name, string? hex_color) {
|
||||||
|
tiles.add(new AvatarTile(image, name, hex_color));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AvatarDrawer plus() {
|
||||||
|
tiles.add(new AvatarTile(null, "…", GRAY));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AvatarDrawer scale(int base_factor) {
|
||||||
|
this.base_factor = base_factor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AvatarDrawer font(string font_family) {
|
||||||
|
this.font_family = font_family;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageSurface draw_image_surface() {
|
||||||
|
ImageSurface surface = new ImageSurface(Format.ARGB32, width, height);
|
||||||
|
draw_on_context(new Context(surface));
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw_on_context(Cairo.Context ctx) {
|
||||||
|
double radius = 3 * base_factor;
|
||||||
|
double degrees = Math.PI / 180.0;
|
||||||
|
ctx.new_sub_path();
|
||||||
|
ctx.arc(width - radius, radius, radius, -90 * degrees, 0 * degrees);
|
||||||
|
ctx.arc(width - radius, height - radius, radius, 0 * degrees, 90 * degrees);
|
||||||
|
ctx.arc(radius, height - radius, radius, 90 * degrees, 180 * degrees);
|
||||||
|
ctx.arc(radius, radius, radius, 180 * degrees, 270 * degrees);
|
||||||
|
ctx.close_path();
|
||||||
|
ctx.clip();
|
||||||
|
|
||||||
|
if (this.tiles.size == 4) {
|
||||||
|
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
||||||
|
Cairo.Context bufctx = new Cairo.Context(buffer);
|
||||||
|
bufctx.scale(0.5, 0.5);
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 0, width - 1, height - 1, 2 * base_factor), 0, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 1, width - 1, height - 1, 2 * base_factor), width + 1, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 2, width - 1, height - 1, 2 * base_factor), 0, height + 1);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 3, width - 1, height - 1, 2 * base_factor), width + 1, height + 1);
|
||||||
|
bufctx.paint();
|
||||||
|
|
||||||
|
ctx.set_source_surface(buffer, 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else if (this.tiles.size == 3) {
|
||||||
|
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
||||||
|
Cairo.Context bufctx = new Cairo.Context(buffer);
|
||||||
|
bufctx.scale(0.5, 0.5);
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 0, width - 1, height - 1, 2 * base_factor), 0, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 1, width - 1, height * 2, 2 * base_factor), width + 1, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 2, width - 1, height - 1, 2 * base_factor), 0, height + 1);
|
||||||
|
bufctx.paint();
|
||||||
|
|
||||||
|
ctx.set_source_surface(buffer, 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else if (this.tiles.size == 2) {
|
||||||
|
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
||||||
|
Cairo.Context bufctx = new Cairo.Context(buffer);
|
||||||
|
bufctx.scale(0.5, 0.5);
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 0, width - 1, height * 2, 2 * base_factor), 0, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface_idx(ctx, 1, width - 1, height * 2, 2 * base_factor), width + 1, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
|
||||||
|
ctx.set_source_surface(buffer, 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else if (this.tiles.size == 1) {
|
||||||
|
ctx.set_source_surface(sub_surface_idx(ctx, 0, width, height, base_factor), 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else if (this.tiles.size == 0) {
|
||||||
|
ctx.set_source_surface(sub_surface_idx(ctx, -1, width, height, base_factor), 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gray) {
|
||||||
|
// convert to greyscale
|
||||||
|
ctx.set_operator(Cairo.Operator.HSL_COLOR);
|
||||||
|
ctx.set_source_rgb(1, 1, 1);
|
||||||
|
ctx.rectangle(0, 0, width, height);
|
||||||
|
ctx.fill();
|
||||||
|
// make the visible part more light
|
||||||
|
ctx.set_operator(Cairo.Operator.ATOP);
|
||||||
|
ctx.set_source_rgba(1, 1, 1, 0.7);
|
||||||
|
ctx.rectangle(0, 0, width, height);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cairo.Surface sub_surface_idx(Cairo.Context ctx, int idx, int width, int height, int font_factor = 1) {
|
||||||
|
Gdk.Pixbuf? avatar = idx >= 0 ? tiles[idx].image : null;
|
||||||
|
string? name = idx >= 0 ? tiles[idx].name : "";
|
||||||
|
string hex_color = !gray && idx >= 0 ? tiles[idx].hex_color : GRAY;
|
||||||
|
return sub_surface(ctx, font_family, avatar, name, hex_color, width, height, font_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Cairo.Surface sub_surface(Cairo.Context ctx, string font_family, Gdk.Pixbuf? avatar, string? name, string? hex_color, int width, int height, int font_factor = 1) {
|
||||||
|
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
||||||
|
Cairo.Context bufctx = new Cairo.Context(buffer);
|
||||||
|
if (avatar == null) {
|
||||||
|
set_source_hex_color(bufctx, hex_color ?? GRAY);
|
||||||
|
bufctx.rectangle(0, 0, width, height);
|
||||||
|
bufctx.fill();
|
||||||
|
|
||||||
|
string text = name == null ? "…" : name.get_char(0).toupper().to_string();
|
||||||
|
bufctx.select_font_face(font_family, Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL);
|
||||||
|
bufctx.set_font_size(width / font_factor < 40 ? font_factor * 17 : font_factor * 25);
|
||||||
|
Cairo.TextExtents extents;
|
||||||
|
bufctx.text_extents(text, out extents);
|
||||||
|
double x_pos = width/2 - (extents.width/2 + extents.x_bearing);
|
||||||
|
double y_pos = height/2 - (extents.height/2 + extents.y_bearing);
|
||||||
|
bufctx.move_to(x_pos, y_pos);
|
||||||
|
bufctx.set_source_rgba(1, 1, 1, 1);
|
||||||
|
bufctx.show_text(text);
|
||||||
|
} else {
|
||||||
|
double w_scale = (double) width / avatar.width;
|
||||||
|
double h_scale = (double) height / avatar.height;
|
||||||
|
double scale = double.max(w_scale, h_scale);
|
||||||
|
bufctx.scale(scale, scale);
|
||||||
|
|
||||||
|
double x_off = 0, y_off = 0;
|
||||||
|
if (scale == h_scale) {
|
||||||
|
x_off = (width / scale - avatar.width) / 2.0;
|
||||||
|
} else {
|
||||||
|
y_off = (height / scale - avatar.height) / 2.0;
|
||||||
|
}
|
||||||
|
Gdk.cairo_set_source_pixbuf(bufctx, avatar, x_off, y_off);
|
||||||
|
bufctx.get_source().set_filter(Cairo.Filter.BEST);
|
||||||
|
bufctx.paint();
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void set_source_hex_color(Cairo.Context ctx, string hex_color) {
|
||||||
|
ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255,
|
||||||
|
(double) from_hex(hex_color.substring(2, 2)) / 255,
|
||||||
|
(double) from_hex(hex_color.substring(4, 2)) / 255,
|
||||||
|
hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AvatarTile {
|
||||||
|
public Pixbuf? image { get; private set; }
|
||||||
|
public string? name { get; private set; }
|
||||||
|
public string? hex_color { get; private set; }
|
||||||
|
|
||||||
|
public AvatarTile(Pixbuf? image, string? name, string? hex_color) {
|
||||||
|
this.image = image;
|
||||||
|
this.name = name;
|
||||||
|
this.hex_color = hex_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,270 +0,0 @@
|
||||||
using Cairo;
|
|
||||||
using Gee;
|
|
||||||
using Gdk;
|
|
||||||
using Gtk;
|
|
||||||
|
|
||||||
using Dino.Entities;
|
|
||||||
using Xmpp;
|
|
||||||
using Xmpp.Util;
|
|
||||||
|
|
||||||
namespace Dino.Ui {
|
|
||||||
|
|
||||||
public class AvatarGenerator {
|
|
||||||
|
|
||||||
private const string COLOR_GREY = "E0E0E0";
|
|
||||||
private const string GROUPCHAT_ICON = "system-users-symbolic";
|
|
||||||
|
|
||||||
StreamInteractor? stream_interactor;
|
|
||||||
bool greyscale = false;
|
|
||||||
bool stateless = false;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int scale_factor;
|
|
||||||
|
|
||||||
public AvatarGenerator(int width, int height, int scale_factor = 1) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.scale_factor = scale_factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ImageSurface draw_jid(StreamInteractor stream_interactor, Jid jid_, Account account) {
|
|
||||||
Jid? jid = jid_;
|
|
||||||
this.stream_interactor = stream_interactor;
|
|
||||||
Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(jid, account);
|
|
||||||
if (real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).has_avatar(account, real_jid)) {
|
|
||||||
jid = real_jid;
|
|
||||||
}
|
|
||||||
ImageSurface surface = crop_corners(yield draw_tile(jid, account, width * scale_factor, height * scale_factor), 3 * scale_factor);
|
|
||||||
surface.set_device_scale(scale_factor, scale_factor);
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ImageSurface draw_message(StreamInteractor stream_interactor, Message message) {
|
|
||||||
if (message.real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).has_avatar(message.account, message.real_jid)) {
|
|
||||||
return yield draw_jid(stream_interactor, message.real_jid, message.account);
|
|
||||||
}
|
|
||||||
return yield draw_jid(stream_interactor, message.from, message.account);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ImageSurface draw_conversation(StreamInteractor stream_interactor, Conversation conversation) {
|
|
||||||
return yield draw_jid(stream_interactor, conversation.counterpart, conversation.account);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ImageSurface draw_account(StreamInteractor stream_interactor, Account account) {
|
|
||||||
return yield draw_jid(stream_interactor, account.bare_jid, account);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageSurface draw_text(string text) {
|
|
||||||
ImageSurface surface = draw_colored_rectangle_text(COLOR_GREY, text, width, height);
|
|
||||||
return crop_corners(surface, 3 * scale_factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AvatarGenerator set_greyscale(bool greyscale) {
|
|
||||||
this.greyscale = greyscale;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AvatarGenerator set_stateless(bool stateless) {
|
|
||||||
this.stateless = stateless;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int get_left_border() {
|
|
||||||
return (int)Math.floor(scale_factor/2.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int get_right_border() {
|
|
||||||
return (int)Math.ceil(scale_factor/2.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void add_tile_to_pixbuf(Pixbuf pixbuf, Jid jid, Account account, int width, int height, int x, int y) {
|
|
||||||
Pixbuf tile = pixbuf_get_from_surface(yield draw_chat_tile(jid, account, width, height), 0, 0, width, height);
|
|
||||||
tile.copy_area(0, 0, width, height, pixbuf, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ImageSurface draw_tile(Jid jid, Account account, int width, int height) {
|
|
||||||
ImageSurface surface;
|
|
||||||
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(jid, account)) {
|
|
||||||
surface = yield draw_groupchat_tile(jid, account, width, height);
|
|
||||||
} else {
|
|
||||||
surface = yield draw_chat_tile(jid, account, width, height);
|
|
||||||
}
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ImageSurface draw_chat_tile(Jid jid, Account account, int width, int height) {
|
|
||||||
Pixbuf? pixbuf = yield stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, jid);
|
|
||||||
if (pixbuf != null) {
|
|
||||||
double desired_ratio = (double) width / height;
|
|
||||||
double avatar_ratio = (double) pixbuf.width / pixbuf.height;
|
|
||||||
if (avatar_ratio > desired_ratio) {
|
|
||||||
int comp_width = width * pixbuf.height / height;
|
|
||||||
pixbuf = new Pixbuf.subpixbuf(pixbuf, pixbuf.width / 2 - comp_width / 2, 0, comp_width, pixbuf.height);
|
|
||||||
} else if (avatar_ratio < desired_ratio) {
|
|
||||||
int comp_height = height * pixbuf.width / width;
|
|
||||||
pixbuf = new Pixbuf.subpixbuf(pixbuf, 0, pixbuf.height / 2 - comp_height / 2, pixbuf.width, comp_height);
|
|
||||||
}
|
|
||||||
pixbuf = pixbuf.scale_simple(width, height, InterpType.BILINEAR);
|
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, pixbuf.width, pixbuf.height));
|
|
||||||
cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
|
||||||
ctx.paint();
|
|
||||||
ImageSurface avatar_surface = (ImageSurface) ctx.get_target();
|
|
||||||
if (greyscale) avatar_surface = convert_to_greyscale(avatar_surface);
|
|
||||||
return avatar_surface;
|
|
||||||
} else {
|
|
||||||
string display_name = Util.get_display_name(stream_interactor, jid, account);
|
|
||||||
string color = greyscale ? COLOR_GREY : Util.get_avatar_hex_color(stream_interactor, account, jid);
|
|
||||||
return draw_colored_rectangle_text(color, display_name.get_char(0).toupper().to_string(), width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ImageSurface draw_groupchat_tile(Jid jid, Account account, int width, int height) {
|
|
||||||
Gee.List<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_other_occupants(jid, account);
|
|
||||||
if (stateless || occupants == null || occupants.size == 0) {
|
|
||||||
return yield draw_chat_tile(jid, account, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < occupants.size && i < 4; i++) {
|
|
||||||
Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(occupants[i], account);
|
|
||||||
if (real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).has_avatar(account, real_jid)) {
|
|
||||||
occupants[i] = real_jid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Pixbuf pixbuf = initialize_pixbuf(width, height);
|
|
||||||
if (occupants.size == 1 || occupants.size == 2 || occupants.size == 3) {
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, occupants[0], account, width / 2 - get_right_border(), height, 0, 0);
|
|
||||||
if (occupants.size == 1) {
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, account.bare_jid, account, width / 2 - get_left_border(), height, width / 2 + get_left_border(), 0);
|
|
||||||
} else if (occupants.size == 2) {
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height, width / 2 + get_left_border(), 0);
|
|
||||||
} else if (occupants.size == 3) {
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height / 2 - get_right_border(), width / 2 + get_left_border(), 0);
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, occupants[2], account, width / 2 - get_left_border(), height / 2 - get_left_border(), width / 2 + get_left_border(), height / 2 + get_left_border());
|
|
||||||
}
|
|
||||||
} else if (occupants.size >= 4) {
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, occupants[0], account, width / 2 - get_right_border(), height / 2 - get_right_border(), 0, 0);
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height / 2 - get_right_border(), width / 2 + get_left_border(), 0);
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, occupants[2], account, width / 2 - get_right_border(), height / 2 - get_left_border(), 0, height / 2 + get_left_border());
|
|
||||||
if (occupants.size == 4) {
|
|
||||||
yield add_tile_to_pixbuf(pixbuf, occupants[3], account, width / 2 - get_left_border(), height / 2 - get_left_border(), width / 2 + get_left_border(), height / 2 + get_left_border());
|
|
||||||
} else if (occupants.size > 4) {
|
|
||||||
ImageSurface plus_surface = draw_colored_rectangle_text("555753", "+", width / 2 - get_left_border(), height / 2 - get_left_border());
|
|
||||||
if (greyscale) plus_surface = convert_to_greyscale(plus_surface);
|
|
||||||
pixbuf_get_from_surface(plus_surface, 0, 0, plus_surface.get_width(), plus_surface.get_height()).copy_area(0, 0, width / 2 - get_left_border(), height / 2 - get_left_border(), pixbuf, width / 2 + get_left_border(), height / 2 + get_left_border());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, pixbuf.width, pixbuf.height));
|
|
||||||
cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
|
||||||
ctx.paint();
|
|
||||||
return (ImageSurface) ctx.get_target();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageSurface draw_colored_icon(string hex_color, string icon, int width, int height) {
|
|
||||||
int ICON_SIZE = width > 20 * scale_factor ? 17 * scale_factor : 14 * scale_factor;
|
|
||||||
|
|
||||||
Context rectancle_context = new Context(new ImageSurface(Format.ARGB32, width, height));
|
|
||||||
draw_colored_rectangle(rectancle_context, hex_color, width, height);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Pixbuf icon_pixbuf = IconTheme.get_default().load_icon(icon, ICON_SIZE, IconLookupFlags.FORCE_SIZE);
|
|
||||||
Surface icon_surface = cairo_surface_create_from_pixbuf(icon_pixbuf, 1, null);
|
|
||||||
Context context = new Context(icon_surface);
|
|
||||||
context.set_operator(Operator.IN);
|
|
||||||
context.set_source_rgba(1, 1, 1, 1);
|
|
||||||
context.rectangle(0, 0, width, height);
|
|
||||||
context.fill();
|
|
||||||
|
|
||||||
rectancle_context.set_source_surface(icon_surface, width / 2 - ICON_SIZE / 2, height / 2 - ICON_SIZE / 2);
|
|
||||||
rectancle_context.paint();
|
|
||||||
} catch (Error e) { warning(@"Icon $icon does not exist"); }
|
|
||||||
|
|
||||||
return (ImageSurface) rectancle_context.get_target();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageSurface draw_colored_rectangle_text(string hex_color, string text, int width, int height) {
|
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, width, height));
|
|
||||||
draw_colored_rectangle(ctx, hex_color, width, height);
|
|
||||||
draw_center_text(ctx, text, width < 40 * scale_factor ? 17 * scale_factor : 25 * scale_factor, width, height);
|
|
||||||
return (ImageSurface) ctx.get_target();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void draw_center_text(Context ctx, string text, int fontsize, int width, int height) {
|
|
||||||
ctx.select_font_face("Sans", Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL);
|
|
||||||
ctx.set_font_size(fontsize);
|
|
||||||
Cairo.TextExtents extents;
|
|
||||||
ctx.text_extents(text, out extents);
|
|
||||||
double x_pos = width/2 - (extents.width/2 + extents.x_bearing);
|
|
||||||
double y_pos = height/2 - (extents.height/2 + extents.y_bearing);
|
|
||||||
ctx.move_to(x_pos, y_pos);
|
|
||||||
ctx.set_source_rgba(1, 1, 1, 1);
|
|
||||||
ctx.show_text(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void draw_colored_rectangle(Context ctx, string hex_color, int width, int height) {
|
|
||||||
set_source_hex_color(ctx, hex_color);
|
|
||||||
ctx.rectangle(0, 0, width, height);
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ImageSurface convert_to_greyscale(ImageSurface surface) {
|
|
||||||
Context context = new Context(surface);
|
|
||||||
// convert to greyscale
|
|
||||||
context.set_operator(Operator.HSL_COLOR);
|
|
||||||
context.set_source_rgb(1, 1, 1);
|
|
||||||
context.rectangle(0, 0, surface.get_width(), surface.get_height());
|
|
||||||
context.fill();
|
|
||||||
// make the visible part more light
|
|
||||||
context.set_operator(Operator.ATOP);
|
|
||||||
context.set_source_rgba(1, 1, 1, 0.7);
|
|
||||||
context.rectangle(0, 0, surface.get_width(), surface.get_height());
|
|
||||||
context.fill();
|
|
||||||
return (ImageSurface) context.get_target();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Pixbuf crop_corners_pixbuf(Pixbuf pixbuf, double radius = 3) {
|
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, pixbuf.width, pixbuf.height));
|
|
||||||
cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
|
||||||
double degrees = Math.PI / 180.0;
|
|
||||||
ctx.new_sub_path();
|
|
||||||
ctx.arc(pixbuf.width - radius, radius, radius, -90 * degrees, 0 * degrees);
|
|
||||||
ctx.arc(pixbuf.width - radius, pixbuf.height - radius, radius, 0 * degrees, 90 * degrees);
|
|
||||||
ctx.arc(radius, pixbuf.height - radius, radius, 90 * degrees, 180 * degrees);
|
|
||||||
ctx.arc(radius, radius, radius, 180 * degrees, 270 * degrees);
|
|
||||||
ctx.close_path();
|
|
||||||
ctx.clip();
|
|
||||||
ctx.paint();
|
|
||||||
return pixbuf_get_from_surface(ctx.get_target(), 0, 0, pixbuf.width, pixbuf.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ImageSurface crop_corners(ImageSurface surface, double radius = 3) {
|
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, surface.get_width(), surface.get_height()));
|
|
||||||
ctx.set_source_surface(surface, 0, 0);
|
|
||||||
double degrees = Math.PI / 180.0;
|
|
||||||
ctx.new_sub_path();
|
|
||||||
ctx.arc(surface.get_width() - radius, radius, radius, -90 * degrees, 0 * degrees);
|
|
||||||
ctx.arc(surface.get_width() - radius, surface.get_height() - radius, radius, 0 * degrees, 90 * degrees);
|
|
||||||
ctx.arc(radius, surface.get_height() - radius, radius, 90 * degrees, 180 * degrees);
|
|
||||||
ctx.arc(radius, radius, radius, 180 * degrees, 270 * degrees);
|
|
||||||
ctx.close_path();
|
|
||||||
ctx.clip();
|
|
||||||
ctx.paint();
|
|
||||||
return (ImageSurface) ctx.get_target();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Pixbuf initialize_pixbuf(int width, int height) {
|
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, width, height));
|
|
||||||
ctx.set_source_rgba(1, 1, 1, 0);
|
|
||||||
ctx.rectangle(0, 0, width, height);
|
|
||||||
ctx.fill();
|
|
||||||
return pixbuf_get_from_surface(ctx.get_target(), 0, 0, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void set_source_hex_color(Context ctx, string hex_color) {
|
|
||||||
ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255,
|
|
||||||
(double) from_hex(hex_color.substring(2, 2)) / 255,
|
|
||||||
(double) from_hex(hex_color.substring(4, 2)) / 255,
|
|
||||||
hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -9,16 +9,15 @@ public class AvatarImage : Misc {
|
||||||
public int height { get; set; default = 35; }
|
public int height { get; set; default = 35; }
|
||||||
public int width { get; set; default = 35; }
|
public int width { get; set; default = 35; }
|
||||||
public bool allow_gray { get; set; default = true; }
|
public bool allow_gray { get; set; default = true; }
|
||||||
public Account account { get; private set; }
|
public StreamInteractor? stream_interactor { get; set; }
|
||||||
public StreamInteractor stream_interactor { get; set; }
|
public AvatarManager? avatar_manager { owned get { return stream_interactor == null ? null : stream_interactor.get_module(AvatarManager.IDENTITY); } }
|
||||||
public AvatarManager avatar_manager { owned get { return stream_interactor.get_module(AvatarManager.IDENTITY); } }
|
public MucManager? muc_manager { owned get { return stream_interactor == null ? null : stream_interactor.get_module(MucManager.IDENTITY); } }
|
||||||
public MucManager muc_manager { owned get { return stream_interactor.get_module(MucManager.IDENTITY); } }
|
public PresenceManager? presence_manager { owned get { return stream_interactor == null ? null : stream_interactor.get_module(PresenceManager.IDENTITY); } }
|
||||||
private Jid jid;
|
public ConnectionManager? connection_manager { owned get { return stream_interactor == null ? null : stream_interactor.connection_manager; } }
|
||||||
private string? text_only;
|
public Account account { get { return conversation.account; } }
|
||||||
private bool with_plus;
|
private AvatarDrawer? drawer;
|
||||||
private bool gray;
|
private Conversation conversation;
|
||||||
private Jid[] current_jids;
|
private Jid[] jids;
|
||||||
private Gdk.Pixbuf[] current_avatars;
|
|
||||||
private Cairo.ImageSurface? cached_surface;
|
private Cairo.ImageSurface? cached_surface;
|
||||||
private static int8 use_image_surface = -1;
|
private static int8 use_image_surface = -1;
|
||||||
|
|
||||||
|
@ -37,52 +36,8 @@ public class AvatarImage : Misc {
|
||||||
natural_height = height;
|
natural_height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Cairo.Surface sub_surface(Cairo.Context ctx, int idx, int width, int height, int font_factor = 1) {
|
|
||||||
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
|
||||||
Cairo.Context bufctx = new Cairo.Context(buffer);
|
|
||||||
if (idx == -1 || current_avatars[idx] == null) {
|
|
||||||
set_source_hex_color(bufctx, gray || idx == -1 || current_jids[idx] == null ? "555753" : Util.get_avatar_hex_color(stream_interactor, account, current_jids[idx]));
|
|
||||||
bufctx.rectangle(0, 0, width, height);
|
|
||||||
bufctx.fill();
|
|
||||||
|
|
||||||
string text = text_only ?? (idx == -1 || current_jids[idx] == null ? "…" : Util.get_display_name(stream_interactor, current_jids[idx], account).get_char(0).toupper().to_string());
|
|
||||||
bufctx.select_font_face(get_pango_context().get_font_description().get_family(), Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL);
|
|
||||||
bufctx.set_font_size(width / font_factor < 40 ? font_factor * 17 : font_factor * 25);
|
|
||||||
Cairo.TextExtents extents;
|
|
||||||
bufctx.text_extents(text, out extents);
|
|
||||||
double x_pos = width/2 - (extents.width/2 + extents.x_bearing);
|
|
||||||
double y_pos = height/2 - (extents.height/2 + extents.y_bearing);
|
|
||||||
bufctx.move_to(x_pos, y_pos);
|
|
||||||
bufctx.set_source_rgba(1, 1, 1, 1);
|
|
||||||
bufctx.show_text(text);
|
|
||||||
} else {
|
|
||||||
double w_scale = (double) width / current_avatars[idx].width;
|
|
||||||
double h_scale = (double) height / current_avatars[idx].height;
|
|
||||||
double scale = double.max(w_scale, h_scale);
|
|
||||||
bufctx.scale(scale, scale);
|
|
||||||
|
|
||||||
double x_off = 0, y_off = 0;
|
|
||||||
if (scale == h_scale) {
|
|
||||||
x_off = (width / scale - current_avatars[idx].width) / 2.0;
|
|
||||||
} else {
|
|
||||||
y_off = (height / scale - current_avatars[idx].height) / 2.0;
|
|
||||||
}
|
|
||||||
Gdk.cairo_set_source_pixbuf(bufctx, current_avatars[idx], x_off, y_off);
|
|
||||||
bufctx.get_source().set_filter(Cairo.Filter.BEST);
|
|
||||||
bufctx.paint();
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void set_source_hex_color(Cairo.Context ctx, string hex_color) {
|
|
||||||
ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255,
|
|
||||||
(double) from_hex(hex_color.substring(2, 2)) / 255,
|
|
||||||
(double) from_hex(hex_color.substring(4, 2)) / 255,
|
|
||||||
hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool draw(Cairo.Context ctx_in) {
|
public override bool draw(Cairo.Context ctx_in) {
|
||||||
if (text_only == null && (current_jids == null || current_avatars == null || current_jids.length == 0)) return false;
|
if (drawer == null) return false;
|
||||||
|
|
||||||
Cairo.Context ctx = ctx_in;
|
Cairo.Context ctx = ctx_in;
|
||||||
int width = this.width, height = this.height, base_factor = 1;
|
int width = this.width, height = this.height, base_factor = 1;
|
||||||
|
@ -104,82 +59,10 @@ public class AvatarImage : Misc {
|
||||||
ctx = new Cairo.Context(cached_surface);
|
ctx = new Cairo.Context(cached_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
double radius = 3 * base_factor;
|
drawer.size(height, width)
|
||||||
double degrees = Math.PI / 180.0;
|
.scale(base_factor)
|
||||||
ctx.new_sub_path();
|
.font(get_pango_context().get_font_description().get_family())
|
||||||
ctx.arc(width - radius, radius, radius, -90 * degrees, 0 * degrees);
|
.draw_on_context(ctx);
|
||||||
ctx.arc(width - radius, height - radius, radius, 0 * degrees, 90 * degrees);
|
|
||||||
ctx.arc(radius, height - radius, radius, 90 * degrees, 180 * degrees);
|
|
||||||
ctx.arc(radius, radius, radius, 180 * degrees, 270 * degrees);
|
|
||||||
ctx.close_path();
|
|
||||||
ctx.clip();
|
|
||||||
|
|
||||||
if (text_only != null) {
|
|
||||||
ctx.set_source_surface(sub_surface(ctx, -1, width, height, base_factor), 0, 0);
|
|
||||||
ctx.paint();
|
|
||||||
} else if (current_jids.length == 4 || with_plus) {
|
|
||||||
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
|
||||||
Cairo.Context bufctx = new Cairo.Context(buffer);
|
|
||||||
bufctx.scale(0.5, 0.5);
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height - 1, 2 * base_factor), 0, 0);
|
|
||||||
bufctx.paint();
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height - 1, 2 * base_factor), width + 1, 0);
|
|
||||||
bufctx.paint();
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 2, width - 1, height - 1, 2 * base_factor), 0, height + 1);
|
|
||||||
bufctx.paint();
|
|
||||||
if (with_plus) {
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, -1, width - 1, height - 1, 2 * base_factor), width + 1, height + 1);
|
|
||||||
bufctx.paint();
|
|
||||||
} else {
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 3, width - 1, height - 1, 2 * base_factor), width + 1, height + 1);
|
|
||||||
bufctx.paint();
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.set_source_surface(buffer, 0, 0);
|
|
||||||
ctx.paint();
|
|
||||||
} else if (current_jids.length == 3) {
|
|
||||||
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
|
||||||
Cairo.Context bufctx = new Cairo.Context(buffer);
|
|
||||||
bufctx.scale(0.5, 0.5);
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height - 1, 2 * base_factor), 0, 0);
|
|
||||||
bufctx.paint();
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height * 2, 2 * base_factor), width + 1, 0);
|
|
||||||
bufctx.paint();
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 2, width - 1 , height - 1, 2 * base_factor), 0, height + 1);
|
|
||||||
bufctx.paint();
|
|
||||||
|
|
||||||
ctx.set_source_surface(buffer, 0, 0);
|
|
||||||
ctx.paint();
|
|
||||||
} else if (current_jids.length == 2) {
|
|
||||||
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
|
||||||
Cairo.Context bufctx = new Cairo.Context(buffer);
|
|
||||||
bufctx.scale(0.5, 0.5);
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height * 2, 2 * base_factor), 0, 0);
|
|
||||||
bufctx.paint();
|
|
||||||
bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height * 2, 2 * base_factor), width + 1, 0);
|
|
||||||
bufctx.paint();
|
|
||||||
|
|
||||||
ctx.set_source_surface(buffer, 0, 0);
|
|
||||||
ctx.paint();
|
|
||||||
} else if (current_jids.length == 1) {
|
|
||||||
ctx.set_source_surface(sub_surface(ctx, 0, width, height, base_factor), 0, 0);
|
|
||||||
ctx.paint();
|
|
||||||
} else {
|
|
||||||
assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gray) {
|
|
||||||
// convert to greyscale
|
|
||||||
ctx.set_operator(Cairo.Operator.HSL_COLOR);
|
|
||||||
ctx.set_source_rgb(1, 1, 1);
|
|
||||||
ctx.rectangle(0, 0, width, height);
|
|
||||||
ctx.fill();
|
|
||||||
// make the visible part more light
|
|
||||||
ctx.set_operator(Cairo.Operator.ATOP);
|
|
||||||
ctx.set_source_rgba(1, 1, 1, 0.7);
|
|
||||||
ctx.rectangle(0, 0, width, height);
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (use_image_surface == 1) {
|
if (use_image_surface == 1) {
|
||||||
ctx_in.set_source_surface(ctx.get_target(), 0, 0);
|
ctx_in.set_source_surface(ctx.get_target(), 0, 0);
|
||||||
|
@ -190,100 +73,38 @@ public class AvatarImage : Misc {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void destroy() {
|
public override void destroy() {
|
||||||
|
disconnect_stream_interactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disconnect_stream_interactor() {
|
||||||
if (stream_interactor != null) {
|
if (stream_interactor != null) {
|
||||||
stream_interactor.get_module(PresenceManager.IDENTITY).show_received.disconnect(on_show_received);
|
presence_manager.show_received.disconnect(on_show_received);
|
||||||
stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.disconnect(on_received_avatar);
|
avatar_manager.received_avatar.disconnect(on_received_avatar);
|
||||||
stream_interactor.connection_manager.connection_state_changed.disconnect(on_connection_changed);
|
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(RosterManager.IDENTITY).updated_roster_item.disconnect(on_roster_updated);
|
||||||
stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.disconnect(on_occupant_updated);
|
muc_manager.private_room_occupant_updated.disconnect(on_private_room_occupant_updated);
|
||||||
|
stream_interactor = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set_jid(StreamInteractor stream_interactor, Jid jid_, Account account, bool force_update = false) {
|
|
||||||
this.account = account;
|
|
||||||
if (this.stream_interactor == null) {
|
|
||||||
this.stream_interactor = stream_interactor;
|
|
||||||
stream_interactor.get_module(PresenceManager.IDENTITY).show_received.connect(on_show_received);
|
|
||||||
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.has_avatar(account, jid_)) {
|
|
||||||
// Groupchat without avatar
|
|
||||||
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()))) {
|
|
||||||
set_jids_(new Jid[] {jid_}, false, occupants == null || !is_self_online());
|
|
||||||
}
|
|
||||||
} else if (occupants.size > 4) {
|
|
||||||
bool requires_update = force_update;
|
|
||||||
if (!with_plus) requires_update = true;
|
|
||||||
foreach (Jid jid in current_jids) {
|
|
||||||
if (!occupants.contains(jid)) {
|
|
||||||
requires_update = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (requires_update) {
|
|
||||||
set_jids_(occupants.slice(0, 3).to_array(), true);
|
|
||||||
}
|
|
||||||
} else { // 1 <= occupants.size <= 4
|
|
||||||
bool requires_update = force_update;
|
|
||||||
if (with_plus) requires_update = true;
|
|
||||||
if (current_jids.length != occupants.size) requires_update = true;
|
|
||||||
foreach (Jid jid in current_jids) {
|
|
||||||
if (!occupants.contains(jid)) {
|
|
||||||
requires_update = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (requires_update) {
|
|
||||||
set_jids_(occupants.to_array(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Single user or MUC with vcard avatar
|
|
||||||
this.jid = jid_;
|
|
||||||
if (force_update || current_jids.length != 1 || !current_jids[0].equals(jid) || gray != (allow_gray && (!is_counterpart_online(jid) || !is_self_online()))) {
|
|
||||||
set_jids_(new Jid[] { jid }, false, !is_counterpart_online(jid) || !is_self_online());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set_jids(StreamInteractor stream_interactor, Jid[] jids, Account account, bool gray = false) {
|
|
||||||
this.stream_interactor = stream_interactor;
|
|
||||||
this.account = account;
|
|
||||||
set_jids_(jids.length > 3 ? jids[0:3] : jids, jids.length > 3, gray);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void on_show_received(Show show, Jid jid, Account account) {
|
private void on_show_received(Show show, Jid jid, Account account) {
|
||||||
if (!account.equals(this.account)) return;
|
if (!account.equals(this.account)) return;
|
||||||
if (jid.equals_bare(this.jid)) {
|
update_avatar_if_jid(jid);
|
||||||
set_jid(stream_interactor, this.jid, account, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
foreach (Jid jid_ in current_jids) {
|
|
||||||
if (jid.equals_bare(jid_)) {
|
|
||||||
set_jid(stream_interactor, this.jid, account, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void on_received_avatar(Gdk.Pixbuf avatar, Jid jid, Account account) {
|
private void on_received_avatar(Gdk.Pixbuf avatar, Jid jid, Account account) {
|
||||||
if (!account.equals(this.account)) return;
|
if (!account.equals(this.account)) return;
|
||||||
if (jid.equals_bare(this.jid)) {
|
update_avatar_if_jid(jid);
|
||||||
set_jid(stream_interactor, this.jid, account, true);
|
}
|
||||||
|
|
||||||
|
private void update_avatar_if_jid(Jid jid) {
|
||||||
|
if (jid.equals_bare(this.conversation.counterpart)) {
|
||||||
|
update_avatar_async.begin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (Jid jid_ in current_jids) {
|
foreach (Jid ours in this.jids) {
|
||||||
if (jid.equals_bare(jid_)) {
|
if (jid.equals_bare(ours)) {
|
||||||
set_jid(stream_interactor, this.jid, account, true);
|
update_avatar_async.begin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,67 +112,73 @@ public class AvatarImage : Misc {
|
||||||
|
|
||||||
private void on_connection_changed(Account account, ConnectionManager.ConnectionState state) {
|
private void on_connection_changed(Account account, ConnectionManager.ConnectionState state) {
|
||||||
if (!account.equals(this.account)) return;
|
if (!account.equals(this.account)) return;
|
||||||
set_jid(stream_interactor, this.jid, account, true);
|
update_avatar_async.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void on_roster_updated(Account account, Jid jid, Roster.Item roster_item) {
|
private void on_roster_updated(Account account, Jid jid, Roster.Item roster_item) {
|
||||||
if (!account.equals(this.account)) return;
|
if (!account.equals(this.account)) return;
|
||||||
if (!jid.equals_bare(this.jid)) return;
|
update_avatar_if_jid(jid);
|
||||||
set_jid(stream_interactor, this.jid, account, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void on_occupant_updated(Account account, Jid room, Jid occupant) {
|
private void on_private_room_occupant_updated(Account account, Jid room, Jid occupant) {
|
||||||
if (!account.equals(this.account)) return;
|
if (!account.equals(this.account)) return;
|
||||||
if (!room.equals_bare(this.jid)) return;
|
update_avatar_if_jid(room);
|
||||||
set_jid(stream_interactor, this.jid, account, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool is_self_online() {
|
private bool is_self_online() {
|
||||||
return stream_interactor.connection_manager.get_state(account) == ConnectionManager.ConnectionState.CONNECTED;
|
if (connection_manager != null) {
|
||||||
|
return connection_manager.get_state(account) == ConnectionManager.ConnectionState.CONNECTED;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool is_counterpart_online(Jid counterpart) {
|
private bool is_counterpart_online() {
|
||||||
return stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(counterpart, account) != null;
|
return presence_manager.get_full_jids(conversation.counterpart, account) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set_jids_(Jid[] jids, bool with_plus = false, bool gray = false) {
|
public void set_conversation(StreamInteractor stream_interactor, Conversation conversation) {
|
||||||
assert(jids.length > 0);
|
set_avatar_async.begin(stream_interactor, conversation, new Jid[0]);
|
||||||
assert(jids.length < 5);
|
}
|
||||||
assert(!with_plus || jids.length == 3);
|
|
||||||
|
public void set_conversation_participant(StreamInteractor stream_interactor, Conversation conversation, Jid sub_jid) {
|
||||||
|
set_avatar_async.begin(stream_interactor, conversation, new Jid[] {sub_jid});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set_conversation_participants(StreamInteractor stream_interactor, Conversation conversation, Jid[] sub_jids) {
|
||||||
|
set_avatar_async.begin(stream_interactor, conversation, sub_jids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void update_avatar_async() {
|
||||||
this.cached_surface = null;
|
this.cached_surface = null;
|
||||||
this.text_only = null;
|
this.drawer = yield Util.get_conversation_participants_avatar_drawer(stream_interactor, conversation, jids);
|
||||||
this.gray = gray && allow_gray;
|
if (allow_gray && (!is_self_online() || !is_counterpart_online())) drawer.grayscale();
|
||||||
this.with_plus = with_plus;
|
|
||||||
|
|
||||||
set_jids_async.begin(jids);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void set_jids_async(Jid[] jids) {
|
|
||||||
Jid[] jids_ = jids;
|
|
||||||
Gdk.Pixbuf[] avatars = new Gdk.Pixbuf[jids.length];
|
|
||||||
for (int i = 0; i < jids_.length; ++i) {
|
|
||||||
Jid? real_jid = muc_manager.get_real_jid(jids_[i], account);
|
|
||||||
if (real_jid != null) {
|
|
||||||
avatars[i] = yield avatar_manager.get_avatar(account, real_jid);
|
|
||||||
if (avatars[i] != null) {
|
|
||||||
jids_[i] = real_jid;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
avatars[i] = yield avatar_manager.get_avatar(account, jids_[i]);
|
|
||||||
}
|
|
||||||
this.current_avatars = avatars;
|
|
||||||
this.current_jids = jids_;
|
|
||||||
|
|
||||||
queue_draw();
|
queue_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void set_avatar_async(StreamInteractor stream_interactor, Conversation conversation, Jid[] jids) {
|
||||||
|
if (this.stream_interactor != null && stream_interactor != this.stream_interactor) {
|
||||||
|
disconnect_stream_interactor();
|
||||||
|
}
|
||||||
|
if (this.stream_interactor != stream_interactor) {
|
||||||
|
this.stream_interactor = stream_interactor;
|
||||||
|
presence_manager.show_received.connect(on_show_received);
|
||||||
|
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);
|
||||||
|
muc_manager.private_room_occupant_updated.connect(on_private_room_occupant_updated);
|
||||||
|
}
|
||||||
|
this.cached_surface = null;
|
||||||
|
this.conversation = conversation;
|
||||||
|
this.jids = jids;
|
||||||
|
|
||||||
|
yield update_avatar_async();
|
||||||
|
}
|
||||||
|
|
||||||
public void set_text(string text, bool gray = true) {
|
public void set_text(string text, bool gray = true) {
|
||||||
this.text_only = text;
|
disconnect_stream_interactor();
|
||||||
this.gray = gray;
|
this.drawer = new AvatarDrawer().tile(null, text, null);
|
||||||
this.with_plus = false;
|
if (gray) drawer.grayscale();
|
||||||
this.current_jids = null;
|
|
||||||
this.current_avatars = null;
|
|
||||||
queue_draw();
|
queue_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ public class Dialog : Gtk.Dialog {
|
||||||
}
|
}
|
||||||
jid_label.label = conversation.counterpart.to_string();
|
jid_label.label = conversation.counterpart.to_string();
|
||||||
account_label.label = "via " + conversation.account.bare_jid.to_string();
|
account_label.label = "via " + conversation.account.bare_jid.to_string();
|
||||||
avatar.set_jid(stream_interactor, conversation.counterpart, conversation.account);
|
avatar.set_conversation(stream_interactor, conversation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add_entry(string category, string label, string? description, Object wo) {
|
private void add_entry(string category, string label, string? description, Object wo) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class SettingsProvider : Plugins.ContactDetailsProvider, Object {
|
||||||
public void populate(Conversation conversation, Plugins.ContactDetails contact_details, Plugins.WidgetType type) {
|
public void populate(Conversation conversation, Plugins.ContactDetails contact_details, Plugins.WidgetType type) {
|
||||||
if (type != Plugins.WidgetType.GTK) return;
|
if (type != Plugins.WidgetType.GTK) return;
|
||||||
|
|
||||||
if (!stream_interactor.get_module(MucManager.IDENTITY).is_public_room(conversation.account, conversation.counterpart)) {
|
if (!stream_interactor.get<MucManager>().is_public_room(conversation.account, conversation.counterpart)) {
|
||||||
string details_headline = conversation.type_ == Conversation.Type.GROUPCHAT ? DETAILS_HEADLINE_ROOM : DETAILS_HEADLINE_CHAT;
|
string details_headline = conversation.type_ == Conversation.Type.GROUPCHAT ? DETAILS_HEADLINE_ROOM : DETAILS_HEADLINE_CHAT;
|
||||||
|
|
||||||
ComboBoxText combobox_typing = get_combobox(Dino.Application.get_default().settings.send_typing);
|
ComboBoxText combobox_typing = get_combobox(Dino.Application.get_default().settings.send_typing);
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class ConversationSelectorRow : ListBoxRow {
|
||||||
last_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation);
|
last_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation);
|
||||||
|
|
||||||
x_button.clicked.connect(close_conversation);
|
x_button.clicked.connect(close_conversation);
|
||||||
image.set_jid(stream_interactor, conversation.counterpart, conversation.account);
|
image.set_conversation(stream_interactor, conversation);
|
||||||
conversation.notify["read-up-to"].connect(update_read);
|
conversation.notify["read-up-to"].connect(update_read);
|
||||||
|
|
||||||
update_name_label();
|
update_name_label();
|
||||||
|
@ -131,7 +131,7 @@ public class ConversationSelectorRow : ListBoxRow {
|
||||||
Message last_message = message_item.message;
|
Message last_message = message_item.message;
|
||||||
|
|
||||||
if (conversation.type_ == Conversation.Type.GROUPCHAT) {
|
if (conversation.type_ == Conversation.Type.GROUPCHAT) {
|
||||||
nick_label.label = Util.get_message_display_name(stream_interactor, last_message, conversation.account) + ": ";
|
nick_label.label = Util.get_participant_display_name(stream_interactor, conversation, last_message.from, true) + ": ";
|
||||||
} else {
|
} else {
|
||||||
nick_label.label = last_message.direction == Message.DIRECTION_SENT ? _("Me") + ": " : "";
|
nick_label.label = last_message.direction == Message.DIRECTION_SENT ? _("Me") + ": " : "";
|
||||||
}
|
}
|
||||||
|
@ -145,8 +145,7 @@ public class ConversationSelectorRow : ListBoxRow {
|
||||||
|
|
||||||
if (conversation.type_ == Conversation.Type.GROUPCHAT) {
|
if (conversation.type_ == Conversation.Type.GROUPCHAT) {
|
||||||
// TODO properly display nick for oneself
|
// TODO properly display nick for oneself
|
||||||
string nick = transfer.direction == Message.DIRECTION_SENT ? _("Me") : Util.get_display_name(stream_interactor, file_item.file_transfer.counterpart, conversation.account);
|
nick_label.label = Util.get_participant_display_name(stream_interactor, conversation, file_item.file_transfer.counterpart, true) + ": ";
|
||||||
nick_label.label = nick + ": ";
|
|
||||||
} else {
|
} else {
|
||||||
nick_label.label = transfer.direction == Message.DIRECTION_SENT ? _("Me") + ": " : "";
|
nick_label.label = transfer.direction == Message.DIRECTION_SENT ? _("Me") + ": " : "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,11 +135,11 @@ private class MetaChatStateItem : Plugins.MetaConversationItem {
|
||||||
private void update() {
|
private void update() {
|
||||||
if (image == null || label == null) return;
|
if (image == null || label == null) return;
|
||||||
|
|
||||||
image.set_jids(stream_interactor, jids.to_array(), conversation.account, true);
|
image.set_conversation_participants(stream_interactor, conversation, jids.to_array());
|
||||||
|
|
||||||
Gee.List<string> display_names = new ArrayList<string>();
|
Gee.List<string> display_names = new ArrayList<string>();
|
||||||
foreach (Jid jid in jids) {
|
foreach (Jid jid in jids) {
|
||||||
display_names.add(Util.get_display_name(stream_interactor, jid, conversation.account));
|
display_names.add(Util.get_participant_display_name(stream_interactor, conversation, jid));
|
||||||
}
|
}
|
||||||
string new_text = "";
|
string new_text = "";
|
||||||
if (jids.size > 3) {
|
if (jids.size > 3) {
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class MessageItemWidgetGenerator : WidgetGenerator, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message_item.message.body.has_prefix("/me")) {
|
if (message_item.message.body.has_prefix("/me")) {
|
||||||
string display_name = Util.get_message_display_name(stream_interactor, message, conversation.account);
|
string display_name = Util.get_participant_display_name(stream_interactor, conversation, message.from);
|
||||||
update_me_style(stream_interactor, message.real_jid ?? message.from, display_name, conversation.account, label, markup_text);
|
update_me_style(stream_interactor, message.real_jid ?? message.from, display_name, conversation.account, label, markup_text);
|
||||||
label.realize.connect(() => update_me_style(stream_interactor, message.real_jid ?? message.from, display_name, conversation.account, label, markup_text));
|
label.realize.connect(() => update_me_style(stream_interactor, message.real_jid ?? message.from, display_name, conversation.account, label, markup_text));
|
||||||
label.style_updated.connect(() => update_me_style(stream_interactor, message.real_jid ?? message.from, display_name, conversation.account, label, markup_text));
|
label.style_updated.connect(() => update_me_style(stream_interactor, message.real_jid ?? message.from, display_name, conversation.account, label, markup_text));
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class ConversationItemSkeleton : EventBox {
|
||||||
this.get_style_context().add_class("message-box");
|
this.get_style_context().add_class("message-box");
|
||||||
|
|
||||||
if (item.requires_avatar) {
|
if (item.requires_avatar) {
|
||||||
image.set_jid(stream_interactor, item.jid, conversation.account);
|
image.set_conversation_participant(stream_interactor, conversation, item.jid);
|
||||||
image_content_box.add(image);
|
image_content_box.add(image);
|
||||||
}
|
}
|
||||||
if (item.display_time != null) {
|
if (item.display_time != null) {
|
||||||
|
@ -137,7 +137,7 @@ public class ItemMetaDataHeader : Box {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update_name_label() {
|
private void update_name_label() {
|
||||||
string display_name = Markup.escape_text(Util.get_display_name(stream_interactor, item.jid, conversation.account));
|
string display_name = Markup.escape_text(Util.get_participant_display_name(stream_interactor, conversation, item.jid));
|
||||||
string color = Util.get_name_hex_color(stream_interactor, conversation.account, item.jid, Util.is_dark_theme(name_label));
|
string color = Util.get_name_hex_color(stream_interactor, conversation.account, item.jid, Util.is_dark_theme(name_label));
|
||||||
name_label.label = @"<span foreground=\"#$color\">$display_name</span>";
|
name_label.label = @"<span foreground=\"#$color\">$display_name</span>";
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,9 +86,15 @@ public class GlobalSearch : Overlay {
|
||||||
foreach(SearchSuggestion suggestion in suggestions) {
|
foreach(SearchSuggestion suggestion in suggestions) {
|
||||||
Builder builder = new Builder.from_resource("/im/dino/Dino/search_autocomplete.ui");
|
Builder builder = new Builder.from_resource("/im/dino/Dino/search_autocomplete.ui");
|
||||||
AvatarImage avatar = (AvatarImage)builder.get_object("image");
|
AvatarImage avatar = (AvatarImage)builder.get_object("image");
|
||||||
avatar.set_jid(stream_interactor, suggestion.jid, suggestion.account);
|
|
||||||
Label label = (Label)builder.get_object("label");
|
Label label = (Label)builder.get_object("label");
|
||||||
string display_name = Util.get_display_name(stream_interactor, suggestion.jid, suggestion.account);
|
string display_name;
|
||||||
|
if (suggestion.conversation.type_ == Conversation.Type.GROUPCHAT && !suggestion.conversation.counterpart.equals(suggestion.jid) || suggestion.conversation.type_ == Conversation.Type.GROUPCHAT_PM) {
|
||||||
|
display_name = Util.get_participant_display_name(stream_interactor, suggestion.conversation, suggestion.jid);
|
||||||
|
avatar.set_conversation_participant(stream_interactor, suggestion.conversation, suggestion.jid);
|
||||||
|
} else {
|
||||||
|
display_name = Util.get_conversation_display_name(stream_interactor, suggestion.conversation);
|
||||||
|
avatar.set_conversation(stream_interactor, suggestion.conversation);
|
||||||
|
}
|
||||||
if (display_name != suggestion.jid.to_string()) {
|
if (display_name != suggestion.jid.to_string()) {
|
||||||
label.set_markup(@"$display_name <span font_weight='light' fgalpha='80%'>$(suggestion.jid)</span>");
|
label.set_markup(@"$display_name <span font_weight='light' fgalpha='80%'>$(suggestion.jid)</span>");
|
||||||
} else {
|
} else {
|
||||||
|
@ -188,7 +194,6 @@ public class GlobalSearch : Overlay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Label label = new Label("") { use_markup=true, xalign=0, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, vexpand=true, visible=true };
|
Label label = new Label("") { use_markup=true, xalign=0, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, vexpand=true, visible=true };
|
||||||
string markup_text = Markup.escape_text(text);
|
|
||||||
|
|
||||||
// Build regex containing all keywords
|
// Build regex containing all keywords
|
||||||
string regex_str = "(";
|
string regex_str = "(";
|
||||||
|
@ -205,19 +210,19 @@ public class GlobalSearch : Overlay {
|
||||||
regex_str += ")";
|
regex_str += ")";
|
||||||
|
|
||||||
// Color the keywords
|
// Color the keywords
|
||||||
|
string markup_text = "";
|
||||||
try {
|
try {
|
||||||
int elongated_by = 0;
|
Regex highlight_regex = new Regex(regex_str, RegexCompileFlags.CASELESS);
|
||||||
Regex highlight_regex = new Regex(regex_str);
|
|
||||||
MatchInfo match_info;
|
MatchInfo match_info;
|
||||||
string markup_text_bak = markup_text.down();
|
highlight_regex.match(text, 0, out match_info);
|
||||||
highlight_regex.match(markup_text_bak, 0, out match_info);
|
int last_end = 0;
|
||||||
for (; match_info.matches(); match_info.next()) {
|
for (; match_info.matches(); match_info.next()) {
|
||||||
int start, end;
|
int start, end;
|
||||||
match_info.fetch_pos(0, out start, out end);
|
match_info.fetch_pos(0, out start, out end);
|
||||||
markup_text = markup_text[0:start+elongated_by] + "<span bgcolor=\"yellow\">" + markup_text[start+elongated_by:end+elongated_by] + "</span>" + markup_text[end+elongated_by:markup_text.length];
|
markup_text += Markup.escape_text(text[last_end:start]) + "<span bgcolor=\"yellow\">" + Markup.escape_text(text[start:end]) + "</span>";
|
||||||
elongated_by += "<span bgcolor=\"yellow\">".length + "</span>".length;
|
last_end = end;
|
||||||
}
|
}
|
||||||
markup_text_bak += ""; // We need markup_text_bak to live until here because url_regex.match does not copy the string
|
markup_text += Markup.escape_text(text[last_end:text.length]);
|
||||||
} catch (RegexError e) {
|
} catch (RegexError e) {
|
||||||
assert_not_reached();
|
assert_not_reached();
|
||||||
}
|
}
|
||||||
|
@ -244,11 +249,11 @@ public class GlobalSearch : Overlay {
|
||||||
|
|
||||||
private Grid get_skeleton(MessageItem item) {
|
private Grid get_skeleton(MessageItem item) {
|
||||||
AvatarImage image = new AvatarImage() { height=32, width=32, margin_end=7, valign=Align.START, visible=true, allow_gray = false };
|
AvatarImage image = new AvatarImage() { height=32, width=32, margin_end=7, valign=Align.START, visible=true, allow_gray = false };
|
||||||
image.set_jid(stream_interactor, item.jid, item.message.account);
|
image.set_conversation_participant(stream_interactor, item.conversation, item.jid);
|
||||||
Grid grid = new Grid() { row_homogeneous=false, visible=true };
|
Grid grid = new Grid() { row_homogeneous=false, visible=true };
|
||||||
grid.attach(image, 0, 0, 1, 2);
|
grid.attach(image, 0, 0, 1, 2);
|
||||||
|
|
||||||
string display_name = Util.get_display_name(stream_interactor, item.jid, item.message.account);
|
string display_name = Util.get_participant_display_name(stream_interactor, item.conversation, item.jid);
|
||||||
string color = Util.get_name_hex_color(stream_interactor, item.message.account, item.jid, false); // TODO Util.is_dark_theme(name_label)
|
string color = Util.get_name_hex_color(stream_interactor, item.message.account, item.jid, false); // TODO Util.is_dark_theme(name_label)
|
||||||
Label name_label = new Label("") { use_markup=true, xalign=0, visible=true };
|
Label name_label = new Label("") { use_markup=true, xalign=0, visible=true };
|
||||||
name_label.label = @"<span size='small' foreground=\"#$color\">$display_name</span>";
|
name_label.label = @"<span size='small' foreground=\"#$color\">$display_name</span>";
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class AccountRow : Gtk.ListBoxRow {
|
||||||
public AccountRow(StreamInteractor stream_interactor, Account account) {
|
public AccountRow(StreamInteractor stream_interactor, Account account) {
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
image.set_jid(stream_interactor, account.bare_jid, account);
|
image.set_conversation(stream_interactor, new Conversation(account.bare_jid, account, Conversation.Type.CHAT));
|
||||||
jid_label.set_label(account.bare_jid.to_string());
|
jid_label.set_label(account.bare_jid.to_string());
|
||||||
|
|
||||||
stream_interactor.connection_manager.connection_error.connect((account, error) => {
|
stream_interactor.connection_manager.connection_error.connect((account, error) => {
|
||||||
|
|
|
@ -182,14 +182,14 @@ public class Dialog : Gtk.Dialog {
|
||||||
|
|
||||||
private void on_received_avatar(Pixbuf pixbuf, Jid jid, Account account) {
|
private void on_received_avatar(Pixbuf pixbuf, Jid jid, Account account) {
|
||||||
if (selected_account.equals(account) && jid.equals(account.bare_jid)) {
|
if (selected_account.equals(account) && jid.equals(account.bare_jid)) {
|
||||||
image.set_jid(stream_interactor, account.bare_jid, account);
|
image.set_conversation(stream_interactor, new Conversation(account.bare_jid, account, Conversation.Type.CHAT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populate_grid_data(Account account) {
|
private void populate_grid_data(Account account) {
|
||||||
active_switch.state_set.disconnect(change_account_state);
|
active_switch.state_set.disconnect(change_account_state);
|
||||||
|
|
||||||
image.set_jid(stream_interactor, account.bare_jid, account);
|
image.set_conversation(stream_interactor, new Conversation(account.bare_jid, account, Conversation.Type.CHAT));
|
||||||
active_switch.set_active(account.enabled);
|
active_switch.set_active(account.enabled);
|
||||||
jid_label.label = account.bare_jid.to_string();
|
jid_label.label = account.bare_jid.to_string();
|
||||||
|
|
||||||
|
|
|
@ -72,13 +72,13 @@ public class Notifications : Object {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(conversation.counterpart, conversation.account)) {
|
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(conversation.counterpart, conversation.account)) {
|
||||||
string muc_occupant = Util.get_display_name(stream_interactor, content_item.jid, conversation.account);
|
string muc_occupant = Util.get_participant_display_name(stream_interactor, conversation, content_item.jid);
|
||||||
text = @"$muc_occupant: $text";
|
text = @"$muc_occupant: $text";
|
||||||
}
|
}
|
||||||
notifications[conversation].set_title(display_name);
|
notifications[conversation].set_title(display_name);
|
||||||
notifications[conversation].set_body(text);
|
notifications[conversation].set_body(text);
|
||||||
try {
|
try {
|
||||||
Cairo.ImageSurface conversation_avatar = yield (new AvatarGenerator(40, 40)).draw_conversation(stream_interactor, conversation);
|
Cairo.ImageSurface conversation_avatar = (yield Util.get_conversation_avatar_drawer(stream_interactor, conversation)).size(40, 40).draw_image_surface();
|
||||||
notifications[conversation].set_icon(get_pixbuf_icon(conversation_avatar));
|
notifications[conversation].set_icon(get_pixbuf_icon(conversation_avatar));
|
||||||
} catch (Error e) { }
|
} catch (Error e) { }
|
||||||
window.get_application().send_notification(conversation.id.to_string(), notifications[conversation]);
|
window.get_application().send_notification(conversation.id.to_string(), notifications[conversation]);
|
||||||
|
@ -95,7 +95,7 @@ public class Notifications : Object {
|
||||||
Notification notification = new Notification(_("Subscription request"));
|
Notification notification = new Notification(_("Subscription request"));
|
||||||
notification.set_body(conversation.counterpart.to_string());
|
notification.set_body(conversation.counterpart.to_string());
|
||||||
try {
|
try {
|
||||||
Cairo.ImageSurface jid_avatar = yield (new AvatarGenerator(40, 40)).draw_jid(stream_interactor, conversation.counterpart, conversation.account);
|
Cairo.ImageSurface jid_avatar = (yield Util.get_conversation_avatar_drawer(stream_interactor, conversation)).size(40, 40).draw_image_surface();
|
||||||
notification.set_icon(get_pixbuf_icon(jid_avatar));
|
notification.set_icon(get_pixbuf_icon(jid_avatar));
|
||||||
} catch (Error e) { }
|
} catch (Error e) { }
|
||||||
notification.set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id));
|
notification.set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id));
|
||||||
|
@ -119,21 +119,22 @@ public class Notifications : Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void on_invite_received(Account account, Jid room_jid, Jid from_jid, string? password, string? reason) {
|
private async void on_invite_received(Account account, Jid room_jid, Jid from_jid, string? password, string? reason) {
|
||||||
string display_name = Util.get_display_name(stream_interactor, from_jid, account);
|
Conversation direct_conversation = new Conversation(from_jid, account, Conversation.Type.CHAT);
|
||||||
|
string display_name = Util.get_participant_display_name(stream_interactor, direct_conversation, from_jid);
|
||||||
string display_room = room_jid.bare_jid.to_string();
|
string display_room = room_jid.bare_jid.to_string();
|
||||||
Notification notification = new Notification(_("Invitation to %s").printf(display_room));
|
Notification notification = new Notification(_("Invitation to %s").printf(display_room));
|
||||||
string body = _("%s invited you to %s").printf(display_name, display_room);
|
string body = _("%s invited you to %s").printf(display_name, display_room);
|
||||||
notification.set_body(body);
|
notification.set_body(body);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Cairo.ImageSurface jid_avatar = yield (new AvatarGenerator(40, 40)).draw_jid(stream_interactor, from_jid, account);
|
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));
|
notification.set_icon(get_pixbuf_icon(jid_avatar));
|
||||||
} catch (Error e) { }
|
} catch (Error e) { }
|
||||||
|
|
||||||
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(room_jid, account, Conversation.Type.GROUPCHAT);
|
Conversation group_conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(room_jid, account, Conversation.Type.GROUPCHAT);
|
||||||
notification.set_default_action_and_target_value("app.open-muc-join", new Variant.int32(conversation.id));
|
notification.set_default_action_and_target_value("app.open-muc-join", new Variant.int32(group_conversation.id));
|
||||||
notification.add_button_with_target_value(_("Deny"), "app.deny-invite", conversation.id);
|
notification.add_button_with_target_value(_("Deny"), "app.deny-invite", group_conversation.id);
|
||||||
notification.add_button_with_target_value(_("Accept"), "app.open-muc-join", conversation.id);
|
notification.add_button_with_target_value(_("Accept"), "app.open-muc-join", group_conversation.id);
|
||||||
window.get_application().send_notification(null, notification);
|
window.get_application().send_notification(null, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class List : Box {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add_occupant(Jid jid) {
|
public void add_occupant(Jid jid) {
|
||||||
rows[jid] = new ListRow(stream_interactor, conversation.account, jid);
|
rows[jid] = new ListRow(stream_interactor, conversation, jid);
|
||||||
list_box.add(rows[jid]);
|
list_box.add(rows[jid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,12 +83,12 @@ public class List : Box {
|
||||||
|
|
||||||
private void header(ListBoxRow row, ListBoxRow? before_row) {
|
private void header(ListBoxRow row, ListBoxRow? before_row) {
|
||||||
ListRow c1 = row as ListRow;
|
ListRow c1 = row as ListRow;
|
||||||
Xmpp.Xep.Muc.Affiliation? a1 = stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c1.jid, c1.account);
|
Xmpp.Xep.Muc.Affiliation? a1 = stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c1.jid, c1.conversation.account);
|
||||||
if (a1 == null) return;
|
if (a1 == null) return;
|
||||||
|
|
||||||
if (before_row != null) {
|
if (before_row != null) {
|
||||||
ListRow c2 = (ListRow) before_row;
|
ListRow c2 = (ListRow) before_row;
|
||||||
Xmpp.Xep.Muc.Affiliation? a2 = stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c2.jid, c2.account);
|
Xmpp.Xep.Muc.Affiliation? a2 = stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c2.jid, c2.conversation.account);
|
||||||
if (a1 != a2) {
|
if (a1 != a2) {
|
||||||
row.set_header(generate_header_widget(a1, false));
|
row.set_header(generate_header_widget(a1, false));
|
||||||
} else if (row.get_header() != null){
|
} else if (row.get_header() != null){
|
||||||
|
@ -145,8 +145,8 @@ public class List : Box {
|
||||||
if (row1.get_type().is_a(typeof(ListRow)) && row2.get_type().is_a(typeof(ListRow))) {
|
if (row1.get_type().is_a(typeof(ListRow)) && row2.get_type().is_a(typeof(ListRow))) {
|
||||||
ListRow c1 = row1 as ListRow;
|
ListRow c1 = row1 as ListRow;
|
||||||
ListRow c2 = row2 as ListRow;
|
ListRow c2 = row2 as ListRow;
|
||||||
int affiliation1 = get_affiliation_ranking(stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c1.jid, c1.account) ?? Xmpp.Xep.Muc.Affiliation.NONE);
|
int affiliation1 = get_affiliation_ranking(stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c1.jid, c1.conversation.account) ?? Xmpp.Xep.Muc.Affiliation.NONE);
|
||||||
int affiliation2 = get_affiliation_ranking(stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c2.jid, c2.account) ?? Xmpp.Xep.Muc.Affiliation.NONE);
|
int affiliation2 = get_affiliation_ranking(stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c2.jid, c2.conversation.account) ?? Xmpp.Xep.Muc.Affiliation.NONE);
|
||||||
if (affiliation1 < affiliation2) return -1;
|
if (affiliation1 < affiliation2) return -1;
|
||||||
else if (affiliation1 > affiliation2) return 1;
|
else if (affiliation1 > affiliation2) return 1;
|
||||||
else return c1.name_label.label.collate(c2.name_label.label);
|
else return c1.name_label.label.collate(c2.name_label.label);
|
||||||
|
|
|
@ -11,15 +11,15 @@ public class ListRow : ListBoxRow {
|
||||||
[GtkChild] private AvatarImage image;
|
[GtkChild] private AvatarImage image;
|
||||||
[GtkChild] public Label name_label;
|
[GtkChild] public Label name_label;
|
||||||
|
|
||||||
public Account? account;
|
public Conversation? conversation;
|
||||||
public Jid? jid;
|
public Jid? jid;
|
||||||
|
|
||||||
public ListRow(StreamInteractor stream_interactor, Account account, Jid jid) {
|
public ListRow(StreamInteractor stream_interactor, Conversation conversation, Jid jid) {
|
||||||
this.account = account;
|
this.conversation = conversation;
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
|
|
||||||
name_label.label = Util.get_display_name(stream_interactor, jid, account);
|
name_label.label = Util.get_participant_display_name(stream_interactor, conversation, jid);
|
||||||
image.set_jid(stream_interactor, jid, account);
|
image.set_conversation_participant(stream_interactor, conversation, jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListRow.label(string c, string text) {
|
public ListRow.label(string c, string text) {
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class View : Popover {
|
||||||
ListRow? list_row = list.list_box.get_selected_row() as ListRow;
|
ListRow? list_row = list.list_box.get_selected_row() as ListRow;
|
||||||
if (list_row == null) return;
|
if (list_row == null) return;
|
||||||
|
|
||||||
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(list_row.jid, list_row.account, Conversation.Type.GROUPCHAT_PM);
|
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(list_row.jid, list_row.conversation.account, Conversation.Type.GROUPCHAT_PM);
|
||||||
stream_interactor.get_module(ConversationManager.IDENTITY).start_conversation(conversation);
|
stream_interactor.get_module(ConversationManager.IDENTITY).start_conversation(conversation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,14 +12,14 @@ private const string[] material_colors_500 = {"F44336", "E91E63", "9C27B0", "673
|
||||||
private const string[] material_colors_300 = {"E57373", "F06292", "BA68C8", "9575CD", "7986CB", "64B5F6", "4FC3F7", "4DD0E1", "4DB6AC", "81C784", "AED581", "DCE775", "FFD54F", "FFB74D", "FF8A65", "A1887F"};
|
private const string[] material_colors_300 = {"E57373", "F06292", "BA68C8", "9575CD", "7986CB", "64B5F6", "4FC3F7", "4DD0E1", "4DB6AC", "81C784", "AED581", "DCE775", "FFD54F", "FFB74D", "FF8A65", "A1887F"};
|
||||||
private const string[] material_colors_200 = {"EF9A9A", "F48FB1", "CE93D8", "B39DDB", "9FA8DA", "90CAF9", "81D4FA", "80DEEA", "80CBC4", "A5D6A7", "C5E1A5", "E6EE9C", "FFE082", "FFCC80", "FFAB91", "BCAAA4"};
|
private const string[] material_colors_200 = {"EF9A9A", "F48FB1", "CE93D8", "B39DDB", "9FA8DA", "90CAF9", "81D4FA", "80DEEA", "80CBC4", "A5D6A7", "C5E1A5", "E6EE9C", "FFE082", "FFCC80", "FFAB91", "BCAAA4"};
|
||||||
|
|
||||||
public static string get_avatar_hex_color(StreamInteractor stream_interactor, Account account, Jid jid) {
|
public static string get_avatar_hex_color(StreamInteractor stream_interactor, Account account, Jid jid, Conversation? conversation = null) {
|
||||||
uint hash = get_relevant_jid(stream_interactor, account, jid).to_string().hash();
|
uint hash = get_relevant_jid(stream_interactor, account, jid, conversation).to_string().hash();
|
||||||
return material_colors_300[hash % material_colors_300.length];
|
return material_colors_300[hash % material_colors_300.length];
|
||||||
// return tango_colors_light[name.hash() % tango_colors_light.length];
|
// return tango_colors_light[name.hash() % tango_colors_light.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string get_name_hex_color(StreamInteractor stream_interactor, Account account, Jid jid, bool dark_theme = false) {
|
public static string get_name_hex_color(StreamInteractor stream_interactor, Account account, Jid jid, bool dark_theme = false, Conversation? conversation = null) {
|
||||||
uint hash = get_relevant_jid(stream_interactor, account, jid).to_string().hash();
|
uint hash = get_relevant_jid(stream_interactor, account, jid, conversation).to_string().hash();
|
||||||
if (dark_theme) {
|
if (dark_theme) {
|
||||||
return material_colors_300[hash % material_colors_300.length];
|
return material_colors_300[hash % material_colors_300.length];
|
||||||
} else {
|
} else {
|
||||||
|
@ -28,8 +28,9 @@ public static string get_name_hex_color(StreamInteractor stream_interactor, Acco
|
||||||
// return tango_colors_medium[name.hash() % tango_colors_medium.length];
|
// return tango_colors_medium[name.hash() % tango_colors_medium.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Jid get_relevant_jid(StreamInteractor stream_interactor, Account account, Jid jid) {
|
private static Jid get_relevant_jid(StreamInteractor stream_interactor, Account account, Jid jid, Conversation? conversation = null) {
|
||||||
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(jid.bare_jid, account)) {
|
Conversation conversation_ = conversation ?? stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid.bare_jid, account);
|
||||||
|
if (conversation_ != null && conversation_.type_ == Conversation.Type.GROUPCHAT) {
|
||||||
Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(jid, account);
|
Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(jid, account);
|
||||||
if (real_jid != null) {
|
if (real_jid != null) {
|
||||||
return real_jid.bare_jid;
|
return real_jid.bare_jid;
|
||||||
|
@ -51,15 +52,109 @@ public static string color_for_show(string show) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string get_conversation_display_name(StreamInteractor stream_interactor, Conversation conversation) {
|
public static async AvatarDrawer get_conversation_avatar_drawer(StreamInteractor stream_interactor, Conversation conversation) {
|
||||||
if (conversation.type_ == Conversation.Type.GROUPCHAT_PM) {
|
return yield get_conversation_participants_avatar_drawer(stream_interactor, conversation, new Jid[0]);
|
||||||
return conversation.counterpart.resourcepart + " from " + get_display_name(stream_interactor, conversation.counterpart.bare_jid, conversation.account);
|
|
||||||
}
|
|
||||||
return get_display_name(stream_interactor, conversation.counterpart, conversation.account);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string get_display_name(StreamInteractor stream_interactor, Jid jid, Account account, bool fallback_to_localpart = false) {
|
public static async AvatarDrawer get_conversation_participants_avatar_drawer(StreamInteractor stream_interactor, Conversation conversation, Jid[] jids) {
|
||||||
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(jid, account)) {
|
AvatarManager avatar_manager = stream_interactor.get_module(AvatarManager.IDENTITY);
|
||||||
|
MucManager muc_manager = stream_interactor.get_module(MucManager.IDENTITY);
|
||||||
|
if (conversation.type_ != Conversation.Type.GROUPCHAT) {
|
||||||
|
Jid jid = jids.length == 1 ? jids[0] : conversation.counterpart;
|
||||||
|
Jid avatar_jid = jid;
|
||||||
|
if (conversation.type_ == Conversation.Type.GROUPCHAT_PM) avatar_jid = muc_manager.get_real_jid(avatar_jid, conversation.account) ?? avatar_jid;
|
||||||
|
return new AvatarDrawer().tile(yield avatar_manager.get_avatar(conversation.account, avatar_jid), jids.length == 1 ?
|
||||||
|
get_participant_display_name(stream_interactor, conversation, jid) :
|
||||||
|
get_conversation_display_name(stream_interactor, conversation),
|
||||||
|
Util.get_avatar_hex_color(stream_interactor, conversation.account, jid, conversation));
|
||||||
|
}
|
||||||
|
if (jids.length > 0) {
|
||||||
|
AvatarDrawer drawer = new AvatarDrawer();
|
||||||
|
for (int i = 0; i < (jids.length <= 4 ? jids.length : 3); i++) {
|
||||||
|
Jid avatar_jid = jids[i];
|
||||||
|
Gdk.Pixbuf? part_avatar = yield avatar_manager.get_avatar(conversation.account, avatar_jid);
|
||||||
|
if (part_avatar == null && avatar_jid.equals_bare(conversation.counterpart) && muc_manager.is_private_room(conversation.account, conversation.counterpart)) {
|
||||||
|
avatar_jid = muc_manager.get_real_jid(avatar_jid, conversation.account) ?? avatar_jid;
|
||||||
|
part_avatar = yield avatar_manager.get_avatar(conversation.account, avatar_jid);
|
||||||
|
}
|
||||||
|
drawer.tile(part_avatar, get_participant_display_name(stream_interactor, conversation, jids[i]),
|
||||||
|
Util.get_avatar_hex_color(stream_interactor, conversation.account, jids[i], conversation));
|
||||||
|
}
|
||||||
|
if (jids.length > 4) {
|
||||||
|
drawer.plus();
|
||||||
|
}
|
||||||
|
return drawer;
|
||||||
|
}
|
||||||
|
Gdk.Pixbuf? room_avatar = yield avatar_manager.get_avatar(conversation.account, conversation.counterpart);
|
||||||
|
Gee.List<Jid>? occupants = muc_manager.get_other_offline_members(conversation.counterpart, conversation.account);
|
||||||
|
if (room_avatar != null || !muc_manager.is_private_room(conversation.account, conversation.counterpart) || occupants == null || occupants.size == 0) {
|
||||||
|
return new AvatarDrawer().tile(room_avatar, "#", Util.get_avatar_hex_color(stream_interactor, conversation.account, conversation.counterpart, conversation));
|
||||||
|
}
|
||||||
|
AvatarDrawer drawer = new AvatarDrawer();
|
||||||
|
for (int i = 0; i < (occupants.size <= 4 ? occupants.size : 3); i++) {
|
||||||
|
Jid jid = occupants[i];
|
||||||
|
Jid avatar_jid = jid;
|
||||||
|
Gdk.Pixbuf? part_avatar = yield avatar_manager.get_avatar(conversation.account, avatar_jid);
|
||||||
|
if (part_avatar == null && avatar_jid.equals_bare(conversation.counterpart) && muc_manager.is_private_room(conversation.account, conversation.counterpart)) {
|
||||||
|
avatar_jid = muc_manager.get_real_jid(avatar_jid, conversation.account) ?? avatar_jid;
|
||||||
|
part_avatar = yield avatar_manager.get_avatar(conversation.account, avatar_jid);
|
||||||
|
}
|
||||||
|
drawer.tile(part_avatar, get_participant_display_name(stream_interactor, conversation, jid),
|
||||||
|
Util.get_avatar_hex_color(stream_interactor, conversation.account, jid, conversation));
|
||||||
|
}
|
||||||
|
if (occupants.size > 4) {
|
||||||
|
drawer.plus();
|
||||||
|
}
|
||||||
|
return drawer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string get_conversation_display_name(StreamInteractor stream_interactor, Conversation conversation) {
|
||||||
|
if (conversation.type_ == Conversation.Type.CHAT) {
|
||||||
|
string? display_name = get_real_display_name(stream_interactor, conversation.account, conversation.counterpart);
|
||||||
|
if (display_name != null) return display_name;
|
||||||
|
return conversation.counterpart.to_string();
|
||||||
|
}
|
||||||
|
if (conversation.type_ == Conversation.Type.GROUPCHAT) {
|
||||||
|
return get_groupchat_display_name(stream_interactor, conversation.account, conversation.counterpart);
|
||||||
|
}
|
||||||
|
if (conversation.type_ == Conversation.Type.GROUPCHAT_PM) {
|
||||||
|
return _("%s from %s").printf(get_occupant_display_name(stream_interactor, conversation.account, conversation.counterpart), get_groupchat_display_name(stream_interactor, conversation.account, conversation.counterpart.bare_jid));
|
||||||
|
}
|
||||||
|
return conversation.counterpart.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string get_participant_display_name(StreamInteractor stream_interactor, Conversation conversation, Jid participant, bool me_is_me = false) {
|
||||||
|
if (me_is_me) {
|
||||||
|
if (conversation.account.bare_jid.equals_bare(participant) ||
|
||||||
|
(conversation.type_ == Conversation.Type.GROUPCHAT || conversation.type_ == Conversation.Type.GROUPCHAT_PM) &&
|
||||||
|
conversation.nickname != null && participant.equals_bare(conversation.counterpart) && conversation.nickname == participant.resourcepart) {
|
||||||
|
return _("Me");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conversation.type_ == Conversation.Type.CHAT) {
|
||||||
|
return get_real_display_name(stream_interactor, conversation.account, participant, me_is_me) ?? participant.bare_jid.to_string();
|
||||||
|
}
|
||||||
|
if ((conversation.type_ == Conversation.Type.GROUPCHAT || conversation.type_ == Conversation.Type.GROUPCHAT_PM) && conversation.counterpart.equals_bare(participant)) {
|
||||||
|
return get_occupant_display_name(stream_interactor, conversation.account, participant);
|
||||||
|
}
|
||||||
|
return participant.bare_jid.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? get_real_display_name(StreamInteractor stream_interactor, Account account, Jid jid, bool me_is_me = false) {
|
||||||
|
if (me_is_me && jid.equals_bare(account.bare_jid)) {
|
||||||
|
return _("Me");
|
||||||
|
}
|
||||||
|
if (jid.equals_bare(account.bare_jid) && account.alias != null && account.alias.length != 0) {
|
||||||
|
return account.alias;
|
||||||
|
}
|
||||||
|
Roster.Item roster_item = stream_interactor.get_module(RosterManager.IDENTITY).get_roster_item(account, jid);
|
||||||
|
if (roster_item != null && roster_item.name != null && roster_item.name != "") {
|
||||||
|
return roster_item.name;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string get_groupchat_display_name(StreamInteractor stream_interactor, Account account, Jid jid) {
|
||||||
MucManager muc_manager = stream_interactor.get_module(MucManager.IDENTITY);
|
MucManager muc_manager = stream_interactor.get_module(MucManager.IDENTITY);
|
||||||
string room_name = muc_manager.get_room_name(account, jid);
|
string room_name = muc_manager.get_room_name(account, jid);
|
||||||
if (room_name != null && room_name != jid.localpart) {
|
if (room_name != null && room_name != jid.localpart) {
|
||||||
|
@ -70,41 +165,28 @@ public static string get_display_name(StreamInteractor stream_interactor, Jid ji
|
||||||
if (other_occupants != null && other_occupants.size > 0) {
|
if (other_occupants != null && other_occupants.size > 0) {
|
||||||
var builder = new StringBuilder ();
|
var builder = new StringBuilder ();
|
||||||
foreach(Jid occupant in other_occupants) {
|
foreach(Jid occupant in other_occupants) {
|
||||||
|
|
||||||
if (builder.len != 0) {
|
if (builder.len != 0) {
|
||||||
builder.append(", ");
|
builder.append(", ");
|
||||||
}
|
}
|
||||||
builder.append(get_display_name(stream_interactor, occupant, account, true).split(" ")[0]);
|
builder.append((get_real_display_name(stream_interactor, account, occupant) ?? occupant.localpart).split(" ")[0]);
|
||||||
}
|
}
|
||||||
return builder.str;
|
return builder.str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account)) {
|
return jid.to_string();
|
||||||
return jid.resourcepart;
|
|
||||||
} else {
|
|
||||||
if (jid.equals_bare(account.bare_jid)) {
|
|
||||||
if (account.alias == null || account.alias == "") {
|
|
||||||
return _("Me");
|
|
||||||
} else {
|
|
||||||
return account.alias;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Roster.Item roster_item = stream_interactor.get_module(RosterManager.IDENTITY).get_roster_item(account, jid);
|
|
||||||
if (roster_item != null && roster_item.name != null && roster_item.name != "") {
|
|
||||||
return roster_item.name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to bare_jid / localpart
|
private static string get_occupant_display_name(StreamInteractor stream_interactor, Account account, Jid jid, bool me_is_me = false) {
|
||||||
if (fallback_to_localpart && jid.localpart != null) {
|
MucManager muc_manager = stream_interactor.get_module(MucManager.IDENTITY);
|
||||||
return jid.localpart;
|
/* TODO: MUC Real JID
|
||||||
} else {
|
if (muc_manager.is_private_room(account, jid.bare_jid)) {
|
||||||
return jid.bare_jid.to_string();
|
Jid? real_jid = muc_manager.get_real_jid(jid, account);
|
||||||
|
if (real_jid != null) {
|
||||||
|
string? display_name = get_real_display_name(stream_interactor, account, real_jid, me_is_me);
|
||||||
|
if (display_name != null) return display_name;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
return jid.resourcepart ?? jid.to_string();
|
||||||
public static string get_message_display_name(StreamInteractor stream_interactor, Entities.Message message, Account account) {
|
|
||||||
return get_display_name(stream_interactor, message.from, account);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void image_set_from_scaled_pixbuf(Image image, Gdk.Pixbuf pixbuf, int scale = 0, int width = 0, int height = 0) {
|
public static void image_set_from_scaled_pixbuf(Image image, Gdk.Pixbuf pixbuf, int scale = 0, int width = 0, int height = 0) {
|
||||||
|
|
Loading…
Reference in a new issue