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:
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)
{