From db3b0d5f233ee3587ae54f8f035222cb098b11dd Mon Sep 17 00:00:00 2001 From: Marvin W Date: Tue, 24 Jan 2023 18:59:46 +0100 Subject: New Avatar UI --- libdino/src/service/avatar_manager.vala | 78 ++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 15 deletions(-) (limited to 'libdino/src') diff --git a/libdino/src/service/avatar_manager.vala b/libdino/src/service/avatar_manager.vala index b308aa2b..1296856b 100644 --- a/libdino/src/service/avatar_manager.vala +++ b/libdino/src/service/avatar_manager.vala @@ -12,6 +12,7 @@ public class AvatarManager : StreamInteractionModule, Object { public string id { get { return IDENTITY.id; } } public signal void received_avatar(Jid jid, Account account); + public signal void fetched_avatar(Jid jid, Account account); private enum Source { USER_AVATARS, @@ -25,6 +26,7 @@ public class AvatarManager : StreamInteractionModule, Object { private HashMap vcard_avatars = new HashMap(Jid.hash_func, Jid.equals_func); private HashMap cached_pixbuf = new HashMap(); private HashMap> pending_pixbuf = new HashMap>(); + private HashSet pending_fetch = new HashSet(); private const int MAX_PIXEL = 192; public static void start(StreamInteractor stream_interactor, Database db) { @@ -45,6 +47,18 @@ public class AvatarManager : StreamInteractionModule, Object { }); } + public File? get_avatar_file(Account account, Jid jid_) { + string? hash = get_avatar_hash(account, jid_); + if (hash == null) return null; + File file = File.new_for_path(Path.build_filename(folder, hash)); + if (!file.query_exists()) { + fetch_and_store_for_jid(account, jid_); + return null; + } else { + return file; + } + } + private string? get_avatar_hash(Account account, Jid jid_) { Jid jid = jid_; if (!stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid_, account)) { @@ -59,6 +73,7 @@ public class AvatarManager : StreamInteractionModule, Object { } } + [Version (deprecated = true)] public bool has_avatar_cached(Account account, Jid jid) { string? hash = get_avatar_hash(account, jid); return hash != null && cached_pixbuf.has_key(hash); @@ -68,6 +83,7 @@ public class AvatarManager : StreamInteractionModule, Object { return get_avatar_hash(account, jid) != null; } + [Version (deprecated = true)] public Pixbuf? get_cached_avatar(Account account, Jid jid_) { string? hash = get_avatar_hash(account, jid_); if (hash == null) return null; @@ -75,6 +91,7 @@ public class AvatarManager : StreamInteractionModule, Object { return null; } + [Version (deprecated = true)] public async Pixbuf? get_avatar(Account account, Jid jid_) { Jid jid = jid_; if (!stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid_, account)) { @@ -111,17 +128,7 @@ public class AvatarManager : StreamInteractionModule, Object { if (image != null) { cached_pixbuf[hash] = image; } else { - Bytes? bytes = null; - if (source == 1) { - bytes = yield Xmpp.Xep.UserAvatars.fetch_image(stream, jid, hash); - } else if (source == 2) { - bytes = yield Xmpp.Xep.VCard.fetch_image(stream, jid, hash); - if (bytes == null && jid.is_bare()) { - db.avatar.delete().with(db.avatar.jid_id, "=", db.get_jid_id(jid)).perform(); - } - } - if (bytes != null) { - store_image(hash, bytes); + if (yield fetch_and_store(stream, account, jid, source, hash)) { image = yield get_image(hash); } cached_pixbuf[hash] = image; @@ -162,7 +169,7 @@ public class AvatarManager : StreamInteractionModule, Object { ); foreach (var entry in get_avatar_hashes(account, Source.USER_AVATARS).entries) { - user_avatars[entry.key] = entry.value; + on_user_avatar_received(account, entry.key, entry.value); } foreach (var entry in get_avatar_hashes(account, Source.VCARD).entries) { @@ -172,7 +179,7 @@ public class AvatarManager : StreamInteractionModule, Object { continue; } - vcard_avatars[entry.key] = entry.value; + on_vcard_avatar_received(account, entry.key, entry.value); } } @@ -218,12 +225,53 @@ public class AvatarManager : StreamInteractionModule, Object { return ret; } - public void store_image(string id, Bytes data) { + public async bool fetch_and_store_for_jid(Account account, Jid jid) { + int source = -1; + string? hash = null; + if (user_avatars.has_key(jid)) { + hash = user_avatars[jid]; + source = 1; + } else if (vcard_avatars.has_key(jid)) { + hash = vcard_avatars[jid]; + source = 2; + } else { + return false; + } + + XmppStream? stream = stream_interactor.get_stream(account); + if (stream == null || !stream.negotiation_complete) return false; + + return yield fetch_and_store(stream, account, jid, source, hash); + } + + private async bool fetch_and_store(XmppStream stream, Account account, Jid jid, int source, string? hash) { + if (hash == null || pending_fetch.contains(hash)) return false; + + pending_fetch.add(hash); + Bytes? bytes = null; + if (source == 1) { + bytes = yield Xmpp.Xep.UserAvatars.fetch_image(stream, jid, hash); + } else if (source == 2) { + bytes = yield Xmpp.Xep.VCard.fetch_image(stream, jid, hash); + if (bytes == null && jid.is_bare()) { + db.avatar.delete().with(db.avatar.jid_id, "=", db.get_jid_id(jid)).perform(); + } + } + + if (bytes != null) { + yield store_image(hash, bytes); + fetched_avatar(jid, account); + } + pending_fetch.remove(hash); + return bytes != null; + } + + private async void store_image(string id, Bytes data) { File file = File.new_for_path(Path.build_filename(folder, id)); try { if (file.query_exists()) file.delete(); //TODO y? DataOutputStream fos = new DataOutputStream(file.create(FileCreateFlags.REPLACE_DESTINATION)); - fos.write_bytes_async.begin(data); + yield fos.write_bytes_async(data); } catch (Error e) { // Ignore: we failed in storing, so we refuse to display later... } -- cgit v1.2.3-54-g00ecf