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:
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;