files.c (8161B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 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/files.c 23 */ 24 25 #include "files.h" 26 27 #include "file_entry.h" 28 #include "../application.h" 29 #include "../ui.h" 30 #include <gnunet/gnunet_chat_lib.h> 31 #include <gnunet/gnunet_common.h> 32 33 static void 34 handle_back_button_click(GtkButton *button, 35 gpointer user_data) 36 { 37 g_assert(user_data); 38 39 UI_FILES_Handle *handle = (UI_FILES_Handle*) user_data; 40 41 gtk_stack_set_visible_child(handle->dialog_stack, handle->list_box); 42 gtk_widget_set_visible(GTK_WIDGET(button), false); 43 } 44 45 static void 46 handle_close_button_click(UNUSED GtkButton *button, 47 gpointer user_data) 48 { 49 g_assert(user_data); 50 51 GtkDialog *dialog = GTK_DIALOG(user_data); 52 gtk_window_close(GTK_WINDOW(dialog)); 53 } 54 55 static void 56 handle_files_listbox_row_activated(UNUSED GtkListBox* listbox, 57 GtkListBoxRow* row, 58 gpointer user_data) 59 { 60 g_assert((row) && (user_data)); 61 62 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 63 64 if (!gtk_list_box_row_get_selectable(row)) 65 return; 66 67 UI_FILES_Handle *handle = &(app->ui.files); 68 69 struct GNUNET_CHAT_File *file = (struct GNUNET_CHAT_File*) ( 70 g_object_get_qdata(G_OBJECT(row), app->quarks.data) 71 ); 72 73 application_chat_lock(app); 74 75 const gdouble progress = ( 76 (gdouble) GNUNET_CHAT_file_get_local_size(file) / 77 GNUNET_CHAT_file_get_size(file) 78 ); 79 80 gtk_progress_bar_set_fraction(handle->storage_progress_bar, progress); 81 82 if (GNUNET_YES == GNUNET_CHAT_file_is_downloading(file)) 83 gtk_stack_set_visible_child(handle->play_icon_stack, handle->pause_icon_image); 84 else 85 gtk_stack_set_visible_child(handle->play_icon_stack, handle->play_icon_image); 86 87 gtk_widget_set_visible( 88 GTK_WIDGET(handle->play_pause_button), 89 GNUNET_YES != GNUNET_CHAT_file_is_ready(file) 90 ); 91 92 application_chat_unlock(app); 93 94 UI_FILE_ENTRY_Handle *entry = (UI_FILE_ENTRY_Handle*) ( 95 g_object_get_qdata(G_OBJECT(row), app->quarks.ui) 96 ); 97 98 const gchar *name = gtk_label_get_text(entry->name_label); 99 const gchar *size = gtk_label_get_text(entry->size_label); 100 101 gtk_label_set_text(handle->name_label, name); 102 gtk_progress_bar_set_text(handle->storage_progress_bar, size); 103 104 gtk_stack_set_visible_child(handle->dialog_stack, handle->info_box); 105 gtk_widget_set_visible(GTK_WIDGET(handle->back_button), true); 106 } 107 108 static gboolean 109 handle_files_listbox_filter_func(GtkListBoxRow *row, 110 gpointer user_data) 111 { 112 g_assert((row) && (user_data)); 113 114 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 115 116 if (!gtk_list_box_row_get_selectable(row)) 117 return TRUE; 118 119 const gchar *filter = gtk_entry_get_text( 120 GTK_ENTRY(app->ui.files.file_search_entry) 121 ); 122 123 if (!filter) 124 return TRUE; 125 126 UI_FILE_ENTRY_Handle *entry = (UI_FILE_ENTRY_Handle*) ( 127 g_object_get_qdata(G_OBJECT(row), app->quarks.ui) 128 ); 129 130 if (!entry) 131 return FALSE; 132 133 const gchar *name = gtk_label_get_text(entry->name_label); 134 135 if (!name) 136 return FALSE; 137 138 return g_str_match_string(filter, name, TRUE); 139 } 140 141 static void 142 handle_file_search_entry_search_changed(UNUSED GtkSearchEntry* search_entry, 143 gpointer user_data) 144 { 145 g_assert(user_data); 146 147 GtkListBox *listbox = GTK_LIST_BOX(user_data); 148 149 gtk_list_box_invalidate_filter(listbox); 150 } 151 152 static void 153 handle_dialog_destroy(UNUSED GtkWidget *window, 154 gpointer user_data) 155 { 156 g_assert(user_data); 157 158 ui_files_dialog_cleanup((UI_FILES_Handle*) user_data); 159 } 160 161 static enum GNUNET_GenericReturnValue 162 _iterate_files(void *cls, 163 UNUSED struct GNUNET_CHAT_Handle *handle, 164 struct GNUNET_CHAT_File *file) 165 { 166 g_assert((cls) && (file)); 167 168 MESSENGER_Application *app = (MESSENGER_Application*) cls; 169 GtkListBox *listbox = app->ui.files.files_listbox; 170 171 UI_FILE_ENTRY_Handle* entry = ui_file_entry_new(app); 172 ui_file_entry_update(entry, file); 173 174 gtk_list_box_prepend(listbox, entry->entry_box); 175 176 GtkListBoxRow *row = GTK_LIST_BOX_ROW( 177 gtk_widget_get_parent(entry->entry_box) 178 ); 179 180 g_object_set_qdata(G_OBJECT(row), app->quarks.data, file); 181 g_object_set_qdata_full( 182 G_OBJECT(row), 183 app->quarks.ui, 184 entry, 185 (GDestroyNotify) ui_file_entry_delete 186 ); 187 188 return GNUNET_YES; 189 } 190 191 void 192 ui_files_dialog_init(MESSENGER_Application *app, 193 UI_FILES_Handle *handle) 194 { 195 g_assert((app) && (handle)); 196 197 handle->builder = ui_builder_from_resource( 198 application_get_resource_path(app, "ui/files.ui") 199 ); 200 201 handle->dialog = GTK_DIALOG( 202 gtk_builder_get_object(handle->builder, "files_dialog") 203 ); 204 205 gtk_window_set_transient_for( 206 GTK_WINDOW(handle->dialog), 207 GTK_WINDOW(app->ui.messenger.main_window) 208 ); 209 210 handle->dialog_stack = GTK_STACK( 211 gtk_builder_get_object(handle->builder, "dialog_stack") 212 ); 213 214 handle->list_box = GTK_WIDGET( 215 gtk_builder_get_object(handle->builder, "list_box") 216 ); 217 218 handle->info_box = GTK_WIDGET( 219 gtk_builder_get_object(handle->builder, "info_box") 220 ); 221 222 handle->file_search_entry = GTK_SEARCH_ENTRY( 223 gtk_builder_get_object(handle->builder, "file_search_entry") 224 ); 225 226 handle->files_listbox = GTK_LIST_BOX( 227 gtk_builder_get_object(handle->builder, "files_listbox") 228 ); 229 230 gtk_list_box_set_filter_func( 231 handle->files_listbox, 232 handle_files_listbox_filter_func, 233 app, 234 NULL 235 ); 236 237 g_signal_connect( 238 handle->file_search_entry, 239 "search-changed", 240 G_CALLBACK(handle_file_search_entry_search_changed), 241 handle->files_listbox 242 ); 243 244 g_signal_connect( 245 handle->files_listbox, 246 "row-activated", 247 G_CALLBACK(handle_files_listbox_row_activated), 248 app 249 ); 250 251 handle->name_label = GTK_LABEL( 252 gtk_builder_get_object(handle->builder, "name_label") 253 ); 254 255 handle->storage_progress_bar = GTK_PROGRESS_BAR( 256 gtk_builder_get_object(handle->builder, "storage_progress_bar") 257 ); 258 259 handle->delete_file_button = GTK_BUTTON( 260 gtk_builder_get_object(handle->builder, "delete_file_button") 261 ); 262 263 handle->play_pause_button = GTK_BUTTON( 264 gtk_builder_get_object(handle->builder, "play_pause_button") 265 ); 266 267 handle->play_icon_stack = GTK_STACK( 268 gtk_builder_get_object(handle->builder, "play_icon_stack") 269 ); 270 271 handle->play_icon_image = GTK_WIDGET( 272 gtk_builder_get_object(handle->builder, "play_icon_image") 273 ); 274 275 handle->pause_icon_image = GTK_WIDGET( 276 gtk_builder_get_object(handle->builder, "pause_icon_image") 277 ); 278 279 handle->back_button = GTK_BUTTON( 280 gtk_builder_get_object(handle->builder, "back_button") 281 ); 282 283 g_signal_connect( 284 handle->back_button, 285 "clicked", 286 G_CALLBACK(handle_back_button_click), 287 handle 288 ); 289 290 handle->close_button = GTK_BUTTON( 291 gtk_builder_get_object(handle->builder, "close_button") 292 ); 293 294 g_signal_connect( 295 handle->close_button, 296 "clicked", 297 G_CALLBACK(handle_close_button_click), 298 handle->dialog 299 ); 300 301 g_signal_connect( 302 handle->dialog, 303 "destroy", 304 G_CALLBACK(handle_dialog_destroy), 305 handle 306 ); 307 308 GNUNET_CHAT_iterate_files( 309 app->chat.messenger.handle, 310 _iterate_files, 311 app 312 ); 313 314 gtk_list_box_invalidate_filter(handle->files_listbox); 315 } 316 317 void 318 ui_files_dialog_cleanup(UI_FILES_Handle *handle) 319 { 320 g_assert(handle); 321 322 if (handle->builder) 323 g_object_unref(handle->builder); 324 325 memset(handle, 0, sizeof(*handle)); 326 }