aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheJackiMonster <thejackimonster@gmail.com>2021-11-14 17:31:52 +0100
committerTheJackiMonster <thejackimonster@gmail.com>2021-11-14 17:31:52 +0100
commit56a206cd17e1caf23fbfd679c39752e5e194f35d (patch)
treee1667b9a2ef09c269bb8ee7260af719e28583f5f
parent83bf19ca1bc25c2162fa7e1d9f06644dd7e6b267 (diff)
downloadmessenger-gtk-56a206cd17e1caf23fbfd679c39752e5e194f35d.tar.gz
messenger-gtk-56a206cd17e1caf23fbfd679c39752e5e194f35d.zip
Implemented multiple chats in parallel
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r--Makefile1
-rw-r--r--resources/ui/chat.ui268
-rw-r--r--resources/ui/messenger.ui250
-rw-r--r--src/application.c4
-rw-r--r--src/event.c86
-rw-r--r--src/ui/chat.c249
-rw-r--r--src/ui/chat.h59
-rw-r--r--src/ui/chat_entry.c14
-rw-r--r--src/ui/chat_entry.h12
-rw-r--r--src/ui/messenger.c215
-rw-r--r--src/ui/messenger.h17
11 files changed, 672 insertions, 503 deletions
diff --git a/Makefile b/Makefile
index 3deba6c..7b96219 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ SOURCES = messenger_gtk.c\
7 application.c\ 7 application.c\
8 event.c\ 8 event.c\
9 chat/messenger.c\ 9 chat/messenger.c\
10 ui/chat.c\
10 ui/chat_entry.c\ 11 ui/chat_entry.c\
11 ui/message.c\ 12 ui/message.c\
12 ui/messenger.c\ 13 ui/messenger.c\
diff --git a/resources/ui/chat.ui b/resources/ui/chat.ui
new file mode 100644
index 0000000..c7f333c
--- /dev/null
+++ b/resources/ui/chat.ui
@@ -0,0 +1,268 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<!-- Generated with glade 3.38.2
3
4Copyright (C) 2021 GNUnet e.V.
5
6GNUnet is free software: you can redistribute it and/or modify it
7under the terms of the GNU Affero General Public License as published
8by the Free Software Foundation, either version 3 of the License,
9or (at your option) any later version.
10
11GNUnet is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14Affero General Public License for more details.
15
16You should have received a copy of the GNU Affero General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19SPDX-License-Identifier: AGPL3.0-or-later
20Author: Tobias Frisch
21
22-->
23<interface>
24 <requires lib="gtk+" version="3.24"/>
25 <object class="GtkBox" id="chat_box">
26 <property name="visible">True</property>
27 <property name="can-focus">False</property>
28 <property name="orientation">vertical</property>
29 <child>
30 <object class="GtkBox" id="chat-header-box">
31 <property name="visible">True</property>
32 <property name="can-focus">False</property>
33 <property name="margin-start">8</property>
34 <property name="margin-end">8</property>
35 <property name="margin-top">8</property>
36 <property name="margin-bottom">8</property>
37 <property name="spacing">8</property>
38 <child>
39 <object class="GtkButton" id="back_button">
40 <property name="visible">True</property>
41 <property name="can-focus">True</property>
42 <property name="receives-default">True</property>
43 <property name="relief">none</property>
44 <child>
45 <object class="GtkImage">
46 <property name="visible">True</property>
47 <property name="can-focus">False</property>
48 <property name="icon-name">go-previous-symbolic</property>
49 </object>
50 </child>
51 </object>
52 <packing>
53 <property name="expand">False</property>
54 <property name="fill">True</property>
55 <property name="position">0</property>
56 </packing>
57 </child>
58 <child>
59 <object class="GtkBox">
60 <property name="visible">True</property>
61 <property name="can-focus">False</property>
62 <property name="halign">start</property>
63 <property name="margin-start">4</property>
64 <property name="margin-end">4</property>
65 <property name="orientation">vertical</property>
66 <child>
67 <object class="GtkLabel" id="chat_title">
68 <property name="visible">True</property>
69 <property name="can-focus">False</property>
70 <property name="label" translatable="yes">Chat title</property>
71 <property name="xalign">0</property>
72 <attributes>
73 <attribute name="weight" value="bold"/>
74 </attributes>
75 </object>
76 <packing>
77 <property name="expand">False</property>
78 <property name="fill">True</property>
79 <property name="position">0</property>
80 </packing>
81 </child>
82 <child>
83 <object class="GtkLabel" id="chat_subtitle">
84 <property name="visible">True</property>
85 <property name="can-focus">False</property>
86 <property name="label" translatable="yes">Chat subtitle</property>
87 <property name="xalign">0</property>
88 <attributes>
89 <attribute name="weight" value="light"/>
90 </attributes>
91 </object>
92 <packing>
93 <property name="expand">True</property>
94 <property name="fill">True</property>
95 <property name="position">1</property>
96 </packing>
97 </child>
98 </object>
99 <packing>
100 <property name="expand">True</property>
101 <property name="fill">True</property>
102 <property name="position">1</property>
103 </packing>
104 </child>
105 <child>
106 <object class="GtkButton" id="chat_details_button">
107 <property name="visible">True</property>
108 <property name="can-focus">True</property>
109 <property name="receives-default">True</property>
110 <property name="relief">none</property>
111 <child>
112 <object class="GtkImage">
113 <property name="visible">True</property>
114 <property name="can-focus">False</property>
115 <property name="icon-name">view-more-symbolic</property>
116 </object>
117 </child>
118 </object>
119 <packing>
120 <property name="expand">False</property>
121 <property name="fill">True</property>
122 <property name="pack-type">end</property>
123 <property name="position">1</property>
124 </packing>
125 </child>
126 </object>
127 <packing>
128 <property name="expand">False</property>
129 <property name="fill">True</property>
130 <property name="position">0</property>
131 </packing>
132 </child>
133 <child>
134 <object class="GtkScrolledWindow">
135 <property name="visible">True</property>
136 <property name="can-focus">True</property>
137 <child>
138 <object class="GtkViewport">
139 <property name="visible">True</property>
140 <property name="can-focus">False</property>
141 <child>
142 <object class="GtkStack">
143 <property name="visible">True</property>
144 <property name="can-focus">False</property>
145 <child>
146 <object class="GtkListBox" id="messages_listbox">
147 <property name="visible">True</property>
148 <property name="can-focus">False</property>
149 <property name="selection-mode">none</property>
150 <property name="activate-on-single-click">False</property>
151 </object>
152 <packing>
153 <property name="name">page0</property>
154 <property name="title" translatable="yes">page0</property>
155 </packing>
156 </child>
157 </object>
158 </child>
159 </object>
160 </child>
161 </object>
162 <packing>
163 <property name="expand">True</property>
164 <property name="fill">True</property>
165 <property name="position">1</property>
166 </packing>
167 </child>
168 <child>
169 <object class="GtkBox">
170 <property name="visible">True</property>
171 <property name="can-focus">False</property>
172 <property name="margin-start">8</property>
173 <property name="margin-end">8</property>
174 <property name="margin-top">4</property>
175 <property name="margin-bottom">4</property>
176 <property name="spacing">4</property>
177 <child>
178 <object class="GtkButton" id="attach_file_button">
179 <property name="visible">True</property>
180 <property name="can-focus">True</property>
181 <property name="receives-default">True</property>
182 <property name="valign">center</property>
183 <property name="relief">none</property>
184 <child>
185 <object class="GtkImage">
186 <property name="visible">True</property>
187 <property name="can-focus">False</property>
188 <property name="icon-name">mail-attachment-symbolic</property>
189 </object>
190 </child>
191 </object>
192 <packing>
193 <property name="expand">False</property>
194 <property name="fill">True</property>
195 <property name="position">0</property>
196 </packing>
197 </child>
198 <child>
199 <object class="GtkTextView" id="send_text_view">
200 <property name="width-request">210</property>
201 <property name="height-request">48</property>
202 <property name="visible">True</property>
203 <property name="can-focus">True</property>
204 <property name="valign">end</property>
205 <property name="wrap-mode">word-char</property>
206 <property name="left-margin">8</property>
207 <property name="right-margin">8</property>
208 <property name="top-margin">8</property>
209 <property name="bottom-margin">8</property>
210 <property name="input-hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_WORD_COMPLETION | GTK_INPUT_HINT_INHIBIT_OSK | GTK_INPUT_HINT_EMOJI | GTK_INPUT_HINT_NONE</property>
211 </object>
212 <packing>
213 <property name="expand">True</property>
214 <property name="fill">True</property>
215 <property name="position">1</property>
216 </packing>
217 </child>
218 <child>
219 <object class="GtkButton" id="emoji_button">
220 <property name="visible">True</property>
221 <property name="can-focus">True</property>
222 <property name="receives-default">True</property>
223 <property name="valign">center</property>
224 <property name="relief">none</property>
225 <child>
226 <object class="GtkImage">
227 <property name="visible">True</property>
228 <property name="can-focus">False</property>
229 <property name="icon-name">face-smile-symbolic</property>
230 </object>
231 </child>
232 </object>
233 <packing>
234 <property name="expand">False</property>
235 <property name="fill">True</property>
236 <property name="position">2</property>
237 </packing>
238 </child>
239 <child>
240 <object class="GtkButton" id="send_record_button">
241 <property name="visible">True</property>
242 <property name="can-focus">True</property>
243 <property name="receives-default">True</property>
244 <property name="valign">center</property>
245 <property name="relief">none</property>
246 <child>
247 <object class="GtkImage" id="send_record_symbol">
248 <property name="visible">True</property>
249 <property name="can-focus">False</property>
250 <property name="icon-name">audio-input-microphone-symbolic</property>
251 </object>
252 </child>
253 </object>
254 <packing>
255 <property name="expand">False</property>
256 <property name="fill">True</property>
257 <property name="position">3</property>
258 </packing>
259 </child>
260 </object>
261 <packing>
262 <property name="expand">False</property>
263 <property name="fill">True</property>
264 <property name="position">2</property>
265 </packing>
266 </child>
267 </object>
268</interface>
diff --git a/resources/ui/messenger.ui b/resources/ui/messenger.ui
index 79ea388..1c9b2cd 100644
--- a/resources/ui/messenger.ui
+++ b/resources/ui/messenger.ui
@@ -717,248 +717,12 @@ Author: Tobias Frisch
717 <property name="flap-position">end</property> 717 <property name="flap-position">end</property>
718 <property name="reveal-flap">False</property> 718 <property name="reveal-flap">False</property>
719 <property name="fold-policy">always</property> 719 <property name="fold-policy">always</property>
720 <child type="content"> 720 <child>
721 <object class="GtkBox"> 721 <object class="GtkStack" id="chats_stack">
722 <property name="visible">True</property> 722 <property name="visible">True</property>
723 <property name="can-focus">False</property> 723 <property name="can-focus">False</property>
724 <property name="orientation">vertical</property>
725 <child> 724 <child>
726 <object class="GtkBox" id="chat-header-box"> 725 <placeholder/>
727 <property name="visible">True</property>
728 <property name="can-focus">False</property>
729 <property name="margin-start">8</property>
730 <property name="margin-end">8</property>
731 <property name="margin-top">8</property>
732 <property name="margin-bottom">8</property>
733 <property name="spacing">8</property>
734 <child>
735 <object class="GtkButton" id="back_button">
736 <property name="visible">True</property>
737 <property name="can-focus">True</property>
738 <property name="receives-default">True</property>
739 <property name="relief">none</property>
740 <child>
741 <object class="GtkImage">
742 <property name="visible">True</property>
743 <property name="can-focus">False</property>
744 <property name="icon-name">go-previous-symbolic</property>
745 </object>
746 </child>
747 </object>
748 <packing>
749 <property name="expand">False</property>
750 <property name="fill">True</property>
751 <property name="position">0</property>
752 </packing>
753 </child>
754 <child>
755 <object class="GtkBox">
756 <property name="visible">True</property>
757 <property name="can-focus">False</property>
758 <property name="halign">start</property>
759 <property name="margin-start">4</property>
760 <property name="margin-end">4</property>
761 <property name="orientation">vertical</property>
762 <child>
763 <object class="GtkLabel" id="chat_title">
764 <property name="visible">True</property>
765 <property name="can-focus">False</property>
766 <property name="label" translatable="yes">Chat title</property>
767 <property name="xalign">0</property>
768 <attributes>
769 <attribute name="weight" value="bold"/>
770 </attributes>
771 </object>
772 <packing>
773 <property name="expand">False</property>
774 <property name="fill">True</property>
775 <property name="position">0</property>
776 </packing>
777 </child>
778 <child>
779 <object class="GtkLabel" id="chat_subtitle">
780 <property name="visible">True</property>
781 <property name="can-focus">False</property>
782 <property name="label" translatable="yes">Chat subtitle</property>
783 <property name="xalign">0</property>
784 <attributes>
785 <attribute name="weight" value="light"/>
786 </attributes>
787 </object>
788 <packing>
789 <property name="expand">True</property>
790 <property name="fill">True</property>
791 <property name="position">1</property>
792 </packing>
793 </child>
794 </object>
795 <packing>
796 <property name="expand">True</property>
797 <property name="fill">True</property>
798 <property name="position">1</property>
799 </packing>
800 </child>
801 <child>
802 <object class="GtkButton" id="chat_details_button">
803 <property name="visible">True</property>
804 <property name="can-focus">True</property>
805 <property name="receives-default">True</property>
806 <property name="relief">none</property>
807 <child>
808 <object class="GtkImage">
809 <property name="visible">True</property>
810 <property name="can-focus">False</property>
811 <property name="icon-name">view-more-symbolic</property>
812 </object>
813 </child>
814 </object>
815 <packing>
816 <property name="expand">False</property>
817 <property name="fill">True</property>
818 <property name="pack-type">end</property>
819 <property name="position">1</property>
820 </packing>
821 </child>
822 </object>
823 <packing>
824 <property name="expand">False</property>
825 <property name="fill">True</property>
826 <property name="position">0</property>
827 </packing>
828 </child>
829 <child>
830 <object class="GtkScrolledWindow">
831 <property name="visible">True</property>
832 <property name="can-focus">True</property>
833 <child>
834 <object class="GtkViewport">
835 <property name="visible">True</property>
836 <property name="can-focus">False</property>
837 <child>
838 <object class="GtkStack">
839 <property name="visible">True</property>
840 <property name="can-focus">False</property>
841 <child>
842 <object class="GtkListBox" id="messages_listbox">
843 <property name="visible">True</property>
844 <property name="can-focus">False</property>
845 <property name="selection-mode">none</property>
846 <property name="activate-on-single-click">False</property>
847 </object>
848 <packing>
849 <property name="name">page0</property>
850 <property name="title" translatable="yes">page0</property>
851 </packing>
852 </child>
853 </object>
854 </child>
855 </object>
856 </child>
857 </object>
858 <packing>
859 <property name="expand">True</property>
860 <property name="fill">True</property>
861 <property name="position">1</property>
862 </packing>
863 </child>
864 <child>
865 <object class="GtkBox">
866 <property name="visible">True</property>
867 <property name="can-focus">False</property>
868 <property name="margin-start">8</property>
869 <property name="margin-end">8</property>
870 <property name="margin-top">4</property>
871 <property name="margin-bottom">4</property>
872 <property name="spacing">4</property>
873 <child>
874 <object class="GtkButton" id="attach_file_button">
875 <property name="visible">True</property>
876 <property name="can-focus">True</property>
877 <property name="receives-default">True</property>
878 <property name="valign">center</property>
879 <property name="relief">none</property>
880 <child>
881 <object class="GtkImage">
882 <property name="visible">True</property>
883 <property name="can-focus">False</property>
884 <property name="icon-name">mail-attachment-symbolic</property>
885 </object>
886 </child>
887 </object>
888 <packing>
889 <property name="expand">False</property>
890 <property name="fill">True</property>
891 <property name="position">0</property>
892 </packing>
893 </child>
894 <child>
895 <object class="GtkTextView" id="send_text_view">
896 <property name="width-request">210</property>
897 <property name="height-request">48</property>
898 <property name="visible">True</property>
899 <property name="can-focus">True</property>
900 <property name="valign">end</property>
901 <property name="wrap-mode">word-char</property>
902 <property name="left-margin">8</property>
903 <property name="right-margin">8</property>
904 <property name="top-margin">8</property>
905 <property name="bottom-margin">8</property>
906 <property name="input-hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_WORD_COMPLETION | GTK_INPUT_HINT_INHIBIT_OSK | GTK_INPUT_HINT_EMOJI | GTK_INPUT_HINT_NONE</property>
907 </object>
908 <packing>
909 <property name="expand">True</property>
910 <property name="fill">True</property>
911 <property name="position">1</property>
912 </packing>
913 </child>
914 <child>
915 <object class="GtkButton" id="emoji_button">
916 <property name="visible">True</property>
917 <property name="can-focus">True</property>
918 <property name="receives-default">True</property>
919 <property name="valign">center</property>
920 <property name="relief">none</property>
921 <child>
922 <object class="GtkImage">
923 <property name="visible">True</property>
924 <property name="can-focus">False</property>
925 <property name="icon-name">face-smile-symbolic</property>
926 </object>
927 </child>
928 </object>
929 <packing>
930 <property name="expand">False</property>
931 <property name="fill">True</property>
932 <property name="position">2</property>
933 </packing>
934 </child>
935 <child>
936 <object class="GtkButton" id="send_record_button">
937 <property name="visible">True</property>
938 <property name="can-focus">True</property>
939 <property name="receives-default">True</property>
940 <property name="valign">center</property>
941 <property name="relief">none</property>
942 <child>
943 <object class="GtkImage" id="send_record_symbol">
944 <property name="visible">True</property>
945 <property name="can-focus">False</property>
946 <property name="icon-name">audio-input-microphone-symbolic</property>
947 </object>
948 </child>
949 </object>
950 <packing>
951 <property name="expand">False</property>
952 <property name="fill">True</property>
953 <property name="position">3</property>
954 </packing>
955 </child>
956 </object>
957 <packing>
958 <property name="expand">False</property>
959 <property name="fill">True</property>
960 <property name="position">2</property>
961 </packing>
962 </child> 726 </child>
963 </object> 727 </object>
964 </child> 728 </child>
@@ -1108,12 +872,4 @@ Author: Tobias Frisch
1108 <widget name="settings-label"/> 872 <widget name="settings-label"/>
1109 </widgets> 873 </widgets>
1110 </object> 874 </object>
1111 <object class="GtkSizeGroup">
1112 <property name="mode">vertical</property>
1113 <widgets>
1114 <widget name="chats-header-box"/>
1115 <widget name="chat-header-box"/>
1116 <widget name="details-header-box"/>
1117 </widgets>
1118 </object>
1119</interface> 875</interface>
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
54void 54void
@@ -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
30static int 30static 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
60static 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
107void 115void
@@ -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
142void 131void
@@ -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
30static void
31handle_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
43static void
44handle_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
56static void
57handle_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
77static 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
103static void
104handle_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
119static gboolean
120handle_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
135UI_CHAT_Handle*
136ui_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
245void
246ui_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
32typedef struct MESSENGER_Application MESSENGER_Application;
33
34typedef 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
53UI_CHAT_Handle*
54ui_chat_new(MESSENGER_Application *app);
55
56void
57ui_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
27UI_CHAT_ENTRY_Handle* 29UI_CHAT_ENTRY_Handle*
28ui_chat_entry_new(void) 30ui_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
65void
66ui_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
31typedef struct MESSENGER_Application MESSENGER_Application;
32 29
33typedef struct UI_CHAT_ENTRY_Handle 30typedef 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
46UI_CHAT_ENTRY_Handle* 45UI_CHAT_ENTRY_Handle*
47ui_chat_entry_new(void); 46ui_chat_entry_new(MESSENGER_Application *app);
47
48void
49ui_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
81static void 82static void
82handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox, 83handle_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
95static void
96handle_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
108static void
109handle_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
129static void
130handle_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
162static gboolean 98 GtkWidget *entry = GTK_WIDGET(
163handle_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
197static void 105static void
@@ -207,6 +115,8 @@ void
207ui_messenger_init(MESSENGER_Application *app, 115ui_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
294static 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
467void 302void
468ui_messenger_run(MESSENGER_Application *app) 303ui_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
34typedef struct UI_MESSENGER_Handle 34typedef 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
81void 72void
@@ -83,6 +74,6 @@ ui_messenger_init(MESSENGER_Application *app,
83 UI_MESSENGER_Handle *handle); 74 UI_MESSENGER_Handle *handle);
84 75
85void 76void
86ui_messenger_run(MESSENGER_Application *app); 77ui_messenger_cleanup(UI_MESSENGER_Handle *handle);
87 78
88#endif /* UI_MESSENGER_H_ */ 79#endif /* UI_MESSENGER_H_ */