messenger-gtk

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

commit a4a3dba0f0beb345c53b70654654bd555b165475
parent 9c9173f894f25a7363b6027f4e9860f14c9078a6
Author: Jacki <jacki@thejackimonster.de>
Date:   Mon, 15 Apr 2024 18:21:46 +0200

Implement sharing attributes with other contacts

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

Diffstat:
Mresources/ui/contact_info.ui | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/ui/contact_info.c | 255++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/ui/contact_info.h | 6++++++
3 files changed, 376 insertions(+), 18 deletions(-)

diff --git a/resources/ui/contact_info.ui b/resources/ui/contact_info.ui @@ -31,6 +31,16 @@ Author: Tobias Frisch <column type="gchararray"/> </columns> </object> + <object class="GtkListStore" id="sharing_list"> + <columns> + <!-- column-name name --> + <column type="gchararray"/> + <!-- column-name value --> + <column type="gchararray"/> + <!-- column-name shared --> + <column type="gboolean"/> + </columns> + </object> <object class="GtkDialog" id="contact_info_dialog"> <property name="can-focus">False</property> <property name="title" translatable="yes">Contact Information</property> @@ -269,6 +279,50 @@ Author: Tobias Frisch </packing> </child> <child> + <object class="GtkButton" id="share_attributes_button"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="spacing">4</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">emblem-shared-symbolic</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="margin-end">16</property> + <property name="label" translatable="yes">Share Attributes</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> + <child> <object class="GtkStack" id="block_stack"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -365,7 +419,7 @@ Author: Tobias Frisch <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">5</property> + <property name="position">6</property> </packing> </child> <child> @@ -410,7 +464,7 @@ Author: Tobias Frisch <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">6</property> + <property name="position">7</property> </packing> </child> </object> @@ -660,6 +714,81 @@ Author: Tobias Frisch <property name="position">2</property> </packing> </child> + <child> + <object class="GtkBox" id="sharing_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="border-width">8</property> + <property name="orientation">vertical</property> + <property name="spacing">4</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">Shared Attributes:</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkTreeView" id="sharing_tree"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="model">sharing_list</property> + <property name="reorderable">True</property> + <property name="search-column">0</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn"> + <property name="spacing">4</property> + <property name="sizing">autosize</property> + <property name="min-width">120</property> + <property name="title" translatable="yes">Name:</property> + <property name="clickable">True</property> + <property name="sort-indicator">True</property> + <property name="sort-column-id">0</property> + <child> + <object class="GtkCellRendererText"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn"> + <property name="resizable">True</property> + <property name="spacing">4</property> + <property name="sizing">fixed</property> + <property name="fixed-width">50</property> + <property name="title" translatable="yes">Share:</property> + <child> + <object class="GtkCellRendererToggle" id="share_renderer"/> + <attributes> + <attribute name="active">2</attribute> + </attributes> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="name">sharing_page</property> + <property name="position">3</property> + </packing> + </child> </object> </child> </object> diff --git a/src/ui/contact_info.c b/src/ui/contact_info.c @@ -103,47 +103,50 @@ handle_contact_name_entry_activate(UNUSED GtkEntry *entry, } static void -_contact_info_reveal_identity(UI_CONTACT_INFO_Handle *handle) +_contact_info_switch_stack_to(UI_CONTACT_INFO_Handle *handle, + GtkWidget *page_widget) { - g_assert(handle); + g_assert((handle) && (page_widget)); gtk_widget_set_visible(GTK_WIDGET(handle->back_button), TRUE); gtk_stack_set_visible_child( handle->contact_info_stack, - handle->identity_box + page_widget ); } static void -_contact_info_list_attributes(UI_CONTACT_INFO_Handle *handle) +handle_reveal_identity_button_click(UNUSED GtkButton *button, + gpointer user_data) { - g_assert(handle); + g_assert(user_data); - gtk_widget_set_visible(GTK_WIDGET(handle->back_button), TRUE); + struct UI_CONTACT_INFO_Handle *handle = (UI_CONTACT_INFO_Handle*) user_data; - gtk_stack_set_visible_child( - handle->contact_info_stack, - handle->attributes_box - ); + _contact_info_switch_stack_to(handle, handle->identity_box); } static void -handle_reveal_identity_button_click(UNUSED GtkButton *button, +handle_list_attributes_button_click(UNUSED GtkButton *button, gpointer user_data) { g_assert(user_data); - _contact_info_reveal_identity((UI_CONTACT_INFO_Handle*) user_data); + struct UI_CONTACT_INFO_Handle *handle = (UI_CONTACT_INFO_Handle*) user_data; + + _contact_info_switch_stack_to(handle, handle->attributes_box); } static void -handle_list_attributes_button_click(UNUSED GtkButton *button, - gpointer user_data) +handle_share_attributes_button_click(UNUSED GtkButton *button, + gpointer user_data) { g_assert(user_data); - _contact_info_list_attributes((UI_CONTACT_INFO_Handle*) user_data); + struct UI_CONTACT_INFO_Handle *handle = (UI_CONTACT_INFO_Handle*) user_data; + + _contact_info_switch_stack_to(handle, handle->sharing_box); } static void @@ -429,6 +432,114 @@ cb_contact_info_contact_attributes(void *cls, return GNUNET_YES; } +static enum GNUNET_GenericReturnValue +cb_contact_info_unshared_attributes(void *cls, + struct GNUNET_CHAT_Handle *chat, + const char *name, + const char *value) +{ + g_assert((cls) && (chat) && (name) && (value)); + + UI_CONTACT_INFO_Handle *handle = (UI_CONTACT_INFO_Handle*) cls; + GtkTreeModel *model = GTK_TREE_MODEL(handle->sharing_list); + GtkTreeIter iter; + + GValue val_name = G_VALUE_INIT; + GValue val_value = G_VALUE_INIT; + + gboolean valid = gtk_tree_model_get_iter_first(model, &iter); + gboolean match = FALSE; + + while (valid) + { + gtk_tree_model_get_value(model, &iter, 0, &val_name); + gtk_tree_model_get_value(model, &iter, 1, &val_value); + + if ((0 == strcmp(g_value_get_string(&val_name), name)) && + (0 == strcmp(g_value_get_string(&val_value), value))) + match = TRUE; + + g_value_unset(&val_name); + g_value_unset(&val_value); + + if (match) + break; + + valid = gtk_tree_model_iter_next(model, &iter); + } + + if (!match) + gtk_list_store_insert_with_values( + handle->sharing_list, + NULL, + -1, + 0, + name, + 1, + value, + 2, + FALSE, + -1 + ); + + return GNUNET_YES; +} + +static enum GNUNET_GenericReturnValue +cb_contact_info_shared_attributes(void *cls, + struct GNUNET_CHAT_Contact *contact, + const char *name, + const char *value) +{ + g_assert((cls) && (contact) && (name) && (value)); + + UI_CONTACT_INFO_Handle *handle = (UI_CONTACT_INFO_Handle*) cls; + GtkTreeModel *model = GTK_TREE_MODEL(handle->sharing_list); + GtkTreeIter iter; + + GValue val_name = G_VALUE_INIT; + GValue val_value = G_VALUE_INIT; + + gboolean valid = gtk_tree_model_get_iter_first(model, &iter); + gboolean match = FALSE; + + while (valid) + { + gtk_tree_model_get_value(model, &iter, 0, &val_name); + gtk_tree_model_get_value(model, &iter, 1, &val_value); + + if ((0 == strcmp(g_value_get_string(&val_name), name)) && + (0 == strcmp(g_value_get_string(&val_value), value))) + match = TRUE; + + g_value_unset(&val_name); + g_value_unset(&val_value); + + if (match) + break; + + valid = gtk_tree_model_iter_next(model, &iter); + } + + if (match) + gtk_list_store_set(handle->sharing_list, &iter, 2, TRUE, -1); + else + gtk_list_store_insert_with_values( + handle->sharing_list, + NULL, + -1, + 0, + name, + 1, + value, + 2, + TRUE, + -1 + ); + + return GNUNET_YES; +} + static void handle_value_renderer_edit(GtkCellRendererText *renderer, char *path, @@ -535,6 +646,52 @@ handle_attribute_value_entry_activate(UNUSED GtkEntry *entry, handle_add_attribute_button_click(handle->add_attribute_button, handle); } +static void +handle_share_renderer_toggle(GtkCellRendererToggle *renderer, + char *path, + gpointer user_data) +{ + g_assert((renderer) && (path) && (user_data)); + + UI_CONTACT_INFO_Handle *handle = (UI_CONTACT_INFO_Handle*) user_data; + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(handle->sharing_list), &iter, path)) + return; + + struct GNUNET_CHAT_Handle *chat = handle->app->chat.messenger.handle; + + if (!chat) + return; + + struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) g_object_get_qdata( + G_OBJECT(handle->sharing_tree), + handle->app->quarks.data + ); + + if ((!contact) || (GNUNET_YES == GNUNET_CHAT_contact_is_owned(contact))) + return; + + GValue value_name = G_VALUE_INIT; + GValue value_shared = G_VALUE_INIT; + + gtk_tree_model_get_value(GTK_TREE_MODEL(handle->sharing_list), &iter, 0, &value_name); + gtk_tree_model_get_value(GTK_TREE_MODEL(handle->sharing_list), &iter, 2, &value_shared); + + const gchar *name = g_value_get_string(&value_name); + const gboolean shared = g_value_get_boolean(&value_shared); + + if (shared) + GNUNET_CHAT_unshare_attribute_from(chat, contact, name); + else + GNUNET_CHAT_share_attribute_with(chat, contact, name); + + gtk_list_store_set(handle->sharing_list, &iter, 2, !shared, -1); + + g_value_unset(&value_name); + g_value_unset(&value_shared); +} + void ui_contact_info_dialog_init(MESSENGER_Application *app, UI_CONTACT_INFO_Handle *handle) @@ -609,6 +766,10 @@ ui_contact_info_dialog_init(MESSENGER_Application *app, gtk_builder_get_object(handle->builder, "list_attributes_button") ); + handle->share_attributes_button = GTK_BUTTON( + gtk_builder_get_object(handle->builder, "share_attributes_button") + ); + g_signal_connect( handle->list_attributes_button, "clicked", @@ -616,6 +777,13 @@ ui_contact_info_dialog_init(MESSENGER_Application *app, handle ); + g_signal_connect( + handle->share_attributes_button, + "clicked", + G_CALLBACK(handle_share_attributes_button_click), + handle + ); + handle->block_stack = GTK_STACK( gtk_builder_get_object(handle->builder, "block_stack") ); @@ -743,6 +911,29 @@ ui_contact_info_dialog_init(MESSENGER_Application *app, handle ); + handle->sharing_box = GTK_WIDGET( + gtk_builder_get_object(handle->builder, "sharing_box") + ); + + handle->sharing_tree = GTK_TREE_VIEW( + gtk_builder_get_object(handle->builder, "sharing_tree") + ); + + handle->sharing_list = GTK_LIST_STORE( + gtk_builder_get_object(handle->builder, "sharing_list") + ); + + handle->share_renderer = GTK_CELL_RENDERER_TOGGLE( + gtk_builder_get_object(handle->builder, "share_renderer") + ); + + g_signal_connect( + handle->share_renderer, + "toggled", + G_CALLBACK(handle_share_renderer_toggle), + handle + ); + handle->back_button = GTK_BUTTON( gtk_builder_get_object(handle->builder, "back_button") ); @@ -803,6 +994,12 @@ ui_contact_info_dialog_update(UI_CONTACT_INFO_Handle *handle, contact ); + g_object_set_qdata( + G_OBJECT(handle->sharing_tree), + handle->app->quarks.data, + contact + ); + const gboolean editable = ( (!contact) || (GNUNET_YES == GNUNET_CHAT_contact_is_owned(contact)) @@ -857,6 +1054,11 @@ ui_contact_info_dialog_update(UI_CONTACT_INFO_Handle *handle, ); gtk_widget_set_sensitive( + GTK_WIDGET(handle->share_attributes_button), + !editable + ); + + gtk_widget_set_sensitive( GTK_WIDGET(handle->block_button), !editable ); @@ -866,6 +1068,11 @@ ui_contact_info_dialog_update(UI_CONTACT_INFO_Handle *handle, !editable ); + gtk_widget_set_visible( + GTK_WIDGET(handle->share_attributes_button), + !editable + ); + gtk_stack_set_visible_child( handle->block_stack, GNUNET_YES == GNUNET_CHAT_contact_is_blocked(contact)? @@ -885,6 +1092,7 @@ ui_contact_info_dialog_update(UI_CONTACT_INFO_Handle *handle, ); gtk_list_store_clear(handle->attributes_list); + gtk_list_store_clear(handle->sharing_list); if (editable) GNUNET_CHAT_get_attributes( @@ -893,12 +1101,27 @@ ui_contact_info_dialog_update(UI_CONTACT_INFO_Handle *handle, handle ); else + { GNUNET_CHAT_contact_get_attributes( contact, cb_contact_info_contact_attributes, handle ); + GNUNET_CHAT_get_attributes( + handle->app->chat.messenger.handle, + cb_contact_info_unshared_attributes, + handle + ); + + GNUNET_CHAT_get_shared_attributes( + handle->app->chat.messenger.handle, + contact, + cb_contact_info_shared_attributes, + handle + ); + } + struct GNUNET_CHAT_Context *context = GNUNET_CHAT_contact_get_context( contact ); @@ -914,7 +1137,7 @@ ui_contact_info_dialog_update(UI_CONTACT_INFO_Handle *handle, ); if (reveal) - _contact_info_reveal_identity(handle); + _contact_info_switch_stack_to(handle, handle->identity_box); } void diff --git a/src/ui/contact_info.h b/src/ui/contact_info.h @@ -49,6 +49,7 @@ typedef struct UI_CONTACT_INFO_Handle GtkButton *reveal_identity_button; GtkButton *list_attributes_button; + GtkButton *share_attributes_button; GtkStack *block_stack; GtkButton *block_button; GtkButton *unblock_button; @@ -70,6 +71,11 @@ typedef struct UI_CONTACT_INFO_Handle GtkEntry *attribute_value_entry; GtkButton *add_attribute_button; + GtkWidget *sharing_box; + GtkTreeView *sharing_tree; + GtkListStore *sharing_list; + GtkCellRendererToggle *share_renderer; + GtkButton *back_button; GtkButton *close_button;