commit 11bef15928c414e2a26e8e4b63104dd684bf60f2
parent 3b7003ea0cf2f53311e268a773f5f3b23d70e23e
Author: Jacki <jacki@thejackimonster.de>
Date: Sat, 15 Jun 2024 20:26:53 +0200
Implement discourse dialog opening via button from chat details
Signed-off-by: Jacki <jacki@thejackimonster.de>
Diffstat:
7 files changed, 505 insertions(+), 36 deletions(-)
diff --git a/resources/ui/discourse.ui b/resources/ui/discourse.ui
@@ -99,7 +99,7 @@ Author: Tobias Frisch
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkFlowBox">
+ <object class="GtkFlowBox" id="members_flowbox">
<property name="width-request">280</property>
<property name="height-request">180</property>
<property name="visible">True</property>
@@ -205,38 +205,33 @@ Author: Tobias Frisch
</packing>
</child>
<child>
- <object class="GtkButton" id="speakers_button">
+ <object class="GtkVolumeButton" id="speakers_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
+ <property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="relief">none</property>
- <child>
- <object class="GtkStack">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <child>
- <object class="GtkImage" id="speakers_on_icon">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="icon-name">audio-volume-high-symbolic</property>
- </object>
- <packing>
- <property name="name">page0</property>
- <property name="title" translatable="yes">page0</property>
- </packing>
- </child>
- <child>
- <object class="GtkImage" id="speakers_off_icon">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="icon-name">audio-volume-muted-symbolic</property>
- </object>
- <packing>
- <property name="name">page1</property>
- <property name="title" translatable="yes">page1</property>
- <property name="position">1</property>
- </packing>
- </child>
+ <property name="orientation">vertical</property>
+ <property name="icons">audio-volume-muted-symbolic
+audio-volume-high-symbolic
+audio-volume-low-symbolic
+audio-volume-medium-symbolic</property>
+ <child internal-child="plus_button">
+ <object class="GtkButton">
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="relief">none</property>
+ </object>
+ </child>
+ <child internal-child="minus_button">
+ <object class="GtkButton">
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="relief">none</property>
</object>
</child>
</object>
@@ -285,7 +280,7 @@ Author: Tobias Frisch
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">4</property>
+ <property name="position">5</property>
</packing>
</child>
</object>
@@ -311,6 +306,56 @@ Author: Tobias Frisch
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Contacts</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close_details_button">
+ <property name="visible">True</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">window-close</property>
+ </object>
+ </child>
+ </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>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkScrolledWindow">
<property name="width-request">240</property>
<property name="visible">True</property>
@@ -324,6 +369,7 @@ Author: Tobias Frisch
<object class="GtkListBox" id="contacts_listbox">
<property name="visible">True</property>
<property name="can-focus">False</property>
+ <property name="selection-mode">none</property>
</object>
</child>
</object>
@@ -332,7 +378,7 @@ Author: Tobias Frisch
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">0</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
diff --git a/src/application.h b/src/application.h
@@ -41,6 +41,7 @@
#include "ui/contact_info.h"
#include "ui/contacts.h"
#include "ui/delete_messages.h"
+#include "ui/discourse.h"
#include "ui/files.h"
#include "ui/invite_contact.h"
#include "ui/messenger.h"
@@ -122,6 +123,7 @@ typedef struct MESSENGER_Application
UI_CONTACT_INFO_Handle contact_info;
UI_DELETE_MESSAGES_Handle delete_messages;
+ UI_DISCOURSE_Handle discourse;
UI_INVITE_CONTACT_Handle invite_contact;
UI_SEND_FILE_Handle send_file;
UI_PLAY_MEDIA_Handle play_media;
diff --git a/src/ui/chat.c b/src/ui/chat.c
@@ -221,6 +221,23 @@ handle_reveal_identity_button_click(GtkButton *button,
}
static void
+handle_discourse_button_click(GtkButton *button,
+ gpointer user_data)
+{
+ g_assert((button) && (user_data));
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+ MESSENGER_Application *app = handle->app;
+
+ hdy_flap_set_reveal_flap(handle->flap_chat_details, FALSE);
+
+ ui_discourse_window_init(app, &(app->ui.discourse));
+ ui_discourse_window_update(&(app->ui.discourse), handle->context);
+
+ gtk_widget_show(GTK_WIDGET(app->ui.discourse.window));
+}
+
+static void
handle_block_button_click(UNUSED GtkButton *button,
gpointer user_data)
{
@@ -1285,6 +1302,13 @@ ui_chat_new(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "discourse_button")
);
+ g_signal_connect(
+ handle->discourse_button,
+ "clicked",
+ G_CALLBACK(handle_discourse_button_click),
+ handle
+ );
+
handle->block_stack = GTK_STACK(
gtk_builder_get_object(handle->builder, "block_stack")
);
diff --git a/src/ui/chat_title.c b/src/ui/chat_title.c
@@ -56,11 +56,7 @@ _flap_chat_details_reveal_switch(gpointer user_data)
UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
HdyFlap* flap = handle->flap_chat_details;
- if (TRUE == hdy_flap_get_reveal_flap(flap)) {
- hdy_flap_set_reveal_flap(flap, FALSE);
- } else {
- hdy_flap_set_reveal_flap(flap, TRUE);
- }
+ hdy_flap_set_reveal_flap(flap, !hdy_flap_get_reveal_flap(flap));
gtk_widget_set_sensitive(GTK_WIDGET(handle->messages_listbox), TRUE);
return FALSE;
diff --git a/src/ui/discourse.c b/src/ui/discourse.c
@@ -0,0 +1,307 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2024 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
+/*
+ * @author Tobias Frisch
+ * @file ui/discourse.c
+ */
+
+#include "discourse.h"
+
+#include "account_entry.h"
+
+#include "../application.h"
+#include "../ui.h"
+#include "../util.h"
+
+static void
+handle_back_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ GtkWindow *window = GTK_WINDOW(user_data);
+ gtk_window_close(window);
+}
+
+static void
+handle_details_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ HdyFlap *flap = HDY_FLAP(user_data);
+
+ hdy_flap_set_reveal_flap(flap, !hdy_flap_get_reveal_flap(flap));
+}
+
+static void
+handle_details_folded(GObject* object,
+ GParamSpec* pspec,
+ gpointer user_data)
+{
+ g_assert((object) && (pspec) && (user_data));
+
+ HdyFlap* flap = HDY_FLAP(object);
+ UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) user_data;
+
+ const gboolean revealed = hdy_flap_get_reveal_flap(flap);
+
+ gtk_widget_set_sensitive(
+ GTK_WIDGET(handle->back_button),
+ !revealed
+ );
+}
+
+static void
+handle_window_destroy(UNUSED GtkWidget *window,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ ui_discourse_window_cleanup((UI_DISCOURSE_Handle*) user_data);
+}
+
+void
+ui_discourse_window_init(MESSENGER_Application *app,
+ UI_DISCOURSE_Handle *handle)
+{
+ g_assert((app) && (handle));
+
+ handle->app = app;
+ handle->context = NULL;
+
+ handle->parent = GTK_WINDOW(app->ui.messenger.main_window);
+
+ handle->builder = ui_builder_from_resource(
+ application_get_resource_path(app, "ui/discourse.ui")
+ );
+
+ handle->window = HDY_WINDOW(
+ gtk_builder_get_object(handle->builder, "discourse_window")
+ );
+
+ gtk_window_set_position(
+ GTK_WINDOW(handle->window),
+ GTK_WIN_POS_CENTER_ON_PARENT
+ );
+
+ gtk_window_set_transient_for(
+ GTK_WINDOW(handle->window),
+ handle->parent
+ );
+
+ handle->title_bar = HDY_HEADER_BAR(
+ gtk_builder_get_object(handle->builder, "title_bar")
+ );
+
+ handle->back_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "back_button")
+ );
+
+ g_signal_connect(
+ handle->back_button,
+ "clicked",
+ G_CALLBACK(handle_back_button_click),
+ handle->window
+ );
+
+ handle->details_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "details_button")
+ );
+
+ handle->details_flap = HDY_FLAP(
+ gtk_builder_get_object(handle->builder, "details_flap")
+ );
+
+ g_signal_connect(
+ handle->details_button,
+ "clicked",
+ G_CALLBACK(handle_details_button_click),
+ handle->details_flap
+ );
+
+ g_signal_connect(
+ handle->details_flap,
+ "notify::reveal-flap",
+ G_CALLBACK(handle_details_folded),
+ handle
+ );
+
+ handle->members_flowbox = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "members_flowbox")
+ );
+
+ handle->microphone_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "microphone_button")
+ );
+
+ handle->camera_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "camera_button")
+ );
+
+ handle->screen_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "screen_button")
+ );
+
+ handle->speakers_button = GTK_VOLUME_BUTTON(
+ gtk_builder_get_object(handle->builder, "speakers_button")
+ );
+
+ handle->call_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "call_button")
+ );
+
+ handle->close_details_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "close_details_button")
+ );
+
+ g_signal_connect(
+ handle->close_details_button,
+ "clicked",
+ G_CALLBACK(handle_details_button_click),
+ handle->details_flap
+ );
+
+ handle->contacts_listbox = GTK_LIST_BOX(
+ gtk_builder_get_object(handle->builder, "contacts_listbox")
+ );
+
+ g_signal_connect(
+ handle->window,
+ "destroy",
+ G_CALLBACK(handle_window_destroy),
+ handle
+ );
+
+ gtk_widget_show_all(GTK_WIDGET(handle->window));
+}
+
+struct IterateChatClosure {
+ MESSENGER_Application *app;
+ GtkContainer *container;
+};
+
+static enum GNUNET_GenericReturnValue
+iterate_ui_discourse_update_group_contacts(void *cls,
+ UNUSED const struct GNUNET_CHAT_Group *group,
+ struct GNUNET_CHAT_Contact *contact)
+{
+ struct IterateChatClosure *closure = (
+ (struct IterateChatClosure*) cls
+ );
+
+ GtkListBox *listbox = GTK_LIST_BOX(closure->container);
+ UI_ACCOUNT_ENTRY_Handle* entry = ui_account_entry_new(closure->app);
+
+ ui_account_entry_set_contact(entry, contact);
+
+ gtk_list_box_prepend(listbox, entry->entry_box);
+
+ GtkListBoxRow *row = GTK_LIST_BOX_ROW(
+ gtk_widget_get_parent(entry->entry_box)
+ );
+
+ g_object_set_qdata(G_OBJECT(row), closure->app->quarks.data, contact);
+ g_object_set_qdata_full(
+ G_OBJECT(row),
+ closure->app->quarks.ui,
+ entry,
+ (GDestroyNotify) ui_account_entry_delete
+ );
+
+ return GNUNET_YES;
+}
+
+static void
+_discourse_update_contacts(UI_DISCOURSE_Handle *handle,
+ struct GNUNET_CHAT_Group* group)
+{
+ 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
+ );
+ }
+
+ if (children)
+ g_list_free(children);
+
+ if (group)
+ {
+ struct IterateChatClosure closure;
+ closure.app = handle->app;
+ closure.container = GTK_CONTAINER(handle->contacts_listbox);
+
+ GNUNET_CHAT_group_iterate_contacts(
+ group,
+ iterate_ui_discourse_update_group_contacts,
+ &closure
+ );
+ }
+
+ gtk_widget_set_visible(
+ GTK_WIDGET(handle->details_button),
+ group? TRUE : FALSE
+ );
+}
+
+void
+ui_discourse_window_update(UI_DISCOURSE_Handle *handle,
+ struct GNUNET_CHAT_Context *context)
+{
+ g_assert(handle);
+
+ if (handle->context)
+ {
+ // TODO
+
+
+ }
+
+ handle->context = context;
+
+ struct GNUNET_CHAT_Group* group = GNUNET_CHAT_context_get_group(
+ handle->context
+ );
+
+ _discourse_update_contacts(handle, group);
+}
+
+void
+ui_discourse_window_cleanup(UI_DISCOURSE_Handle *handle)
+{
+ g_assert(handle);
+
+ ui_discourse_window_update(handle, NULL);
+
+ g_object_unref(handle->builder);
+
+ memset(handle, 0, sizeof(*handle));
+}
diff --git a/src/ui/discourse.h b/src/ui/discourse.h
@@ -0,0 +1,93 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2024 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
+/*
+ * @author Tobias Frisch
+ * @file ui/discourse.h
+ */
+
+#ifndef UI_DISCOURSE_H_
+#define UI_DISCOURSE_H_
+
+#include "messenger.h"
+
+#include <glib-2.0/glib.h>
+#include <gstreamer-1.0/gst/gst.h>
+#include <pthread.h>
+
+typedef struct UI_DISCOURSE_Handle
+{
+ MESSENGER_Application *app;
+ struct GNUNET_CHAT_Context *context;
+
+ GtkWindow *parent;
+
+ GtkBuilder *builder;
+ HdyWindow *window;
+
+ HdyHeaderBar *title_bar;
+ GtkButton *back_button;
+ GtkButton *details_button;
+
+ HdyFlap *details_flap;
+
+ GtkFlowBox *members_flowbox;
+
+ GtkButton *microphone_button;
+ GtkButton *camera_button;
+ GtkButton *screen_button;
+ GtkVolumeButton *speakers_button;
+ GtkButton *call_button;
+
+ GtkButton *close_details_button;
+ GtkListBox *contacts_listbox;
+} UI_DISCOURSE_Handle;
+
+/**
+ * Initializes a handle for the discourse window
+ * of a given messenger application.
+ *
+ * @param app Messenger application
+ * @param handle Discourse window handle
+ */
+void
+ui_discourse_window_init(MESSENGER_Application *app,
+ UI_DISCOURSE_Handle *handle);
+
+/**
+ * Updates a handle for the discourse window with
+ * a given chat context.
+ *
+ * @param handle Discourse window handle
+ * @param context Chat context
+ */
+void
+ui_discourse_window_update(UI_DISCOURSE_Handle *handle,
+ struct GNUNET_CHAT_Context *context);
+
+/**
+ * Cleans up the allocated resources and resets the
+ * state of a given discourse window handle.
+ *
+ * @param handle Discourse window handle
+ */
+void
+ui_discourse_window_cleanup(UI_DISCOURSE_Handle *handle);
+
+#endif /* UI_DISCOURSE_H_ */
diff --git a/src/ui/meson.build b/src/ui/meson.build
@@ -29,6 +29,7 @@ messenger_gtk_ui_sources = files([
'contact_info.c', 'contact_info.h',
'contacts.c', 'contacts.h',
'delete_messages.c', 'delete_messages.h',
+ 'discourse.c', 'discourse.h',
'files.c', 'files.h',
'file_entry.c', 'file_entry.h',
'file_load_entry.c', 'file_load_entry.h',