invite_contact.c (6278B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2021--2024 GNUnet e.V. 4 5 GNUnet is free software: you can redistribute it and/or modify it 6 under the terms of the GNU Affero General Public License as published 7 by the Free Software Foundation, either version 3 of the License, 8 or (at your option) any later version. 9 10 GNUnet is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 SPDX-License-Identifier: AGPL3.0-or-later 19 */ 20 /* 21 * @author Tobias Frisch 22 * @file ui/invite_contact.c 23 */ 24 25 #include "invite_contact.h" 26 27 #include "contact_entry.h" 28 #include "../application.h" 29 #include "../ui.h" 30 31 static void 32 handle_close_button_click(UNUSED GtkButton *button, 33 gpointer user_data) 34 { 35 g_assert(user_data); 36 37 GtkDialog *dialog = GTK_DIALOG(user_data); 38 gtk_window_close(GTK_WINDOW(dialog)); 39 } 40 41 static void 42 handle_contacts_listbox_row_activated(GtkListBox* listbox, 43 GtkListBoxRow* row, 44 gpointer user_data) 45 { 46 g_assert((listbox) && (row) && (user_data)); 47 48 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 49 50 GtkTextView *text_view = GTK_TEXT_VIEW( 51 g_object_get_qdata(G_OBJECT(listbox), app->quarks.widget) 52 ); 53 54 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( 55 g_object_get_qdata(G_OBJECT(row), app->quarks.data) 56 ); 57 58 application_chat_lock(app); 59 60 if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) || 61 (GNUNET_YES == GNUNET_CHAT_contact_is_owned(contact)) || 62 (!text_view)) 63 goto close_dialog; 64 65 struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) ( 66 g_object_get_qdata(G_OBJECT(text_view), app->quarks.data) 67 ); 68 69 if (!context) 70 goto close_dialog; 71 72 struct GNUNET_CHAT_Group *group = GNUNET_CHAT_context_get_group( 73 context 74 ); 75 76 if (group) 77 GNUNET_CHAT_group_invite_contact(group, contact); 78 79 close_dialog: 80 application_chat_unlock(app); 81 82 gtk_window_close(GTK_WINDOW(app->ui.invite_contact.dialog)); 83 } 84 85 static gboolean 86 handle_contacts_listbox_filter_func(GtkListBoxRow *row, 87 gpointer user_data) 88 { 89 g_assert((row) && (user_data)); 90 91 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 92 93 if (!gtk_list_box_row_get_selectable(row)) 94 return TRUE; 95 96 const gchar *filter = gtk_entry_get_text( 97 GTK_ENTRY(app->ui.invite_contact.contact_search_entry) 98 ); 99 100 if (!filter) 101 return TRUE; 102 103 UI_CONTACT_ENTRY_Handle *entry = (UI_CONTACT_ENTRY_Handle*) ( 104 g_object_get_qdata(G_OBJECT(row), app->quarks.ui) 105 ); 106 107 if (!entry) 108 return FALSE; 109 110 const gchar *name = gtk_label_get_text(entry->title_label); 111 112 if (!name) 113 return FALSE; 114 115 return g_str_match_string(filter, name, TRUE); 116 } 117 118 static void 119 handle_contact_search_entry_search_changed(UNUSED GtkSearchEntry* search_entry, 120 gpointer user_data) 121 { 122 g_assert(user_data); 123 124 GtkListBox *listbox = GTK_LIST_BOX(user_data); 125 126 gtk_list_box_invalidate_filter(listbox); 127 } 128 129 static void 130 handle_dialog_destroy(UNUSED GtkWidget *window, 131 gpointer user_data) 132 { 133 g_assert(user_data); 134 135 ui_contacts_dialog_cleanup((UI_CONTACTS_Handle*) user_data); 136 } 137 138 static int 139 _iterate_contacts(void *cls, 140 UNUSED struct GNUNET_CHAT_Handle *handle, 141 struct GNUNET_CHAT_Contact *contact) 142 { 143 g_assert((cls) && (contact)); 144 145 if (GNUNET_YES == GNUNET_CHAT_contact_is_owned(contact)) 146 return GNUNET_YES; 147 148 MESSENGER_Application *app = (MESSENGER_Application*) cls; 149 150 UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app); 151 ui_contact_entry_set_contact(entry, contact); 152 153 gtk_list_box_prepend( 154 app->ui.invite_contact.contacts_listbox, 155 entry->entry_box 156 ); 157 158 GtkListBoxRow *row = GTK_LIST_BOX_ROW( 159 gtk_widget_get_parent(entry->entry_box) 160 ); 161 162 g_object_set_qdata(G_OBJECT(row), app->quarks.data, contact); 163 164 g_object_set_qdata_full( 165 G_OBJECT(row), 166 app->quarks.ui, 167 entry, 168 (GDestroyNotify) ui_contact_entry_delete 169 ); 170 171 return GNUNET_YES; 172 } 173 174 void 175 ui_invite_contact_dialog_init(MESSENGER_Application *app, 176 UI_INVITE_CONTACT_Handle *handle) 177 { 178 g_assert((app) && (handle)); 179 180 handle->builder = ui_builder_from_resource( 181 application_get_resource_path(app, "ui/invite_contact.ui") 182 ); 183 184 handle->dialog = GTK_DIALOG( 185 gtk_builder_get_object(handle->builder, "invite_contact_dialog") 186 ); 187 188 gtk_window_set_transient_for( 189 GTK_WINDOW(handle->dialog), 190 GTK_WINDOW(app->ui.messenger.main_window) 191 ); 192 193 handle->contact_search_entry = GTK_SEARCH_ENTRY( 194 gtk_builder_get_object(handle->builder, "contact_search_entry") 195 ); 196 197 handle->contacts_listbox = GTK_LIST_BOX( 198 gtk_builder_get_object(handle->builder, "contacts_listbox") 199 ); 200 201 gtk_list_box_set_filter_func( 202 handle->contacts_listbox, 203 handle_contacts_listbox_filter_func, 204 app, 205 NULL 206 ); 207 208 g_signal_connect( 209 handle->contact_search_entry, 210 "search-changed", 211 G_CALLBACK(handle_contact_search_entry_search_changed), 212 handle->contacts_listbox 213 ); 214 215 g_signal_connect( 216 handle->contacts_listbox, 217 "row-activated", 218 G_CALLBACK(handle_contacts_listbox_row_activated), 219 app 220 ); 221 222 handle->close_button = GTK_BUTTON( 223 gtk_builder_get_object(handle->builder, "close_button") 224 ); 225 226 g_signal_connect( 227 handle->close_button, 228 "clicked", 229 G_CALLBACK(handle_close_button_click), 230 handle->dialog 231 ); 232 233 g_signal_connect( 234 handle->dialog, 235 "destroy", 236 G_CALLBACK(handle_dialog_destroy), 237 handle 238 ); 239 240 GNUNET_CHAT_iterate_contacts( 241 app->chat.messenger.handle, 242 _iterate_contacts, 243 app 244 ); 245 246 gtk_list_box_invalidate_filter(handle->contacts_listbox); 247 } 248 249 void 250 ui_invite_contact_dialog_cleanup(UI_INVITE_CONTACT_Handle *handle) 251 { 252 g_assert(handle); 253 254 g_object_unref(handle->builder); 255 256 memset(handle, 0, sizeof(*handle)); 257 }