diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/application.c | 4 | ||||
-rw-r--r-- | src/event.c | 86 | ||||
-rw-r--r-- | src/ui/chat.c | 249 | ||||
-rw-r--r-- | src/ui/chat.h | 59 | ||||
-rw-r--r-- | src/ui/chat_entry.c | 14 | ||||
-rw-r--r-- | src/ui/chat_entry.h | 12 | ||||
-rw-r--r-- | src/ui/messenger.c | 215 | ||||
-rw-r--r-- | src/ui/messenger.h | 17 |
8 files changed, 400 insertions, 256 deletions
diff --git a/src/application.c b/src/application.c index e73d9de..764b8ea 100644 --- a/src/application.c +++ b/src/application.c | |||
@@ -48,7 +48,7 @@ _application_activate(UNUSED GtkApplication* application, | |||
48 | { | 48 | { |
49 | MESSENGER_Application *app = (MESSENGER_Application*) user_data; | 49 | MESSENGER_Application *app = (MESSENGER_Application*) user_data; |
50 | 50 | ||
51 | ui_messenger_run(app); | 51 | ui_messenger_init(app, &(app->ui.messenger)); |
52 | } | 52 | } |
53 | 53 | ||
54 | void | 54 | void |
@@ -140,6 +140,8 @@ application_run(MESSENGER_Application *app) | |||
140 | 140 | ||
141 | pthread_join(app->chat.tid, NULL); | 141 | pthread_join(app->chat.tid, NULL); |
142 | 142 | ||
143 | ui_messenger_cleanup(&(app->ui.messenger)); | ||
144 | |||
143 | g_hash_table_destroy(app->ui.bindings); | 145 | g_hash_table_destroy(app->ui.bindings); |
144 | 146 | ||
145 | notify_uninit(); | 147 | notify_uninit(); |
diff --git a/src/event.c b/src/event.c index d11b8cf..6683e63 100644 --- a/src/event.c +++ b/src/event.c | |||
@@ -27,21 +27,43 @@ | |||
27 | #include "ui/chat_entry.h" | 27 | #include "ui/chat_entry.h" |
28 | #include "ui/message.h" | 28 | #include "ui/message.h" |
29 | 29 | ||
30 | static int | 30 | static void |
31 | _iterate_profile_contacts(void *cls, | 31 | _add_new_chat_entry(MESSENGER_Application *app, |
32 | UNUSED struct GNUNET_CHAT_Handle *handle, | 32 | struct GNUNET_CHAT_Context *context) |
33 | UNUSED struct GNUNET_CHAT_Contact *contact) | ||
34 | { | 33 | { |
35 | MESSENGER_Application *app = (MESSENGER_Application*) cls; | ||
36 | |||
37 | UI_MESSENGER_Handle *ui = &(app->ui.messenger); | 34 | UI_MESSENGER_Handle *ui = &(app->ui.messenger); |
38 | 35 | ||
39 | UI_CHAT_ENTRY_Handle *entry = ui_chat_entry_new(); | 36 | UI_CHAT_ENTRY_Handle *entry = ui_chat_entry_new(app); |
40 | |||
41 | gtk_container_add(GTK_CONTAINER(ui->chats_listbox), entry->entry_box); | 37 | gtk_container_add(GTK_CONTAINER(ui->chats_listbox), entry->entry_box); |
38 | GNUNET_CHAT_context_set_user_pointer(context, entry); | ||
39 | |||
40 | char context_id [9]; | ||
41 | g_snprintf(context_id, sizeof(context_id), "%08lx", (gulong) context); | ||
42 | |||
43 | gtk_widget_set_name(entry->entry_box, context_id); | ||
42 | 44 | ||
43 | g_free(entry); //TODO: add to a list or similar? | 45 | gtk_stack_add_named( |
46 | ui->chats_stack, | ||
47 | entry->chat->chat_box, | ||
48 | context_id | ||
49 | ); | ||
44 | 50 | ||
51 | g_hash_table_insert( | ||
52 | app->ui.bindings, | ||
53 | entry->chat->send_text_view, | ||
54 | context | ||
55 | ); | ||
56 | |||
57 | ui->chat_entries = g_list_append(ui->chat_entries, entry); | ||
58 | } | ||
59 | |||
60 | static int | ||
61 | _iterate_profile_contacts(void *cls, | ||
62 | UNUSED struct GNUNET_CHAT_Handle *handle, | ||
63 | UNUSED struct GNUNET_CHAT_Contact *contact) | ||
64 | { | ||
65 | MESSENGER_Application *app = (MESSENGER_Application*) cls; | ||
66 | _add_new_chat_entry(app, GNUNET_CHAT_contact_get_context(contact)); | ||
45 | return GNUNET_YES; | 67 | return GNUNET_YES; |
46 | } | 68 | } |
47 | 69 | ||
@@ -51,15 +73,7 @@ _iterate_profile_groups(void *cls, | |||
51 | UNUSED struct GNUNET_CHAT_Group *group) | 73 | UNUSED struct GNUNET_CHAT_Group *group) |
52 | { | 74 | { |
53 | MESSENGER_Application *app = (MESSENGER_Application*) cls; | 75 | MESSENGER_Application *app = (MESSENGER_Application*) cls; |
54 | 76 | _add_new_chat_entry(app, GNUNET_CHAT_group_get_context(group)); | |
55 | UI_MESSENGER_Handle *ui = &(app->ui.messenger); | ||
56 | |||
57 | UI_CHAT_ENTRY_Handle *entry = ui_chat_entry_new(); | ||
58 | |||
59 | gtk_container_add(GTK_CONTAINER(ui->chats_listbox), entry->entry_box); | ||
60 | |||
61 | g_free(entry); //TODO: add to a list or similar? | ||
62 | |||
63 | return GNUNET_YES; | 77 | return GNUNET_YES; |
64 | } | 78 | } |
65 | 79 | ||
@@ -96,12 +110,6 @@ event_update_profile(MESSENGER_Application *app, | |||
96 | 110 | ||
97 | GNUNET_CHAT_iterate_contacts(chat->handle, _iterate_profile_contacts, app); | 111 | GNUNET_CHAT_iterate_contacts(chat->handle, _iterate_profile_contacts, app); |
98 | GNUNET_CHAT_iterate_groups(chat->handle, _iterate_profile_groups, app); | 112 | GNUNET_CHAT_iterate_groups(chat->handle, _iterate_profile_groups, app); |
99 | |||
100 | for (int i = 0; i < 8; i++) { | ||
101 | UI_MESSAGE_Handle *message = ui_message_new(app, i % 2 == 0); | ||
102 | gtk_container_add(GTK_CONTAINER(ui->messages_listbox), message->message_box); | ||
103 | g_free(message); // TODO: this is just a test! | ||
104 | } | ||
105 | } | 113 | } |
106 | 114 | ||
107 | void | 115 | void |
@@ -117,26 +125,7 @@ event_update_chats(MESSENGER_Application *app, | |||
117 | if (GNUNET_CHAT_context_get_user_pointer(context)) | 125 | if (GNUNET_CHAT_context_get_user_pointer(context)) |
118 | return; | 126 | return; |
119 | 127 | ||
120 | UI_MESSENGER_Handle *ui = &(app->ui.messenger); | 128 | _add_new_chat_entry(app, context); |
121 | |||
122 | UI_CHAT_ENTRY_Handle *entry = ui_chat_entry_new(); | ||
123 | gtk_container_add(GTK_CONTAINER(ui->chats_listbox), entry->entry_box); | ||
124 | g_free(entry); // TODO: free already? | ||
125 | |||
126 | // TODO: put something better here to attach it! | ||
127 | GNUNET_CHAT_context_set_user_pointer(context, ui); | ||
128 | |||
129 | g_hash_table_insert( | ||
130 | app->ui.bindings, | ||
131 | app->ui.messenger.send_record_button, | ||
132 | context | ||
133 | ); | ||
134 | |||
135 | g_hash_table_insert( | ||
136 | app->ui.bindings, | ||
137 | app->ui.messenger.send_text_view, | ||
138 | context | ||
139 | ); | ||
140 | } | 129 | } |
141 | 130 | ||
142 | void | 131 | void |
@@ -149,7 +138,9 @@ event_receive_message(MESSENGER_Application *app, | |||
149 | 138 | ||
150 | struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) argv[0]; | 139 | struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) argv[0]; |
151 | 140 | ||
152 | if (!GNUNET_CHAT_context_get_user_pointer(context)) | 141 | UI_CHAT_ENTRY_Handle *handle = GNUNET_CHAT_context_get_user_pointer(context); |
142 | |||
143 | if (!handle) | ||
153 | return; | 144 | return; |
154 | 145 | ||
155 | const struct GNUNET_CHAT_Message *msg; | 146 | const struct GNUNET_CHAT_Message *msg; |
@@ -185,9 +176,12 @@ event_receive_message(MESSENGER_Application *app, | |||
185 | // TODO: check read receipt | 176 | // TODO: check read receipt |
186 | 177 | ||
187 | gtk_container_add( | 178 | gtk_container_add( |
188 | GTK_CONTAINER(app->ui.messenger.messages_listbox), | 179 | GTK_CONTAINER(handle->chat->messages_listbox), |
189 | message->message_box | 180 | message->message_box |
190 | ); | 181 | ); |
191 | 182 | ||
192 | g_free(message); // TODO: this is just a test! | 183 | g_free(message); // TODO: this is just a test! |
184 | |||
185 | gtk_label_set_text(handle->text_label, text? text : ""); | ||
186 | gtk_label_set_text(handle->timestamp_label, time? time : ""); | ||
193 | } | 187 | } |
diff --git a/src/ui/chat.c b/src/ui/chat.c new file mode 100644 index 0000000..7e5c1fc --- /dev/null +++ b/src/ui/chat.c | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2021 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/chat.c | ||
23 | */ | ||
24 | |||
25 | #include "chat.h" | ||
26 | |||
27 | #include "messenger.h" | ||
28 | #include "../application.h" | ||
29 | |||
30 | static void | ||
31 | handle_flap_via_button_click(UNUSED GtkButton* button, | ||
32 | gpointer user_data) | ||
33 | { | ||
34 | HdyFlap* flap = HDY_FLAP(user_data); | ||
35 | |||
36 | if (TRUE == hdy_flap_get_reveal_flap(flap)) { | ||
37 | hdy_flap_set_reveal_flap(flap, FALSE); | ||
38 | } else { | ||
39 | hdy_flap_set_reveal_flap(flap, TRUE); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void | ||
44 | handle_back_button_click(UNUSED GtkButton* button, | ||
45 | gpointer user_data) | ||
46 | { | ||
47 | HdyLeaflet* leaflet = HDY_LEAFLET(user_data); | ||
48 | |||
49 | GList* children = gtk_container_get_children(GTK_CONTAINER(leaflet)); | ||
50 | |||
51 | if (children) { | ||
52 | hdy_leaflet_set_visible_child(leaflet, GTK_WIDGET(children->data)); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | static void | ||
57 | handle_send_text_buffer_changed(GtkTextBuffer *buffer, | ||
58 | gpointer user_data) | ||
59 | { | ||
60 | GtkImage *symbol = GTK_IMAGE(user_data); | ||
61 | |||
62 | GtkTextIter start, end; | ||
63 | gtk_text_buffer_get_start_iter(buffer, &start); | ||
64 | gtk_text_buffer_get_end_iter(buffer, &end); | ||
65 | |||
66 | const gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); | ||
67 | |||
68 | gtk_image_set_from_icon_name( | ||
69 | symbol, | ||
70 | 0 < g_utf8_strlen(text, 1)? | ||
71 | "mail-send-symbolic" : | ||
72 | "audio-input-microphone-symbolic", | ||
73 | GTK_ICON_SIZE_BUTTON | ||
74 | ); | ||
75 | } | ||
76 | |||
77 | static gboolean | ||
78 | _send_text_from_view(MESSENGER_Application *app, | ||
79 | GtkTextView *text_view) | ||
80 | { | ||
81 | GtkTextBuffer *buffer = gtk_text_view_get_buffer(text_view); | ||
82 | |||
83 | GtkTextIter start, end; | ||
84 | gtk_text_buffer_get_start_iter(buffer, &start); | ||
85 | gtk_text_buffer_get_end_iter(buffer, &end); | ||
86 | |||
87 | const gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); | ||
88 | |||
89 | if (0 == g_utf8_strlen(text, 1)) | ||
90 | return FALSE; | ||
91 | |||
92 | struct GNUNET_CHAT_Context *context = g_hash_table_lookup( | ||
93 | app->ui.bindings, text_view | ||
94 | ); | ||
95 | |||
96 | if (context) | ||
97 | GNUNET_CHAT_context_send_text(context, text); | ||
98 | |||
99 | gtk_text_buffer_delete(buffer, &start, &end); | ||
100 | return TRUE; | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | handle_send_record_button_click(GtkButton *button, | ||
105 | gpointer user_data) | ||
106 | { | ||
107 | MESSENGER_Application *app = (MESSENGER_Application*) user_data; | ||
108 | |||
109 | GtkTextView *text_view = GTK_TEXT_VIEW( | ||
110 | g_hash_table_lookup(app->ui.bindings, button) | ||
111 | ); | ||
112 | |||
113 | if (!_send_text_from_view(app, text_view)) | ||
114 | { | ||
115 | // TODO: record audio and attach as file? | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static gboolean | ||
120 | handle_send_text_key_press (GtkWidget *widget, | ||
121 | GdkEventKey *event, | ||
122 | gpointer user_data) | ||
123 | { | ||
124 | MESSENGER_Application *app = (MESSENGER_Application*) user_data; | ||
125 | |||
126 | if ((app->ui.mobile) || | ||
127 | (event->state & GDK_SHIFT_MASK) || | ||
128 | ((event->keyval != GDK_KEY_Return) && | ||
129 | (event->keyval != GDK_KEY_KP_Enter))) | ||
130 | return FALSE; | ||
131 | |||
132 | return _send_text_from_view(app, GTK_TEXT_VIEW(widget)); | ||
133 | } | ||
134 | |||
135 | UI_CHAT_Handle* | ||
136 | ui_chat_new(MESSENGER_Application *app) | ||
137 | { | ||
138 | UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle)); | ||
139 | UI_MESSENGER_Handle *messenger = &(app->ui.messenger); | ||
140 | |||
141 | GtkBuilder* builder = gtk_builder_new_from_file( | ||
142 | "resources/ui/chat.ui" | ||
143 | ); | ||
144 | |||
145 | handle->chat_box = GTK_WIDGET( | ||
146 | gtk_builder_get_object(builder, "chat_box") | ||
147 | ); | ||
148 | |||
149 | handle->back_button = GTK_BUTTON( | ||
150 | gtk_builder_get_object(builder, "back_button") | ||
151 | ); | ||
152 | |||
153 | g_object_bind_property( | ||
154 | messenger->leaflet_chat, | ||
155 | "folded", | ||
156 | handle->back_button, | ||
157 | "visible", | ||
158 | G_BINDING_SYNC_CREATE | ||
159 | ); | ||
160 | |||
161 | g_signal_connect( | ||
162 | handle->back_button, | ||
163 | "clicked", | ||
164 | G_CALLBACK(handle_back_button_click), | ||
165 | messenger->leaflet_chat | ||
166 | ); | ||
167 | |||
168 | handle->chat_title = GTK_LABEL( | ||
169 | gtk_builder_get_object(builder, "chat_title") | ||
170 | ); | ||
171 | |||
172 | handle->chat_subtitle = GTK_LABEL( | ||
173 | gtk_builder_get_object(builder, "chat_subtitle") | ||
174 | ); | ||
175 | |||
176 | handle->chat_details_button = GTK_BUTTON( | ||
177 | gtk_builder_get_object(builder, "chat_details_button") | ||
178 | ); | ||
179 | |||
180 | g_signal_connect( | ||
181 | handle->chat_details_button, | ||
182 | "clicked", | ||
183 | G_CALLBACK(handle_flap_via_button_click), | ||
184 | messenger->flap_chat_details | ||
185 | ); | ||
186 | |||
187 | handle->messages_listbox = GTK_LIST_BOX( | ||
188 | gtk_builder_get_object(builder, "messages_listbox") | ||
189 | ); | ||
190 | |||
191 | handle->attach_file_button = GTK_BUTTON( | ||
192 | gtk_builder_get_object(builder, "attach_file_button") | ||
193 | ); | ||
194 | |||
195 | handle->send_text_view = GTK_TEXT_VIEW( | ||
196 | gtk_builder_get_object(builder, "send_text_view") | ||
197 | ); | ||
198 | |||
199 | handle->emoji_button = GTK_BUTTON( | ||
200 | gtk_builder_get_object(builder, "emoji_button") | ||
201 | ); | ||
202 | |||
203 | handle->send_record_button = GTK_BUTTON( | ||
204 | gtk_builder_get_object(builder, "send_record_button") | ||
205 | ); | ||
206 | |||
207 | handle->send_record_symbol = GTK_IMAGE( | ||
208 | gtk_builder_get_object(builder, "send_record_symbol") | ||
209 | ); | ||
210 | |||
211 | GtkTextBuffer *send_text_buffer = gtk_text_view_get_buffer( | ||
212 | handle->send_text_view | ||
213 | ); | ||
214 | |||
215 | g_signal_connect( | ||
216 | send_text_buffer, | ||
217 | "changed", | ||
218 | G_CALLBACK(handle_send_text_buffer_changed), | ||
219 | handle->send_record_symbol | ||
220 | ); | ||
221 | |||
222 | g_signal_connect( | ||
223 | handle->send_record_button, | ||
224 | "clicked", | ||
225 | G_CALLBACK(handle_send_record_button_click), | ||
226 | app | ||
227 | ); | ||
228 | |||
229 | g_signal_connect( | ||
230 | handle->send_text_view, | ||
231 | "key-press-event", | ||
232 | G_CALLBACK(handle_send_text_key_press), | ||
233 | app | ||
234 | ); | ||
235 | |||
236 | g_hash_table_insert( | ||
237 | app->ui.bindings, | ||
238 | handle->send_record_button, | ||
239 | handle->send_text_view | ||
240 | ); | ||
241 | |||
242 | return handle; | ||
243 | } | ||
244 | |||
245 | void | ||
246 | ui_chat_delete(UI_CHAT_Handle *handle) | ||
247 | { | ||
248 | g_free(handle); | ||
249 | } | ||
diff --git a/src/ui/chat.h b/src/ui/chat.h new file mode 100644 index 0000000..5415647 --- /dev/null +++ b/src/ui/chat.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2021 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/chat.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_CHAT_H_ | ||
26 | #define UI_CHAT_H_ | ||
27 | |||
28 | #include <gtk-3.0/gtk/gtk.h> | ||
29 | #include <libhandy-1/handy.h> | ||
30 | #include <libnotify/notify.h> | ||
31 | |||
32 | typedef struct MESSENGER_Application MESSENGER_Application; | ||
33 | |||
34 | typedef struct UI_CHAT_Handle | ||
35 | { | ||
36 | GtkWidget *chat_box; | ||
37 | |||
38 | GtkButton *back_button; | ||
39 | |||
40 | GtkLabel *chat_title; | ||
41 | GtkLabel *chat_subtitle; | ||
42 | GtkButton *chat_details_button; | ||
43 | |||
44 | GtkListBox *messages_listbox; | ||
45 | |||
46 | GtkButton *attach_file_button; | ||
47 | GtkTextView *send_text_view; | ||
48 | GtkButton *emoji_button; | ||
49 | GtkButton *send_record_button; | ||
50 | GtkImage *send_record_symbol; | ||
51 | } UI_CHAT_Handle; | ||
52 | |||
53 | UI_CHAT_Handle* | ||
54 | ui_chat_new(MESSENGER_Application *app); | ||
55 | |||
56 | void | ||
57 | ui_chat_delete(UI_CHAT_Handle *handle); | ||
58 | |||
59 | #endif /* UI_CHAT_H_ */ | ||
diff --git a/src/ui/chat_entry.c b/src/ui/chat_entry.c index b314211..3de1ada 100644 --- a/src/ui/chat_entry.c +++ b/src/ui/chat_entry.c | |||
@@ -24,11 +24,15 @@ | |||
24 | 24 | ||
25 | #include "chat_entry.h" | 25 | #include "chat_entry.h" |
26 | 26 | ||
27 | #include "../application.h" | ||
28 | |||
27 | UI_CHAT_ENTRY_Handle* | 29 | UI_CHAT_ENTRY_Handle* |
28 | ui_chat_entry_new(void) | 30 | ui_chat_entry_new(MESSENGER_Application *app) |
29 | { | 31 | { |
30 | UI_CHAT_ENTRY_Handle* handle = g_malloc(sizeof(UI_CHAT_ENTRY_Handle)); | 32 | UI_CHAT_ENTRY_Handle* handle = g_malloc(sizeof(UI_CHAT_ENTRY_Handle)); |
31 | 33 | ||
34 | handle->chat = ui_chat_new(app); | ||
35 | |||
32 | GtkBuilder* builder = gtk_builder_new_from_file("resources/ui/chat_entry.ui"); | 36 | GtkBuilder* builder = gtk_builder_new_from_file("resources/ui/chat_entry.ui"); |
33 | 37 | ||
34 | handle->entry_box = GTK_WIDGET( | 38 | handle->entry_box = GTK_WIDGET( |
@@ -57,3 +61,11 @@ ui_chat_entry_new(void) | |||
57 | 61 | ||
58 | return handle; | 62 | return handle; |
59 | } | 63 | } |
64 | |||
65 | void | ||
66 | ui_chat_entry_delete(UI_CHAT_ENTRY_Handle *handle) | ||
67 | { | ||
68 | ui_chat_delete(handle->chat); | ||
69 | |||
70 | g_free(handle); | ||
71 | } | ||
diff --git a/src/ui/chat_entry.h b/src/ui/chat_entry.h index 2315686..4842eaf 100644 --- a/src/ui/chat_entry.h +++ b/src/ui/chat_entry.h | |||
@@ -25,13 +25,12 @@ | |||
25 | #ifndef UI_CHAT_ENTRY_H_ | 25 | #ifndef UI_CHAT_ENTRY_H_ |
26 | #define UI_CHAT_ENTRY_H_ | 26 | #define UI_CHAT_ENTRY_H_ |
27 | 27 | ||
28 | #include <gtk-3.0/gtk/gtk.h> | 28 | #include "chat.h" |
29 | #include <libhandy-1/handy.h> | ||
30 | |||
31 | typedef struct MESSENGER_Application MESSENGER_Application; | ||
32 | 29 | ||
33 | typedef struct UI_CHAT_ENTRY_Handle | 30 | typedef struct UI_CHAT_ENTRY_Handle |
34 | { | 31 | { |
32 | UI_CHAT_Handle *chat; | ||
33 | |||
35 | GtkWidget* entry_box; | 34 | GtkWidget* entry_box; |
36 | 35 | ||
37 | HdyAvatar* entry_avatar; | 36 | HdyAvatar* entry_avatar; |
@@ -44,6 +43,9 @@ typedef struct UI_CHAT_ENTRY_Handle | |||
44 | } UI_CHAT_ENTRY_Handle; | 43 | } UI_CHAT_ENTRY_Handle; |
45 | 44 | ||
46 | UI_CHAT_ENTRY_Handle* | 45 | UI_CHAT_ENTRY_Handle* |
47 | ui_chat_entry_new(void); | 46 | ui_chat_entry_new(MESSENGER_Application *app); |
47 | |||
48 | void | ||
49 | ui_chat_entry_delete(UI_CHAT_ENTRY_Handle *handle); | ||
48 | 50 | ||
49 | #endif /* UI_CHAT_ENTRY_H_ */ | 51 | #endif /* UI_CHAT_ENTRY_H_ */ |
diff --git a/src/ui/messenger.c b/src/ui/messenger.c index daabd17..2fc8c54 100644 --- a/src/ui/messenger.c +++ b/src/ui/messenger.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <gtk-3.0/gdk/gdkkeys.h> | 27 | #include <gtk-3.0/gdk/gdkkeys.h> |
28 | 28 | ||
29 | #include "chat_entry.h" | ||
29 | #include "message.h" | 30 | #include "message.h" |
30 | #include "new_platform.h" | 31 | #include "new_platform.h" |
31 | #include "../application.h" | 32 | #include "../application.h" |
@@ -80,118 +81,25 @@ handle_new_platform_button_click(UNUSED GtkButton* button, | |||
80 | 81 | ||
81 | static void | 82 | static void |
82 | handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox, | 83 | handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox, |
83 | UNUSED GtkListBoxRow* row, | 84 | GtkListBoxRow* row, |
84 | gpointer user_data) | 85 | gpointer user_data) |
85 | { | 86 | { |
86 | HdyLeaflet* leaflet = HDY_LEAFLET(user_data); | 87 | UI_MESSENGER_Handle *handle = (UI_MESSENGER_Handle*) user_data; |
88 | |||
89 | GtkStack *stack = handle->chats_stack; | ||
90 | HdyLeaflet *leaflet = handle->leaflet_chat; | ||
87 | 91 | ||
88 | GList* children = gtk_container_get_children(GTK_CONTAINER(leaflet)); | 92 | GList *children = gtk_container_get_children(GTK_CONTAINER(leaflet)); |
89 | 93 | ||
90 | if ((children) && (children->next)) { | 94 | if ((children) && (children->next)) { |
91 | hdy_leaflet_set_visible_child(leaflet, GTK_WIDGET(children->next->data)); | 95 | hdy_leaflet_set_visible_child(leaflet, GTK_WIDGET(children->next->data)); |
92 | } | 96 | } |
93 | } | ||
94 | |||
95 | static void | ||
96 | handle_back_button_click(UNUSED GtkButton* button, | ||
97 | gpointer user_data) | ||
98 | { | ||
99 | HdyLeaflet* leaflet = HDY_LEAFLET(user_data); | ||
100 | |||
101 | GList* children = gtk_container_get_children(GTK_CONTAINER(leaflet)); | ||
102 | |||
103 | if (children) { | ||
104 | hdy_leaflet_set_visible_child(leaflet, GTK_WIDGET(children->data)); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | handle_send_text_buffer_changed(GtkTextBuffer *buffer, | ||
110 | gpointer user_data) | ||
111 | { | ||
112 | GtkImage *symbol = GTK_IMAGE(user_data); | ||
113 | |||
114 | GtkTextIter start, end; | ||
115 | gtk_text_buffer_get_start_iter(buffer, &start); | ||
116 | gtk_text_buffer_get_end_iter(buffer, &end); | ||
117 | |||
118 | const gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); | ||
119 | |||
120 | gtk_image_set_from_icon_name( | ||
121 | symbol, | ||
122 | 0 < g_utf8_strlen(text, 1)? | ||
123 | "mail-send-symbolic" : | ||
124 | "audio-input-microphone-symbolic", | ||
125 | GTK_ICON_SIZE_BUTTON | ||
126 | ); | ||
127 | } | ||
128 | |||
129 | static void | ||
130 | handle_send_record_button_click(GtkButton *button, | ||
131 | gpointer user_data) | ||
132 | { | ||
133 | MESSENGER_Application *app = (MESSENGER_Application*) user_data; | ||
134 | |||
135 | GtkTextBuffer *buffer = gtk_text_view_get_buffer( | ||
136 | app->ui.messenger.send_text_view | ||
137 | ); | ||
138 | |||
139 | GtkTextIter start, end; | ||
140 | gtk_text_buffer_get_start_iter(buffer, &start); | ||
141 | gtk_text_buffer_get_end_iter(buffer, &end); | ||
142 | |||
143 | const gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); | ||
144 | |||
145 | if (0 < g_utf8_strlen(text, 1)) | ||
146 | { | ||
147 | struct GNUNET_CHAT_Context *context = g_hash_table_lookup( | ||
148 | app->ui.bindings, button | ||
149 | ); | ||
150 | |||
151 | if (context) | ||
152 | GNUNET_CHAT_context_send_text(context, text); | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | // TODO: record audio and attach as file? | ||
157 | } | ||
158 | |||
159 | gtk_text_buffer_delete(buffer, &start, &end); | ||
160 | } | ||
161 | 97 | ||
162 | static gboolean | 98 | GtkWidget *entry = GTK_WIDGET( |
163 | handle_send_text_key_press (GtkWidget *widget, | 99 | gtk_container_get_children(GTK_CONTAINER(row))->data |
164 | GdkEventKey *event, | ||
165 | gpointer user_data) | ||
166 | { | ||
167 | MESSENGER_Application *app = (MESSENGER_Application*) user_data; | ||
168 | |||
169 | if ((app->ui.mobile) || | ||
170 | (event->state & GDK_SHIFT_MASK) || | ||
171 | ((event->keyval != GDK_KEY_Return) && | ||
172 | (event->keyval != GDK_KEY_KP_Enter))) | ||
173 | return FALSE; | ||
174 | |||
175 | GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (widget)); | ||
176 | |||
177 | GtkTextIter start, end; | ||
178 | gtk_text_buffer_get_start_iter(buffer, &start); | ||
179 | gtk_text_buffer_get_end_iter(buffer, &end); | ||
180 | |||
181 | const gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); | ||
182 | |||
183 | if (0 == g_utf8_strlen(text, 1)) | ||
184 | return FALSE; | ||
185 | |||
186 | struct GNUNET_CHAT_Context *context = g_hash_table_lookup( | ||
187 | app->ui.bindings, widget | ||
188 | ); | 100 | ); |
189 | 101 | ||
190 | if (context) | 102 | gtk_stack_set_visible_child_name(stack, gtk_widget_get_name(entry)); |
191 | GNUNET_CHAT_context_send_text(context, text); | ||
192 | |||
193 | gtk_text_buffer_delete(buffer, &start, &end); | ||
194 | return TRUE; | ||
195 | } | 103 | } |
196 | 104 | ||
197 | static void | 105 | static void |
@@ -207,6 +115,8 @@ void | |||
207 | ui_messenger_init(MESSENGER_Application *app, | 115 | ui_messenger_init(MESSENGER_Application *app, |
208 | UI_MESSENGER_Handle *handle) | 116 | UI_MESSENGER_Handle *handle) |
209 | { | 117 | { |
118 | handle->chat_entries = g_list_alloc(); | ||
119 | |||
210 | GtkBuilder* builder = gtk_builder_new_from_file("resources/ui/messenger.ui"); | 120 | GtkBuilder* builder = gtk_builder_new_from_file("resources/ui/messenger.ui"); |
211 | 121 | ||
212 | handle->main_window = GTK_APPLICATION_WINDOW( | 122 | handle->main_window = GTK_APPLICATION_WINDOW( |
@@ -257,25 +167,6 @@ ui_messenger_init(MESSENGER_Application *app, | |||
257 | G_BINDING_INVERT_BOOLEAN | 167 | G_BINDING_INVERT_BOOLEAN |
258 | ); | 168 | ); |
259 | 169 | ||
260 | handle->back_button = GTK_BUTTON( | ||
261 | gtk_builder_get_object(builder, "back_button") | ||
262 | ); | ||
263 | |||
264 | g_object_bind_property( | ||
265 | handle->leaflet_chat, | ||
266 | "folded", | ||
267 | handle->back_button, | ||
268 | "visible", | ||
269 | G_BINDING_SYNC_CREATE | ||
270 | ); | ||
271 | |||
272 | g_signal_connect( | ||
273 | handle->back_button, | ||
274 | "clicked", | ||
275 | G_CALLBACK(handle_back_button_click), | ||
276 | handle->leaflet_chat | ||
277 | ); | ||
278 | |||
279 | handle->profile_avatar = HDY_AVATAR( | 170 | handle->profile_avatar = HDY_AVATAR( |
280 | gtk_builder_get_object(builder, "profile_avatar") | 171 | gtk_builder_get_object(builder, "profile_avatar") |
281 | ); | 172 | ); |
@@ -372,26 +263,11 @@ ui_messenger_init(MESSENGER_Application *app, | |||
372 | handle->chats_listbox, | 263 | handle->chats_listbox, |
373 | "row-activated", | 264 | "row-activated", |
374 | G_CALLBACK(handle_chats_listbox_row_activated), | 265 | G_CALLBACK(handle_chats_listbox_row_activated), |
375 | handle->leaflet_chat | 266 | handle |
376 | ); | ||
377 | |||
378 | handle->chat_title = GTK_LABEL( | ||
379 | gtk_builder_get_object(builder, "chat_title") | ||
380 | ); | ||
381 | |||
382 | handle->chat_subtitle = GTK_LABEL( | ||
383 | gtk_builder_get_object(builder, "chat_subtitle") | ||
384 | ); | ||
385 | |||
386 | handle->chat_details_button = GTK_BUTTON( | ||
387 | gtk_builder_get_object(builder, "chat_details_button") | ||
388 | ); | 267 | ); |
389 | 268 | ||
390 | g_signal_connect( | 269 | handle->chats_stack = GTK_STACK( |
391 | handle->chat_details_button, | 270 | gtk_builder_get_object(builder, "chats_stack") |
392 | "clicked", | ||
393 | G_CALLBACK(handle_flap_via_button_click), | ||
394 | handle->flap_chat_details | ||
395 | ); | 271 | ); |
396 | 272 | ||
397 | handle->hide_chat_details_button = GTK_BUTTON( | 273 | handle->hide_chat_details_button = GTK_BUTTON( |
@@ -405,55 +281,6 @@ ui_messenger_init(MESSENGER_Application *app, | |||
405 | handle->flap_chat_details | 281 | handle->flap_chat_details |
406 | ); | 282 | ); |
407 | 283 | ||
408 | handle->messages_listbox = GTK_LIST_BOX( | ||
409 | gtk_builder_get_object(builder, "messages_listbox") | ||
410 | ); | ||
411 | |||
412 | handle->attach_file_button = GTK_BUTTON( | ||
413 | gtk_builder_get_object(builder, "attach_file_button") | ||
414 | ); | ||
415 | |||
416 | handle->send_text_view = GTK_TEXT_VIEW( | ||
417 | gtk_builder_get_object(builder, "send_text_view") | ||
418 | ); | ||
419 | |||
420 | handle->emoji_button = GTK_BUTTON( | ||
421 | gtk_builder_get_object(builder, "emoji_button") | ||
422 | ); | ||
423 | |||
424 | handle->send_record_button = GTK_BUTTON( | ||
425 | gtk_builder_get_object(builder, "send_record_button") | ||
426 | ); | ||
427 | |||
428 | handle->send_record_symbol = GTK_IMAGE( | ||
429 | gtk_builder_get_object(builder, "send_record_symbol") | ||
430 | ); | ||
431 | |||
432 | GtkTextBuffer *send_text_buffer = gtk_text_view_get_buffer( | ||
433 | handle->send_text_view | ||
434 | ); | ||
435 | |||
436 | g_signal_connect( | ||
437 | send_text_buffer, | ||
438 | "changed", | ||
439 | G_CALLBACK(handle_send_text_buffer_changed), | ||
440 | handle->send_record_symbol | ||
441 | ); | ||
442 | |||
443 | g_signal_connect( | ||
444 | handle->send_record_button, | ||
445 | "clicked", | ||
446 | G_CALLBACK(handle_send_record_button_click), | ||
447 | app | ||
448 | ); | ||
449 | |||
450 | g_signal_connect( | ||
451 | handle->send_text_view, | ||
452 | "key-press-event", | ||
453 | G_CALLBACK(handle_send_text_key_press), | ||
454 | app | ||
455 | ); | ||
456 | |||
457 | gtk_widget_show(GTK_WIDGET(handle->main_window)); | 284 | gtk_widget_show(GTK_WIDGET(handle->main_window)); |
458 | 285 | ||
459 | g_signal_connect( | 286 | g_signal_connect( |
@@ -464,8 +291,16 @@ ui_messenger_init(MESSENGER_Application *app, | |||
464 | ); | 291 | ); |
465 | } | 292 | } |
466 | 293 | ||
294 | static void | ||
295 | _free_ui_chat_entry (gpointer user_data) | ||
296 | { | ||
297 | UI_CHAT_ENTRY_Handle* handle = (UI_CHAT_ENTRY_Handle*) user_data; | ||
298 | |||
299 | ui_chat_entry_delete(handle); | ||
300 | } | ||
301 | |||
467 | void | 302 | void |
468 | ui_messenger_run(MESSENGER_Application *app) | 303 | ui_messenger_cleanup(UI_MESSENGER_Handle *handle) |
469 | { | 304 | { |
470 | ui_messenger_init(app, &(app->ui.messenger)); | 305 | g_list_free_full(handle->chat_entries, _free_ui_chat_entry); |
471 | } | 306 | } |
diff --git a/src/ui/messenger.h b/src/ui/messenger.h index c2e53a1..6cd4c9d 100644 --- a/src/ui/messenger.h +++ b/src/ui/messenger.h | |||
@@ -33,6 +33,8 @@ typedef struct MESSENGER_Application MESSENGER_Application; | |||
33 | 33 | ||
34 | typedef struct UI_MESSENGER_Handle | 34 | typedef struct UI_MESSENGER_Handle |
35 | { | 35 | { |
36 | GList *chat_entries; | ||
37 | |||
36 | GtkApplicationWindow *main_window; | 38 | GtkApplicationWindow *main_window; |
37 | 39 | ||
38 | HdyLeaflet *leaflet_chat; | 40 | HdyLeaflet *leaflet_chat; |
@@ -40,7 +42,6 @@ typedef struct UI_MESSENGER_Handle | |||
40 | HdyFlap *flap_chat_details; | 42 | HdyFlap *flap_chat_details; |
41 | 43 | ||
42 | HdyHeaderBar *title_bar; | 44 | HdyHeaderBar *title_bar; |
43 | GtkButton *back_button; | ||
44 | 45 | ||
45 | HdyAvatar *profile_avatar; | 46 | HdyAvatar *profile_avatar; |
46 | GtkLabel *profile_label; | 47 | GtkLabel *profile_label; |
@@ -63,19 +64,9 @@ typedef struct UI_MESSENGER_Handle | |||
63 | GtkSearchEntry *chats_search; | 64 | GtkSearchEntry *chats_search; |
64 | GtkListBox *chats_listbox; | 65 | GtkListBox *chats_listbox; |
65 | 66 | ||
66 | GtkLabel *chat_title; | 67 | GtkStack *chats_stack; |
67 | GtkLabel *chat_subtitle; | ||
68 | GtkButton *chat_details_button; | ||
69 | 68 | ||
70 | GtkButton *hide_chat_details_button; | 69 | GtkButton *hide_chat_details_button; |
71 | |||
72 | GtkListBox *messages_listbox; | ||
73 | |||
74 | GtkButton *attach_file_button; | ||
75 | GtkTextView *send_text_view; | ||
76 | GtkButton *emoji_button; | ||
77 | GtkButton *send_record_button; | ||
78 | GtkImage *send_record_symbol; | ||
79 | } UI_MESSENGER_Handle; | 70 | } UI_MESSENGER_Handle; |
80 | 71 | ||
81 | void | 72 | void |
@@ -83,6 +74,6 @@ ui_messenger_init(MESSENGER_Application *app, | |||
83 | UI_MESSENGER_Handle *handle); | 74 | UI_MESSENGER_Handle *handle); |
84 | 75 | ||
85 | void | 76 | void |
86 | ui_messenger_run(MESSENGER_Application *app); | 77 | ui_messenger_cleanup(UI_MESSENGER_Handle *handle); |
87 | 78 | ||
88 | #endif /* UI_MESSENGER_H_ */ | 79 | #endif /* UI_MESSENGER_H_ */ |