commit 0518055b9f4b773eb4097623abfed8e791216945
parent 310a225cf85a371d1243c8667991cf86b467316f
Author: Jacki <jacki@thejackimonster.de>
Date: Wed, 13 Mar 2024 16:57:37 +0100
Implement adding and removing tags on messages with flow boxes
Signed-off-by: Jacki <jacki@thejackimonster.de>
Diffstat:
7 files changed, 258 insertions(+), 49 deletions(-)
diff --git a/resources/ui/chat.ui b/resources/ui/chat.ui
@@ -307,6 +307,7 @@ Author: Tobias Frisch
<object class="GtkScrolledWindow" id="chat_scrolled_window">
<property name="visible">True</property>
<property name="can-focus">True</property>
+ <property name="hscrollbar-policy">never</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
diff --git a/resources/ui/message-sent.ui b/resources/ui/message-sent.ui
@@ -55,6 +55,23 @@ Author: Tobias Frisch
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
+ <object class="GtkFlowBox" id="tag_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="column-spacing">2</property>
+ <property name="min-children-per-line">1</property>
+ <property name="max-children-per-line">5</property>
+ <property name="selection-mode">none</property>
+ <property name="activate-on-single-click">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
<placeholder/>
</child>
</object>
diff --git a/resources/ui/message-status.ui b/resources/ui/message-status.ui
@@ -37,79 +37,108 @@ Author: Tobias Frisch
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="spacing">8</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkRevealer" id="deny_revealer">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="transition-type">slide-left</property>
+ <property name="spacing">8</property>
<child>
- <object class="GtkButton" id="deny_button">
+ <object class="GtkRevealer" id="deny_revealer">
<property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="receives-default">True</property>
- <property name="relief">none</property>
+ <property name="can-focus">False</property>
+ <property name="transition-type">slide-left</property>
<child>
- <object class="GtkImage">
+ <object class="GtkButton" id="deny_button">
<property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="icon-name">edit-delete-symbolic</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">edit-delete-symbolic</property>
+ </object>
+ </child>
</object>
</child>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="content_box">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="orientation">vertical</property>
<child>
- <placeholder/>
+ <object class="GtkBox" id="content_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkRevealer" id="accept_revealer">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="transition-type">slide-right</property>
<child>
- <object class="GtkButton" id="accept_button">
+ <object class="GtkRevealer" id="accept_revealer">
<property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="receives-default">True</property>
- <property name="relief">none</property>
+ <property name="can-focus">False</property>
+ <property name="transition-type">slide-right</property>
<child>
- <object class="GtkImage">
+ <object class="GtkButton" id="accept_button">
<property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="icon-name">emblem-ok-symbolic</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">emblem-ok-symbolic</property>
+ </object>
+ </child>
</object>
</child>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
</child>
+ <style>
+ <class name="message-content"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFlowBox" id="tag_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="column-spacing">2</property>
+ <property name="min-children-per-line">1</property>
+ <property name="max-children-per-line">5</property>
+ <property name="selection-mode">none</property>
+ <property name="activate-on-single-click">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
</packing>
</child>
- <style>
- <class name="message-content"/>
- </style>
</object>
</child>
<child type="label">
diff --git a/resources/ui/message.ui b/resources/ui/message.ui
@@ -56,6 +56,22 @@ Author: Tobias Frisch
<child>
<placeholder/>
</child>
+ <child>
+ <object class="GtkFlowBox" id="tag_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="column-spacing">2</property>
+ <property name="max-children-per-line">5</property>
+ <property name="selection-mode">none</property>
+ <property name="activate-on-single-click">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
</child>
<child type="label">
diff --git a/src/event.c b/src/event.c
@@ -763,7 +763,9 @@ skip_message:
}
static void
-_event_update_tag_message_state(const struct GNUNET_CHAT_Message *msg)
+_event_update_tag_message_state(MESSENGER_Application *app,
+ struct GNUNET_CHAT_Context *context,
+ const struct GNUNET_CHAT_Message *msg)
{
g_assert((msg) && (GNUNET_CHAT_KIND_TAG == GNUNET_CHAT_message_get_kind(msg)));
@@ -778,6 +780,35 @@ _event_update_tag_message_state(const struct GNUNET_CHAT_Message *msg)
if (contact)
contact_update_info(contact);
+
+ UI_CHAT_ENTRY_Handle *handle = GNUNET_CHAT_context_get_user_pointer(context);
+
+ if ((!handle) || (!(handle->chat)))
+ return;
+
+ GList *rows = gtk_container_get_children(
+ GTK_CONTAINER(handle->chat->messages_listbox)
+ );
+
+ for (GList *row = rows; row; row = row->next)
+ {
+ UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) g_object_get_qdata(
+ G_OBJECT(row->data), app->quarks.ui
+ );
+
+ if ((message) && (message->msg == target))
+ {
+ if (GNUNET_YES == GNUNET_CHAT_message_is_deleted(msg))
+ ui_message_remove_tag(message, app, msg);
+ else
+ ui_message_add_tag(message, app, msg);
+
+ break;
+ }
+ }
+
+ if (rows)
+ g_list_free(rows);
}
void
@@ -813,7 +844,7 @@ event_delete_message(MESSENGER_Application *app,
g_list_free(rows);
if (GNUNET_CHAT_KIND_TAG == GNUNET_CHAT_message_get_kind(msg))
- _event_update_tag_message_state(msg);
+ _event_update_tag_message_state(app, context, msg);
enqueue_chat_entry_update(handle);
}
@@ -829,7 +860,7 @@ event_tag_message(MESSENGER_Application *app,
const struct GNUNET_CHAT_Message *target = GNUNET_CHAT_message_get_target(msg);
- _event_update_tag_message_state(msg);
+ _event_update_tag_message_state(app, context, msg);
if ((!handle) || (!(handle->chat)))
return;
diff --git a/src/ui/message.c b/src/ui/message.c
@@ -375,6 +375,10 @@ ui_message_new(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder[0], "content_box")
);
+ handle->tag_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder[0], "tag_flow_box")
+ );
+
handle->builder[1] = gtk_builder_new_from_resource(
application_get_resource_path(app, "ui/message_content.ui")
);
@@ -780,6 +784,90 @@ ui_message_set_contact(UI_MESSAGE_Handle *handle,
}
void
+ui_message_add_tag(UI_MESSAGE_Handle *handle,
+ MESSENGER_Application *app,
+ const struct GNUNET_CHAT_Message *tag_message)
+{
+ g_assert((handle) && (app) && (tag_message));
+
+ if ((GNUNET_CHAT_KIND_TAG != GNUNET_CHAT_message_get_kind(tag_message)) ||
+ (GNUNET_CHAT_message_get_target(tag_message) != handle->msg))
+ return;
+
+ const char *tag_value = GNUNET_CHAT_message_get_text(tag_message);
+
+ if ((!tag_value) || (!tag_value[0]))
+ return;
+
+ GtkLabel *tag_label = GTK_LABEL(gtk_label_new(NULL));
+
+ if (!tag_label)
+ return;
+
+ ui_label_set_text(tag_label, tag_value);
+ gtk_label_set_ellipsize(tag_label, PANGO_ELLIPSIZE_END);
+
+ g_object_set_qdata(G_OBJECT(tag_label), app->quarks.data, (gpointer) tag_message);
+
+ gtk_container_add(GTK_CONTAINER(handle->tag_flow_box), GTK_WIDGET(tag_label));
+ gtk_widget_show_all(GTK_WIDGET(tag_label));
+}
+
+void
+ui_message_remove_tag(UI_MESSAGE_Handle *handle,
+ MESSENGER_Application *app,
+ const struct GNUNET_CHAT_Message *tag_message)
+{
+ g_assert((handle) && (app) && (tag_message));
+
+ if ((GNUNET_CHAT_KIND_TAG != GNUNET_CHAT_message_get_kind(tag_message)) ||
+ (GNUNET_CHAT_message_get_target(tag_message) != handle->msg))
+ return;
+
+ GList *children = gtk_container_get_children(GTK_CONTAINER(handle->tag_flow_box));
+
+ if (!children)
+ return;
+
+ GtkWidget *removable = NULL;
+
+ GList *list = children;
+ while (list)
+ {
+ GtkFlowBoxChild *child = GTK_FLOW_BOX_CHILD(list->data);
+ GList *items = gtk_container_get_children(GTK_CONTAINER(child));
+
+ if (items)
+ {
+ GtkLabel *tag_label = GTK_LABEL(items->data);
+
+ const struct GNUNET_CHAT_Message *msg = g_object_get_qdata(
+ G_OBJECT(tag_label),
+ app->quarks.data
+ );
+
+ if (tag_message == msg)
+ removable = GTK_WIDGET(child);
+
+ g_list_free(items);
+ }
+
+ list = list->next;
+
+ if (removable)
+ break;
+ }
+
+ g_list_free(children);
+
+ if (!removable)
+ return;
+
+ gtk_container_remove(GTK_CONTAINER(handle->tag_flow_box), removable);
+ gtk_widget_destroy(removable);
+}
+
+void
ui_message_delete(UI_MESSAGE_Handle *handle)
{
g_assert(handle);
diff --git a/src/ui/message.h b/src/ui/message.h
@@ -51,6 +51,7 @@ typedef struct UI_MESSAGE_Handle
GtkBuilder *builder [2];
GtkWidget *message_box;
+ GtkFlowBox *tag_flow_box;
HdyAvatar *sender_avatar;
GtkLabel *sender_label;
@@ -138,6 +139,32 @@ ui_message_set_contact(UI_MESSAGE_Handle *handle,
const struct GNUNET_CHAT_Contact *contact);
/**
+ * Adds a widget to represent a given tag message
+ * to another message handle.
+ *
+ * @param handle Message handle
+ * @param app Messenger application
+ * @param tag_message Chat tag message
+ */
+void
+ui_message_add_tag(UI_MESSAGE_Handle *handle,
+ MESSENGER_Application *app,
+ const struct GNUNET_CHAT_Message *tag_message);
+
+/**
+ * Remove a widget representing a given tag message
+ * from another message handle.
+ *
+ * @param handle Message handle
+ * @param app Messenger application
+ * @param tag_message Chat tag message
+ */
+void
+ui_message_remove_tag(UI_MESSAGE_Handle *handle,
+ MESSENGER_Application *app,
+ const struct GNUNET_CHAT_Message *tag_message);
+
+/**
* Frees its resources and destroys a given
* message handle.
*