messenger-gtk

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

commit 7521023e5e1bd2df76006418085f7ef5e1246abe
parent 8885ce815870361670c5d12d757ab01f189b73b9
Author: Jacki <jacki@thejackimonster.de>
Date:   Thu, 25 Apr 2024 20:27:27 +0200

Allow setting profile picture during creation

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

Diffstat:
Mresources/ui/contact_info.ui | 2+-
Mresources/ui/new_account.ui | 4++--
Msrc/account.c | 31+++++++++++++++++++++++++++++++
Msrc/account.h | 12++++++++++++
Msrc/event.c | 15++++++---------
Msrc/ui/contact_info.c | 1+
Msrc/ui/messenger.c | 2++
Msrc/ui/new_account.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/ui/new_account.h | 13+++++++++++++
9 files changed, 198 insertions(+), 15 deletions(-)

diff --git a/resources/ui/contact_info.ui b/resources/ui/contact_info.ui @@ -190,7 +190,7 @@ Author: Tobias Frisch <child> <object class="GtkFileChooserButton" id="profile_chooser_button"> <property name="can-focus">False</property> - <property name="title" translatable="yes"/> + <property name="title" translatable="yes">Select profile picture</property> </object> <packing> <property name="expand">False</property> diff --git a/resources/ui/new_account.ui b/resources/ui/new_account.ui @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.38.2 +<!-- Generated with glade 3.40.0 Copyright (C) 2021‑‑2022 GNUnet e.V. @@ -125,7 +125,7 @@ Author: Tobias Frisch <object class="GtkFileChooserButton" id="account_avatar_file"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="title" translatable="yes"/> + <property name="title" translatable="yes">Select profile picture</property> </object> <packing> <property name="expand">False</property> diff --git a/src/account.c b/src/account.c @@ -126,6 +126,37 @@ account_add_name_avatar_to_info(const struct GNUNET_CHAT_Account *account, } void +account_switch_name_avatar_to_info(const struct GNUNET_CHAT_Account *account, + HdyAvatar *avatar) +{ + g_assert(avatar); + + MESSENGER_AccountInfo *info = GNUNET_CHAT_account_get_user_pointer(account); + + if (!info) + return; + + if (g_list_find(info->name_avatars, avatar)) + return; + + GList *list = infos; + while (list) + { + MESSENGER_AccountInfo *other = (MESSENGER_AccountInfo*) list->data; + + if (g_list_find(other->name_avatars, avatar)) + { + account_remove_name_avatar_from_info(other->account, avatar); + break; + } + + list = g_list_next(list); + } + + account_add_name_avatar_to_info(account, avatar); +} + +void account_remove_name_avatar_from_info(const struct GNUNET_CHAT_Account *account, HdyAvatar *avatar) { diff --git a/src/account.h b/src/account.h @@ -78,6 +78,18 @@ account_add_name_avatar_to_info(const struct GNUNET_CHAT_Account *account, HdyAvatar *avatar); /** + * Switches a HdyAvatar to the list of avatars + * in case it's in another list. Otherwise it + * gets added as usual. + * + * @param account Chat account + * @param avatar Avatar + */ +void +account_switch_name_avatar_to_info(const struct GNUNET_CHAT_Account *account, + HdyAvatar *avatar); + +/** * Removes a HdyAvatar from the list of avatars * which get updated by state changes. * diff --git a/src/event.c b/src/event.c @@ -126,8 +126,8 @@ _iterate_reload_account(void *cls, MESSENGER_Application *app = (MESSENGER_Application*) cls; - if (GNUNET_YES == account_create_info(account)) - account_update_attributes(account, app); + account_create_info(account); + account_update_attributes(account, app); return GNUNET_YES; } @@ -135,8 +135,6 @@ _iterate_reload_account(void *cls, static void _reload_accounts(MESSENGER_Application *app) { - account_cleanup_infos(); - GNUNET_CHAT_iterate_accounts( app->chat.messenger.handle, _iterate_reload_account, @@ -330,6 +328,9 @@ event_update_profile(MESSENGER_Application *app) { g_assert(app); + if (app->ui.new_account.dialog) + ui_new_account_dialog_update(app, &(app->ui.new_account)); + UI_MESSENGER_Handle *ui = &(app->ui.messenger); CHAT_MESSENGER_Handle *chat = &(app->chat.messenger); @@ -337,7 +338,7 @@ event_update_profile(MESSENGER_Application *app) const char *name = GNUNET_CHAT_get_name(chat->handle); - account_add_name_avatar_to_info( + account_switch_name_avatar_to_info( GNUNET_CHAT_get_connected(chat->handle), ui->profile_avatar ); @@ -949,8 +950,6 @@ _iterate_contacts_update_own(void *cls, if (GNUNET_YES != GNUNET_CHAT_contact_is_owned(contact)) return GNUNET_YES; - printf("contact-update! %s\n", GNUNET_CHAT_contact_get_name(contact)); - contact_update_attributes(contact, app); return GNUNET_YES; } @@ -969,8 +968,6 @@ event_update_attributes(MESSENGER_Application *app) if (account) account_update_attributes(account, app); - printf("update!\n"); - GNUNET_CHAT_iterate_contacts( chat->handle, _iterate_contacts_update_own, diff --git a/src/ui/contact_info.c b/src/ui/contact_info.c @@ -124,6 +124,7 @@ handle_profile_chooser_update_preview(GtkFileChooser *file_chooser, goto skip_avatar; hdy_avatar_set_loadable_icon(avatar, G_LOADABLE_ICON(icon)); + g_object_unref(icon); have_preview = true; skip_avatar: diff --git a/src/ui/messenger.c b/src/ui/messenger.c @@ -389,6 +389,8 @@ handle_main_window_destroy(UNUSED GtkWidget *window, ui_messenger_cleanup(&(app->ui.messenger)); ui_accounts_dialog_cleanup(&(app->ui.accounts), app); + account_cleanup_infos(); + application_exit(app, MESSENGER_QUIT); } diff --git a/src/ui/new_account.c b/src/ui/new_account.c @@ -25,6 +25,8 @@ #include "new_account.h" #include "../application.h" +#include "../contact.h" +#include "../file.h" #include "../ui.h" static gboolean @@ -85,8 +87,59 @@ handle_account_entry_activate(UNUSED GtkEntry *entry, MESSENGER_Application *app = (MESSENGER_Application*) user_data; _open_new_account(app->ui.new_account.account_entry, app); +} - gtk_window_close(GTK_WINDOW(app->ui.new_account.dialog)); +static void +handle_account_avatar_file_update_preview(GtkFileChooser *file_chooser, + gpointer user_data) +{ + g_assert((file_chooser) && (user_data)); + + HdyAvatar *avatar = HDY_AVATAR(user_data); + + gboolean have_preview = false; + gchar *filename = gtk_file_chooser_get_preview_filename(file_chooser); + + if ((!filename) || (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))) + goto skip_preview; + + GFile *file = g_file_new_for_path(filename); + + if (!file) + goto skip_icon; + + GIcon *icon = g_file_icon_new(file); + + if (!icon) + goto skip_avatar; + + hdy_avatar_set_loadable_icon(avatar, G_LOADABLE_ICON(icon)); + g_object_unref(icon); + have_preview = true; + +skip_avatar: + g_object_unref(file); + +skip_icon: + g_free(filename); + +skip_preview: + gtk_file_chooser_set_preview_widget_active(file_chooser, have_preview); +} + +static void +handle_account_avatar_file_set(GtkFileChooserButton *button, + gpointer user_data) +{ + g_assert(user_data); + + GtkFileChooser *file_chooser = GTK_FILE_CHOOSER(button); + UI_NEW_ACCOUNT_Handle *handle = (UI_NEW_ACCOUNT_Handle*) user_data; + + if (handle->filename) + g_free(handle->filename); + + handle->filename = gtk_file_chooser_get_preview_filename(file_chooser); } static void @@ -108,8 +161,6 @@ handle_confirm_button_click(UNUSED GtkButton *button, MESSENGER_Application *app = (MESSENGER_Application*) user_data; _open_new_account(app->ui.new_account.account_entry, app); - - gtk_window_close(GTK_WINDOW(app->ui.new_account.dialog)); } static void @@ -156,6 +207,20 @@ ui_new_account_dialog_init(MESSENGER_Application *app, gtk_builder_get_object(handle->builder, "account_avatar_file") ); + g_signal_connect( + handle->account_avatar_file, + "update-preview", + G_CALLBACK(handle_account_avatar_file_update_preview), + handle->account_avatar + ); + + g_signal_connect( + handle->account_avatar_file, + "file-set", + G_CALLBACK(handle_account_avatar_file_set), + handle + ); + handle->account_entry = GTK_ENTRY( gtk_builder_get_object(handle->builder, "account_entry") ); @@ -204,6 +269,65 @@ ui_new_account_dialog_init(MESSENGER_Application *app, ); } +static void +_cb_file_upload(void *cls, + struct GNUNET_CHAT_File *file, + uint64_t completed, + uint64_t size) +{ + g_assert((cls) && (file)); + + MESSENGER_Application *app = (MESSENGER_Application*) cls; + + file_update_upload_info(file, completed, size); + + if (completed < size) + return; + + struct GNUNET_CHAT_Uri *uri = GNUNET_CHAT_file_get_uri(file); + + if (!uri) + return; + + char *uri_string = GNUNET_CHAT_uri_to_string(uri); + + if (uri_string) + { + GNUNET_CHAT_set_attribute( + app->chat.messenger.handle, + ATTRIBUTE_PROFILE_PICTURE, + uri_string, + GNUNET_TIME_relative_get_forever_() + ); + + GNUNET_free(uri_string); + } + + GNUNET_CHAT_uri_destroy(uri); +} + +void +ui_new_account_dialog_update(MESSENGER_Application *app, + UI_NEW_ACCOUNT_Handle *handle) +{ + g_assert((app) && (handle)); + + gtk_window_close(GTK_WINDOW(app->ui.new_account.dialog)); + + if (!(handle->filename)) + return; + + GNUNET_CHAT_upload_file( + app->chat.messenger.handle, + handle->filename, + _cb_file_upload, + app + ); + + g_free(handle->filename); + handle->filename = NULL; +} + void ui_new_account_dialog_cleanup(UI_NEW_ACCOUNT_Handle *handle) { @@ -211,6 +335,9 @@ ui_new_account_dialog_cleanup(UI_NEW_ACCOUNT_Handle *handle) g_object_unref(handle->builder); + if (handle->filename) + g_free(handle->filename); + guint show = handle->show_queued; memset(handle, 0, sizeof(*handle)); handle->show_queued = show; diff --git a/src/ui/new_account.h b/src/ui/new_account.h @@ -30,6 +30,7 @@ typedef struct UI_NEW_ACCOUNT_Handle { guint show_queued; + gchar *filename; GtkBuilder *builder; GtkDialog *dialog; @@ -55,6 +56,18 @@ ui_new_account_dialog_init(MESSENGER_Application *app, UI_NEW_ACCOUNT_Handle *handle); /** + * Triggers an update of a new account dialog handle + * to process selected changes regarding the new + * account and finish account creation. + * + * @param app Messenger application + * @param handle New account dialog handle + */ +void +ui_new_account_dialog_update(MESSENGER_Application *app, + UI_NEW_ACCOUNT_Handle *handle); + +/** * Cleans up the allocated resources and resets the * state of a given new account dialog handle. *