commit 2830cd336ab3db18af4905896a76806502b9ef92
parent b2d0576fb5eb5a855e61dc5678fe04ef2036ef04
Author: Jacki <jacki@thejackimonster.de>
Date: Mon, 17 Jun 2024 21:08:57 +0200
Adjust discourse dialog and fix avatar flickering
Signed-off-by: Jacki <jacki@thejackimonster.de>
Diffstat:
7 files changed, 349 insertions(+), 105 deletions(-)
diff --git a/resources/css/style.css b/resources/css/style.css
@@ -51,6 +51,20 @@
padding: 4px;
}
+.discourse-action {
+ background-color: @theme_selected_bg_color;
+ background-image: none;
+ color: @theme_selected_fg_color;
+}
+
+.success-action {
+ background-color: @success_color;
+}
+
+.error-action {
+ background-color: @error_color;
+}
+
.message-avatar {
margin: 4px;
}
diff --git a/resources/ui/discourse.ui b/resources/ui/discourse.ui
@@ -99,15 +99,30 @@ Author: Tobias Frisch
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkFlowBox" id="members_flowbox">
+ <object class="GtkScrolledWindow">
<property name="width-request">280</property>
<property name="height-request">180</property>
<property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="border-width">16</property>
- <property name="column-spacing">2</property>
- <property name="row-spacing">2</property>
- <property name="selection-mode">none</property>
+ <property name="can-focus">True</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="members_flowbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="border-width">16</property>
+ <property name="column-spacing">2</property>
+ <property name="row-spacing">2</property>
+ <property name="min-children-per-line">2</property>
+ <property name="selection-mode">none</property>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
<packing>
<property name="expand">True</property>
@@ -133,28 +148,31 @@ Author: Tobias Frisch
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
- <object class="GtkImage" id="microphone_on_icon">
+ <object class="GtkImage" id="microphone_off_icon">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="icon-name">microphone-sensitivity-high-symbolic</property>
+ <property name="icon-name">microphone-sensitivity-muted-symbolic</property>
</object>
<packing>
- <property name="name">on_page</property>
+ <property name="name">off_page</property>
</packing>
</child>
<child>
- <object class="GtkImage" id="microphone_off_icon">
+ <object class="GtkImage" id="microphone_on_icon">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="icon-name">microphone-sensitivity-muted-symbolic</property>
+ <property name="icon-name">microphone-sensitivity-high-symbolic</property>
</object>
<packing>
- <property name="name">off_page</property>
+ <property name="name">on_page</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
+ <style>
+ <class name="discourse-action"/>
+ </style>
</object>
<packing>
<property name="expand">False</property>
@@ -175,6 +193,9 @@ Author: Tobias Frisch
<property name="icon-name">camera-web-symbolic</property>
</object>
</child>
+ <style>
+ <class name="discourse-action"/>
+ </style>
</object>
<packing>
<property name="expand">False</property>
@@ -195,6 +216,9 @@ Author: Tobias Frisch
<property name="icon-name">video-display-symbolic</property>
</object>
</child>
+ <style>
+ <class name="discourse-action"/>
+ </style>
</object>
<packing>
<property name="expand">False</property>
@@ -232,6 +256,9 @@ audio-volume-medium-symbolic</property>
<property name="relief">none</property>
</object>
</child>
+ <style>
+ <class name="discourse-action"/>
+ </style>
</object>
<packing>
<property name="expand">False</property>
@@ -240,43 +267,59 @@ audio-volume-medium-symbolic</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="call_button">
+ <object class="GtkStack" id="call_stack">
<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>
<child>
- <object class="GtkStack" id="call_stack">
+ <object class="GtkButton" id="call_stop_button">
<property name="visible">True</property>
- <property name="can-focus">False</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
<child>
- <object class="GtkImage" id="call_start_icon">
+ <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="icon-name">call-start-symbolic</property>
+ <property name="icon-name">call-stop-symbolic</property>
</object>
- <packing>
- <property name="name">start_page</property>
- </packing>
</child>
+ <style>
+ <class name="discourse-action"/>
+ <class name="error-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">stop_page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="call_start_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
<child>
- <object class="GtkImage" id="call_stop_icon">
+ <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="icon-name">call-stop-symbolic</property>
+ <property name="icon-name">call-start-symbolic</property>
</object>
- <packing>
- <property name="name">stop_page</property>
- <property name="position">1</property>
- </packing>
</child>
+ <style>
+ <class name="discourse-action"/>
+ <class name="success-action"/>
+ </style>
</object>
+ <packing>
+ <property name="name">page0</property>
+ <property name="title" translatable="yes">page0</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">5</property>
+ <property name="position">4</property>
</packing>
</child>
</object>
diff --git a/resources/ui/discourse_panel.ui b/resources/ui/discourse_panel.ui
@@ -33,7 +33,7 @@ Author: Tobias Frisch
<property name="can-focus">False</property>
<child>
<object class="GtkBox" id="avatar_box">
- <property name="width-request">140</property>
+ <property name="width-request">124</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">8</property>
diff --git a/src/ui.c b/src/ui.c
@@ -245,3 +245,61 @@ ui_avatar_set_icon(HdyAvatar *avatar,
else
hdy_avatar_set_loadable_icon(avatar, G_LOADABLE_ICON(icon));
}
+
+gboolean
+ui_find_qdata_in_container(GtkContainer *container,
+ GQuark quark,
+ const gpointer data)
+{
+ g_assert((container) && (data));
+
+ GList* children = gtk_container_get_children(container);
+ GList *item = children;
+
+ while (item)
+ {
+ GtkWidget *widget = GTK_WIDGET(item->data);
+
+ if (data == g_object_get_qdata(G_OBJECT(widget), quark))
+ break;
+
+ item = item->next;
+ }
+
+ if (children)
+ g_list_free(children);
+
+ return item? TRUE : FALSE;
+}
+
+void
+ui_clear_container_of_missing_qdata(GtkContainer *container,
+ GQuark quark,
+ const GList *list)
+{
+ g_assert(container);
+
+ GList* children = gtk_container_get_children(container);
+ GList *item = children;
+
+ while (item) {
+ GtkWidget *widget = GTK_WIDGET(item->data);
+ const GList *data = list;
+
+ while (data)
+ {
+ if (data->data == g_object_get_qdata(G_OBJECT(widget), quark))
+ break;
+
+ data = data->next;
+ }
+
+ if (!data)
+ gtk_container_remove(container, widget);
+
+ item = item->next;
+ }
+
+ if (children)
+ g_list_free(children);
+}
diff --git a/src/ui.h b/src/ui.h
@@ -114,4 +114,30 @@ void
ui_avatar_set_icon(HdyAvatar *avatar,
GIcon *icon);
+/**
+ * Searches for a specific data set as qdata inside a
+ * container.
+ *
+ * @param container Container
+ * @param quark Quark
+ * @param data Data
+ */
+gboolean
+ui_find_qdata_in_container(GtkContainer *container,
+ GQuark quark,
+ const gpointer data);
+
+/**
+ * Removes children from container which qdata is missing
+ * inside a list of data.
+ *
+ * @param container Container
+ * @param quark Quark
+ * @param list List of data
+ */
+void
+ui_clear_container_of_missing_qdata(GtkContainer *container,
+ GQuark quark,
+ const GList *list);
+
#endif /* UI_H_ */
diff --git a/src/ui/discourse.c b/src/ui/discourse.c
@@ -34,10 +34,24 @@
#include "../application.h"
#include "../ui.h"
#include "../util.h"
-#include <gnunet/gnunet_chat_lib.h>
-#include <gnunet/gnunet_common.h>
+
#include <string.h>
+static const struct GNUNET_ShortHashCode*
+get_voice_discourse_id()
+{
+ static enum GNUNET_GenericReturnValue init = GNUNET_NO;
+ static struct GNUNET_ShortHashCode id;
+
+ if (GNUNET_YES != init)
+ {
+ memset(&id, 0, sizeof(id));
+ init = GNUNET_YES;
+ }
+
+ return &id;
+}
+
static void
handle_back_button_click(UNUSED GtkButton *button,
gpointer user_data)
@@ -101,8 +115,20 @@ handle_microphone_button_click(UNUSED GtkButton *button,
}
static void
-handle_call_button_click(UNUSED GtkButton *button,
- gpointer user_data)
+_update_call_button(UI_DISCOURSE_Handle *handle)
+{
+ g_assert(handle);
+
+ if ((handle->voice_discourse) &&
+ (GNUNET_YES ==GNUNET_CHAT_discourse_is_open(handle->voice_discourse)))
+ gtk_stack_set_visible_child(handle->call_stack, handle->call_stop_button);
+ else
+ gtk_stack_set_visible_child(handle->call_stack, handle->call_start_button);
+}
+
+static void
+handle_call_start_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
{
g_assert(user_data);
@@ -111,25 +137,28 @@ handle_call_button_click(UNUSED GtkButton *button,
if (!(handle->context))
return;
- const gboolean calling = (handle->voice_discourse? TRUE : FALSE);
+ handle->voice_discourse = GNUNET_CHAT_context_open_discourse(
+ handle->context, get_voice_discourse_id()
+ );
- struct GNUNET_ShortHashCode voice_id;
- memset(&voice_id, 0, sizeof(voice_id));
+ _update_call_button(handle);
+}
- if (calling)
- {
- GNUNET_CHAT_discourse_close(handle->voice_discourse);
- handle->voice_discourse = NULL;
- }
- else
- handle->voice_discourse = GNUNET_CHAT_context_open_discourse(
- handle->context, &voice_id
- );
+static void
+handle_call_stop_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
- if (handle->voice_discourse)
- gtk_stack_set_visible_child(handle->call_stack, handle->call_stop_icon);
- else
- gtk_stack_set_visible_child(handle->call_stack, handle->call_start_icon);
+ UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) user_data;
+
+ if ((!(handle->context)) || (!(handle->voice_discourse)))
+ return;
+
+ GNUNET_CHAT_discourse_close(handle->voice_discourse);
+ handle->voice_discourse = NULL;
+
+ _update_call_button(handle);
}
static void
@@ -237,17 +266,6 @@ ui_discourse_window_init(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "speakers_button")
);
- handle->call_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "call_button")
- );
-
- g_signal_connect(
- handle->call_button,
- "clicked",
- G_CALLBACK(handle_call_button_click),
- handle
- );
-
handle->microphone_stack = GTK_STACK(
gtk_builder_get_object(handle->builder, "microphone_stack")
);
@@ -264,12 +282,26 @@ ui_discourse_window_init(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "call_stack")
);
- handle->call_start_icon = GTK_WIDGET(
- gtk_builder_get_object(handle->builder, "call_start_icon")
+ handle->call_start_button = GTK_WIDGET(
+ gtk_builder_get_object(handle->builder, "call_start_button")
+ );
+
+ g_signal_connect(
+ handle->call_start_button,
+ "clicked",
+ G_CALLBACK(handle_call_start_button_click),
+ handle
);
- handle->call_stop_icon = GTK_WIDGET(
- gtk_builder_get_object(handle->builder, "call_stop_icon")
+ handle->call_stop_button = GTK_WIDGET(
+ gtk_builder_get_object(handle->builder, "call_stop_button")
+ );
+
+ g_signal_connect(
+ handle->call_stop_button,
+ "clicked",
+ G_CALLBACK(handle_call_stop_button_click),
+ handle
);
handle->close_details_button = GTK_BUTTON(
@@ -297,6 +329,46 @@ ui_discourse_window_init(MESSENGER_Application *app,
gtk_widget_show_all(GTK_WIDGET(handle->window));
}
+static enum GNUNET_GenericReturnValue
+append_discourse_members_to_list(void *cls,
+ UNUSED const struct GNUNET_CHAT_Discourse *discourse,
+ struct GNUNET_CHAT_Contact *contact)
+{
+ g_assert((cls) && (contact));
+
+ GList **list = (GList**) cls;
+ *list = g_list_append(*list, contact);
+ return GNUNET_YES;
+}
+
+static enum GNUNET_GenericReturnValue
+append_discourses_members(void *cls,
+ UNUSED struct GNUNET_CHAT_Context *context,
+ struct GNUNET_CHAT_Discourse *discourse)
+{
+ g_assert((cls) && (discourse));
+
+ GNUNET_CHAT_discourse_iterate_contacts(
+ discourse,
+ append_discourse_members_to_list,
+ cls
+ );
+
+ return GNUNET_YES;
+}
+
+static enum GNUNET_GenericReturnValue
+append_group_contacts(void *cls,
+ UNUSED const struct GNUNET_CHAT_Group *group,
+ struct GNUNET_CHAT_Contact *contact)
+{
+ g_assert((cls) && (contact));
+
+ GList **list = (GList**) cls;
+ *list = g_list_append(*list, contact);
+ return GNUNET_YES;
+}
+
struct IterateDiscourseClosure {
MESSENGER_Application *app;
GtkContainer *container;
@@ -311,9 +383,12 @@ iterate_ui_discourse_update_discourse_members(void *cls,
(struct IterateDiscourseClosure*) cls
);
+ if (ui_find_qdata_in_container(closure->container, closure->app->quarks.data, contact))
+ return GNUNET_YES;
+
GtkFlowBox *flowbox = GTK_FLOW_BOX(closure->container);
- UI_DISCOURSE_PANEL_Handle* panel = ui_discourse_panel_new(closure->app);
+ UI_DISCOURSE_PANEL_Handle* panel = ui_discourse_panel_new(closure->app);
ui_discourse_panel_set_contact(panel, contact);
gtk_flow_box_insert(flowbox, panel->panel_box, -1);
@@ -354,23 +429,21 @@ _discourse_update_members(UI_DISCOURSE_Handle *handle)
{
g_assert(handle);
- GList* children = gtk_container_get_children(
- GTK_CONTAINER(handle->members_flowbox)
+ GList *list = NULL;
+ GNUNET_CHAT_context_iterate_discourses(
+ handle->context,
+ append_discourses_members,
+ &list
+ );
+
+ ui_clear_container_of_missing_qdata(
+ GTK_CONTAINER(handle->members_flowbox),
+ handle->app->quarks.data,
+ list
);
- GList *item = children;
- while ((item) && (item->next)) {
- GtkWidget *widget = GTK_WIDGET(item->data);
- item = item->next;
-
- gtk_container_remove(
- GTK_CONTAINER(handle->members_flowbox),
- widget
- );
- }
-
- if (children)
- g_list_free(children);
+ if (list)
+ g_list_free(list);
if (!(handle->context))
return;
@@ -395,6 +468,9 @@ iterate_ui_discourse_update_group_contacts(void *cls,
(struct IterateDiscourseClosure*) cls
);
+ if (ui_find_qdata_in_container(closure->container, closure->app->quarks.data, contact))
+ return GNUNET_YES;
+
GtkListBox *listbox = GTK_LIST_BOX(closure->container);
UI_ACCOUNT_ENTRY_Handle* entry = ui_account_entry_new(closure->app);
@@ -423,23 +499,22 @@ _discourse_update_contacts(UI_DISCOURSE_Handle *handle,
{
g_assert((handle) && (handle->app));
- GList* children = gtk_container_get_children(
- GTK_CONTAINER(handle->contacts_listbox)
- );
-
- GList *item = children;
- while ((item) && (item->next)) {
- GtkWidget *widget = GTK_WIDGET(item->data);
- item = item->next;
-
- gtk_container_remove(
- GTK_CONTAINER(handle->contacts_listbox),
- widget
+ GList *list = NULL;
+ if (group)
+ GNUNET_CHAT_group_iterate_contacts(
+ group,
+ append_group_contacts,
+ &list
);
- }
+
+ ui_clear_container_of_missing_qdata(
+ GTK_CONTAINER(handle->contacts_listbox),
+ handle->app->quarks.data,
+ list
+ );
- if (children)
- g_list_free(children);
+ if (list)
+ g_list_free(list);
if (group)
{
@@ -460,19 +535,48 @@ _discourse_update_contacts(UI_DISCOURSE_Handle *handle,
);
}
+static enum GNUNET_GenericReturnValue
+iterate_ui_discourse_search_context_discourses(void *cls,
+ struct GNUNET_CHAT_Context *context,
+ struct GNUNET_CHAT_Discourse *discourse)
+{
+ g_assert((cls) && (context) && (discourse));
+
+ UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) cls;
+
+ if (0 == GNUNET_memcmp(GNUNET_CHAT_discourse_get_id(discourse), get_voice_discourse_id()))
+ handle->voice_discourse = discourse;
+
+ return GNUNET_YES;
+}
+
+static void
+_update_discourse_via_context(UI_DISCOURSE_Handle *handle)
+{
+ g_assert(handle);
+
+ handle->voice_discourse = NULL;
+
+ if (!(handle->context))
+ return;
+
+ GNUNET_CHAT_context_iterate_discourses(
+ handle->context,
+ iterate_ui_discourse_search_context_discourses,
+ handle
+ );
+}
+
void
ui_discourse_window_update(UI_DISCOURSE_Handle *handle,
struct GNUNET_CHAT_Context *context)
{
g_assert(handle);
- if (handle->context)
- {
- // TODO
- }
-
handle->context = context;
+ _update_discourse_via_context(handle);
+ _update_call_button(handle);
_update_microphone_icon(handle);
_discourse_update_members(handle);
diff --git a/src/ui/discourse.h b/src/ui/discourse.h
@@ -59,15 +59,14 @@ typedef struct UI_DISCOURSE_Handle
GtkButton *camera_button;
GtkButton *screen_button;
GtkVolumeButton *speakers_button;
- GtkButton *call_button;
GtkStack *microphone_stack;
GtkWidget *microphone_on_icon;
GtkWidget *microphone_off_icon;
GtkStack *call_stack;
- GtkWidget *call_start_icon;
- GtkWidget *call_stop_icon;
+ GtkWidget *call_start_button;
+ GtkWidget *call_stop_button;
GtkButton *close_details_button;
GtkListBox *contacts_listbox;