messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

commit 5921bac53cee6eb33042d8cd0d2accd4b5f146a3
parent a05965ae509e3dd347d9643ccff99e9563f19365
Author: Jacki <jacki@thejackimonster.de>
Date:   Mon, 22 Apr 2024 18:05:08 +0200

Load profile pictures from attributes dynamically

Signed-off-by: Jacki <jacki@thejackimonster.de>

Diffstat:
Msrc/chat/messenger.c | 1+
Msrc/contact.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/contact.h | 15+++++++++++++++
Msrc/event.c | 17+++++++++++++++--
Msrc/ui/account_entry.c | 22++++++++++++++++++----
Msrc/ui/account_entry.h | 2++
Msrc/ui/chat.c | 18+++++++++++-------
Msrc/ui/contact_info.c | 35++++++++++++++++++++++++++++++++---
Msrc/ui/message.c | 8++++++--
Msrc/ui/send_file.c | 2+-
10 files changed, 269 insertions(+), 19 deletions(-)

diff --git a/src/chat/messenger.c b/src/chat/messenger.c @@ -142,6 +142,7 @@ _chat_messenger_message(void *cls, break; } case GNUNET_CHAT_KIND_CONTACT: + case GNUNET_CHAT_KIND_SHARED_ATTRIBUTES: { application_call_message_event( app, diff --git a/src/contact.c b/src/contact.c @@ -25,6 +25,9 @@ #include "contact.h" #include "ui.h" +#include <gnunet/gnunet_chat_lib.h> +#include <gnunet/gnunet_common.h> +#include <string.h> void contact_create_info(struct GNUNET_CHAT_Contact *contact) @@ -35,6 +38,7 @@ contact_create_info(struct GNUNET_CHAT_Contact *contact) MESSENGER_ContactInfo* info = g_malloc(sizeof(MESSENGER_ContactInfo)); info->last_message = NULL; + info->icon = NULL; info->name_labels = NULL; info->name_avatars = NULL; @@ -62,6 +66,9 @@ contact_destroy_info(struct GNUNET_CHAT_Contact *contact) if (info->visible_widgets) g_list_free(info->visible_widgets); + if (info->icon) + g_object_unref(info->icon); + g_free(info); GNUNET_CHAT_contact_set_user_pointer(contact, NULL); @@ -137,6 +144,9 @@ contact_add_name_avatar_to_info(const struct GNUNET_CHAT_Contact *contact, const char *name = GNUNET_CHAT_contact_get_name(contact); ui_avatar_set_text(avatar, name); + + if (info->icon) + hdy_avatar_set_loadable_icon(avatar, G_LOADABLE_ICON(info->icon)); info->name_avatars = g_list_append(info->name_avatars, avatar); } @@ -208,6 +218,164 @@ contact_update_info(const struct GNUNET_CHAT_Contact *contact) for (list = info->name_avatars; list; list = list->next) ui_avatar_set_text(HDY_AVATAR(list->data), name); + if (info->icon) + for (list = info->name_avatars; list; list = list->next) + hdy_avatar_set_loadable_icon(HDY_AVATAR(list->data), + G_LOADABLE_ICON(info->icon)); + for (list = info->visible_widgets; list; list = list->next) gtk_widget_set_visible(GTK_WIDGET(list->data), visible); } + +static void +_info_profile_downloaded(void *cls, + struct GNUNET_CHAT_File *file, + uint64_t completed, + uint64_t size) +{ + g_assert((cls) && (file)); + + MESSENGER_ContactInfo* info = (MESSENGER_ContactInfo*) cls; + + if (completed < size) + return; + + const char *preview = GNUNET_CHAT_file_open_preview(file); + + if (!preview) + return; + + GFile *file_object = g_file_new_for_path(preview); + + if (!file_object) + return; + + if (info->icon) + g_object_unref(info->icon); + + info->icon = g_file_icon_new(file_object); + + if (!(info->icon)) + goto skip_avatar; + + GList* list; + for (list = info->name_avatars; list; list = list->next) + hdy_avatar_set_loadable_icon(HDY_AVATAR(list->data), G_LOADABLE_ICON(info->icon)); + +skip_avatar: + g_object_unref(file_object); +} + +static enum GNUNET_GenericReturnValue +_info_iterate_attribute(MESSENGER_ContactInfo* info, + struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Contact *contact, + const char *name, + const char *value) +{ + g_assert((info) && (handle) && (contact) && (name)); + + if ((0 != strcmp(name, ATTRIBUTE_PROFILE_PICTURE)) || (!value)) + return GNUNET_YES; + + struct GNUNET_CHAT_Uri *uri = GNUNET_CHAT_uri_parse(value, NULL); + + if (!uri) + return GNUNET_YES; + + struct GNUNET_CHAT_File *file = GNUNET_CHAT_request_file(handle, uri); + + if (!file) + goto skip_file; + + if (GNUNET_YES == GNUNET_CHAT_file_is_ready(file)) + _info_profile_downloaded( + info, + file, + GNUNET_CHAT_file_get_local_size(file), + GNUNET_CHAT_file_get_size(file) + ); + else if (GNUNET_YES != GNUNET_CHAT_file_is_downloading(file)) + GNUNET_CHAT_file_start_download( + file, + _info_profile_downloaded, + info + ); + +skip_file: + GNUNET_CHAT_uri_destroy(uri); + return GNUNET_YES; +} + +static enum GNUNET_GenericReturnValue +_handle_iterate_attribute(void *cls, + struct GNUNET_CHAT_Handle *handle, + const char *name, + const char *value) +{ + g_assert((cls) && (handle) && (name)); + + struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) cls; + + MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact); + + if (!info) + return GNUNET_NO; + + return _info_iterate_attribute( + info, + handle, + contact, + name, + value + ); +} + +static enum GNUNET_GenericReturnValue +_contact_iterate_attribute(void *cls, + struct GNUNET_CHAT_Contact *contact, + const char *name, + const char *value) +{ + g_assert((cls) && (contact) && (name)); + + struct GNUNET_CHAT_Handle *handle = (struct GNUNET_CHAT_Handle*) cls; + + MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact); + + if (!info) + return GNUNET_NO; + + return _info_iterate_attribute( + info, + handle, + contact, + name, + value + ); +} + +void +contact_update_attributes(struct GNUNET_CHAT_Contact *contact, + MESSENGER_Application *app) +{ + g_assert(app); + + MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact); + + if (!info) + return; + + if (GNUNET_YES == GNUNET_CHAT_contact_is_owned(contact)) + GNUNET_CHAT_get_attributes( + app->chat.messenger.handle, + _handle_iterate_attribute, + contact + ); + else + GNUNET_CHAT_contact_get_attributes( + contact, + _contact_iterate_attribute, + app->chat.messenger.handle + ); +} diff --git a/src/contact.h b/src/contact.h @@ -27,9 +27,12 @@ #include "application.h" +#define ATTRIBUTE_PROFILE_PICTURE "profile" + typedef struct MESSENGER_ContactInfo { void *last_message; + GIcon *icon; GList *name_labels; GList *name_avatars; @@ -146,8 +149,20 @@ contact_remove_visible_widget_to_info(const struct GNUNET_CHAT_Contact *contact, * contact depending on the current state. * * @param contact Chat contact + * @param attributes Flag to check for attributes changes */ void contact_update_info(const struct GNUNET_CHAT_Contact *contact); +/** + * Updates the connected UI elements for a given + * contact based on current attributes changes. + * + * @param contact Chat contact + * @param app Messenger application + */ +void +contact_update_attributes(struct GNUNET_CHAT_Contact *contact, + MESSENGER_Application *app); + #endif /* CONTACT_H_ */ diff --git a/src/event.c b/src/event.c @@ -437,7 +437,15 @@ event_update_chats(MESSENGER_Application *app, else if ((handle) && (handle->entry_box)) _clear_chat_entry(gtk_widget_get_parent(handle->entry_box), app); - contact_create_info(GNUNET_CHAT_message_get_sender(msg)); + struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( + msg + ); + + if (!contact) + return; + + contact_create_info(contact); + contact_update_attributes(contact, app); } static void @@ -502,7 +510,9 @@ event_presence_contact(MESSENGER_Application *app, message = ui_message_new(app, UI_MESSAGE_STATUS); ui_message_update(message, app, msg); + contact_update_attributes(contact, app); _update_contact_context(contact); + ui_message_set_contact(message, contact); const enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind( @@ -558,6 +568,9 @@ event_update_contacts(UNUSED MESSENGER_Application *app, if (!contact) return; + if (GNUNET_CHAT_KIND_SHARED_ATTRIBUTES == GNUNET_CHAT_message_get_kind(msg)) + contact_update_attributes(contact, app); + contact_update_info(contact); _update_contact_context(contact); @@ -775,7 +788,7 @@ _event_update_tag_message_state(MESSENGER_Application *app, if (!target) return; - const struct GNUNET_CHAT_Contact *contact; + struct GNUNET_CHAT_Contact *contact; contact = GNUNET_CHAT_message_get_sender(target); if (contact) diff --git a/src/ui/account_entry.c b/src/ui/account_entry.c @@ -25,6 +25,7 @@ #include "account_entry.h" #include "../application.h" +#include "../contact.h" #include "../ui.h" UI_ACCOUNT_ENTRY_Handle* @@ -34,6 +35,8 @@ ui_account_entry_new(MESSENGER_Application *app) UI_ACCOUNT_ENTRY_Handle* handle = g_malloc(sizeof(UI_ACCOUNT_ENTRY_Handle)); + handle->contact = NULL; + handle->builder = ui_builder_from_resource( application_get_resource_path(app, "ui/account_entry.ui") ); @@ -69,18 +72,29 @@ void ui_account_entry_set_contact(UI_ACCOUNT_ENTRY_Handle* handle, const struct GNUNET_CHAT_Contact *contact) { - g_assert((handle) && (contact)); + g_assert(handle); - const char *name = GNUNET_CHAT_contact_get_name(contact); + if (handle->contact) + { + contact_remove_name_avatar_from_info(handle->contact, handle->entry_avatar); + contact_remove_name_label_from_info(handle->contact, handle->entry_label); + } - ui_avatar_set_text(handle->entry_avatar, name); - ui_label_set_text(handle->entry_label, name); + if (contact) + { + contact_add_name_avatar_to_info(contact, handle->entry_avatar); + contact_add_name_label_to_info(contact, handle->entry_label); + } + + handle->contact = contact; } void ui_account_entry_delete(UI_ACCOUNT_ENTRY_Handle *handle) { g_assert(handle); + + ui_account_entry_set_contact(handle, NULL); g_object_unref(handle->builder); diff --git a/src/ui/account_entry.h b/src/ui/account_entry.h @@ -29,6 +29,8 @@ typedef struct UI_ACCOUNT_ENTRY_Handle { + const struct GNUNET_CHAT_Contact *contact; + GtkBuilder *builder; GtkWidget *entry_box; diff --git a/src/ui/chat.c b/src/ui/chat.c @@ -776,7 +776,7 @@ _drop_any_recording(UI_CHAT_Handle *handle) static void handle_sending_recording_upload_file(UNUSED void *cls, - const struct GNUNET_CHAT_File *file, + struct GNUNET_CHAT_File *file, uint64_t completed, uint64_t size) { @@ -1971,7 +1971,7 @@ _chat_update_files(UI_CHAT_Handle *handle, MESSENGER_Application *app, struct GNUNET_CHAT_Context *context) { - g_assert((handle) && (app) && (context)); + g_assert((handle) && (app)); GList* children = gtk_container_get_children( GTK_CONTAINER(handle->chat_files_listbox) @@ -1995,11 +1995,11 @@ _chat_update_files(UI_CHAT_Handle *handle, closure.app = app; closure.container = GTK_CONTAINER(handle->chat_files_listbox); - const int count = GNUNET_CHAT_context_iterate_files( + const int count = context? GNUNET_CHAT_context_iterate_files( context, iterate_ui_chat_update_context_files, &closure - ); + ) : 0; gtk_widget_set_visible( GTK_WIDGET(handle->chat_details_files_box), @@ -2053,7 +2053,7 @@ _chat_update_media(UI_CHAT_Handle *handle, MESSENGER_Application *app, struct GNUNET_CHAT_Context *context) { - g_assert((handle) && (app) && (context)); + g_assert((handle) && (app)); GList* children = gtk_container_get_children( GTK_CONTAINER(handle->chat_media_flowbox) @@ -2077,11 +2077,11 @@ _chat_update_media(UI_CHAT_Handle *handle, closure.app = app; closure.container = GTK_CONTAINER(handle->chat_media_flowbox); - const int count = GNUNET_CHAT_context_iterate_files( + const int count = context? GNUNET_CHAT_context_iterate_files( context, iterate_ui_chat_update_context_media, &closure - ); + ) : 0; gtk_widget_set_visible( GTK_WIDGET(handle->chat_details_media_box), @@ -2256,6 +2256,10 @@ ui_chat_delete(UI_CHAT_Handle *handle) if (handle->loads) g_list_free_full(handle->loads, (GDestroyNotify) ui_file_load_entry_delete); + _chat_update_contacts(handle, handle->app, NULL); + _chat_update_files(handle, handle->app, NULL); + _chat_update_media(handle, handle->app, NULL); + if (handle->record_pipeline) { gst_element_set_state(handle->record_pipeline, GST_STATE_NULL); diff --git a/src/ui/contact_info.c b/src/ui/contact_info.c @@ -27,6 +27,7 @@ #include "chat_entry.h" #include "../application.h" +#include "../contact.h" #include "../file.h" #include "../ui.h" @@ -143,7 +144,7 @@ skip_preview: static void _cb_file_upload(void *cls, - const struct GNUNET_CHAT_File *file, + struct GNUNET_CHAT_File *file, uint64_t completed, uint64_t size) { @@ -167,7 +168,7 @@ _cb_file_upload(void *cls, { GNUNET_CHAT_set_attribute( app->chat.messenger.handle, - "profile", + ATTRIBUTE_PROFILE_PICTURE, uri_string, GNUNET_TIME_relative_get_forever_() ); @@ -1082,6 +1083,29 @@ ui_contact_info_dialog_init(MESSENGER_Application *app, ); } +static void +_contact_info_update(UI_CONTACT_INFO_Handle *handle, + struct GNUNET_CHAT_Contact *contact) +{ + g_assert(handle); + + struct GNUNET_CHAT_Contact *prev = g_object_get_qdata( + G_OBJECT(handle->contact_avatar), + handle->app->quarks.data + ); + + if (prev) + contact_remove_name_avatar_from_info(prev, handle->contact_avatar); + if (contact) + contact_add_name_avatar_to_info(contact, handle->contact_avatar); + + g_object_set_qdata( + G_OBJECT(handle->contact_avatar), + handle->app->quarks.data, + contact + ); +} + void ui_contact_info_dialog_update(UI_CONTACT_INFO_Handle *handle, struct GNUNET_CHAT_Contact *contact, @@ -1097,7 +1121,11 @@ ui_contact_info_dialog_update(UI_CONTACT_INFO_Handle *handle, else name = GNUNET_CHAT_get_name(handle->app->chat.messenger.handle); - ui_avatar_set_text(handle->contact_avatar, name); + if (contact) + _contact_info_update(handle, contact); + else + ui_avatar_set_text(handle->contact_avatar, name); + ui_entry_set_text(handle->contact_name_entry, name); g_object_set_qdata( @@ -1278,6 +1306,7 @@ ui_contact_info_dialog_cleanup(UI_CONTACT_INFO_Handle *handle) handle->id_draw_signal ); + _contact_info_update(handle, NULL); g_object_unref(handle->builder); if (handle->qr) diff --git a/src/ui/message.c b/src/ui/message.c @@ -36,7 +36,7 @@ static void handle_downloading_file(void *cls, - const struct GNUNET_CHAT_File *file, + struct GNUNET_CHAT_File *file, uint64_t completed, uint64_t size) { @@ -91,7 +91,11 @@ handle_file_button_click(GtkButton *button, } else if (local_size < size) { - GNUNET_CHAT_file_start_download(file, handle_downloading_file, app); + GNUNET_CHAT_file_start_download( + file, + handle_downloading_file, + app + ); gtk_image_set_from_icon_name( handle->file_status_image, diff --git a/src/ui/send_file.c b/src/ui/send_file.c @@ -44,7 +44,7 @@ handle_cancel_button_click(UNUSED GtkButton *button, static void handle_sending_upload_file(UNUSED void *cls, - const struct GNUNET_CHAT_File *file, + struct GNUNET_CHAT_File *file, uint64_t completed, uint64_t size) {