aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheJackiMonster <thejackimonster@gmail.com>2021-12-21 18:59:39 +0100
committerTheJackiMonster <thejackimonster@gmail.com>2021-12-21 18:59:39 +0100
commitbd545ea846e668112e5a54b702acc9c9f9231aea (patch)
tree1b0c6ccadd11ac4e98ef597fc36e8a640c834a43
parentd8a0d99da00d29ae50a0a8831d1d396769ed94f6 (diff)
downloadmessenger-gtk-bd545ea846e668112e5a54b702acc9c9f9231aea.tar.gz
messenger-gtk-bd545ea846e668112e5a54b702acc9c9f9231aea.zip
Implemented preview for sending files and added ui for message content
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r--resources/css/style.css4
-rw-r--r--resources/ui/message-sent.ui59
-rw-r--r--resources/ui/message-status.ui106
-rw-r--r--resources/ui/message.ui58
-rw-r--r--resources/ui/message_content.ui187
-rw-r--r--resources/ui/send_file.ui1
-rw-r--r--src/event.c19
-rw-r--r--src/ui/chat.c15
-rw-r--r--src/ui/chat.h2
-rw-r--r--src/ui/message.c65
-rw-r--r--src/ui/message.h17
-rw-r--r--src/ui/new_contact.c2
-rw-r--r--src/ui/send_file.c176
-rw-r--r--src/ui/send_file.h6
14 files changed, 512 insertions, 205 deletions
diff --git a/resources/css/style.css b/resources/css/style.css
index afda9fe..084a639 100644
--- a/resources/css/style.css
+++ b/resources/css/style.css
@@ -61,6 +61,10 @@
61 padding: 2px 4px; 61 padding: 2px 4px;
62} 62}
63 63
64.timestamp-label {
65 font-size: x-small;
66}
67
64.picker-switcher-box { 68.picker-switcher-box {
65 padding: 0px 8px; 69 padding: 0px 8px;
66} 70}
diff --git a/resources/ui/message-sent.ui b/resources/ui/message-sent.ui
index 25ac52c..6e939ea 100644
--- a/resources/ui/message-sent.ui
+++ b/resources/ui/message-sent.ui
@@ -50,68 +50,13 @@ Author: Tobias Frisch
50 <property name="label-xalign">0</property> 50 <property name="label-xalign">0</property>
51 <property name="shadow-type">none</property> 51 <property name="shadow-type">none</property>
52 <child> 52 <child>
53 <object class="GtkBox"> 53 <object class="GtkBox" id="content_box">
54 <property name="visible">True</property> 54 <property name="visible">True</property>
55 <property name="can-focus">False</property> 55 <property name="can-focus">False</property>
56 <property name="orientation">vertical</property> 56 <property name="orientation">vertical</property>
57 <property name="spacing">4</property>
58 <child> 57 <child>
59 <object class="GtkLabel" id="text_label"> 58 <placeholder/>
60 <property name="visible">True</property>
61 <property name="can-focus">False</property>
62 <property name="wrap">True</property>
63 <property name="max-width-chars">64</property>
64 <property name="xalign">0</property>
65 </object>
66 <packing>
67 <property name="expand">True</property>
68 <property name="fill">True</property>
69 <property name="position">0</property>
70 </packing>
71 </child> 59 </child>
72 <child>
73 <object class="GtkBox">
74 <property name="visible">True</property>
75 <property name="can-focus">False</property>
76 <property name="spacing">4</property>
77 <child>
78 <object class="GtkImage" id="read_receipt_image">
79 <property name="visible">True</property>
80 <property name="can-focus">False</property>
81 <property name="icon-name">emblem-default-symbolic</property>
82 </object>
83 <packing>
84 <property name="expand">False</property>
85 <property name="fill">True</property>
86 <property name="pack-type">end</property>
87 <property name="position">0</property>
88 </packing>
89 </child>
90 <child>
91 <object class="GtkLabel" id="timestamp_label">
92 <property name="visible">True</property>
93 <property name="can-focus">False</property>
94 <attributes>
95 <attribute name="weight" value="light"/>
96 </attributes>
97 </object>
98 <packing>
99 <property name="expand">False</property>
100 <property name="fill">True</property>
101 <property name="pack-type">end</property>
102 <property name="position">1</property>
103 </packing>
104 </child>
105 </object>
106 <packing>
107 <property name="expand">False</property>
108 <property name="fill">True</property>
109 <property name="position">1</property>
110 </packing>
111 </child>
112 <style>
113 <class name="message-content"/>
114 </style>
115 </object> 60 </object>
116 </child> 61 </child>
117 <child type="label"> 62 <child type="label">
diff --git a/resources/ui/message-status.ui b/resources/ui/message-status.ui
index fb2057e..8536162 100644
--- a/resources/ui/message-status.ui
+++ b/resources/ui/message-status.ui
@@ -39,15 +39,23 @@ Author: Tobias Frisch
39 <property name="can-focus">False</property> 39 <property name="can-focus">False</property>
40 <property name="spacing">8</property> 40 <property name="spacing">8</property>
41 <child> 41 <child>
42 <object class="GtkButton" id="deny_button"> 42 <object class="GtkRevealer" id="deny_revealer">
43 <property name="can-focus">True</property> 43 <property name="visible">True</property>
44 <property name="receives-default">True</property> 44 <property name="can-focus">False</property>
45 <property name="relief">none</property> 45 <property name="transition-type">slide-left</property>
46 <property name="reveal-child">True</property>
46 <child> 47 <child>
47 <object class="GtkImage"> 48 <object class="GtkButton" id="deny_button">
48 <property name="visible">True</property> 49 <property name="can-focus">True</property>
49 <property name="can-focus">False</property> 50 <property name="receives-default">True</property>
50 <property name="icon-name">edit-delete-symbolic</property> 51 <property name="relief">none</property>
52 <child>
53 <object class="GtkImage">
54 <property name="visible">True</property>
55 <property name="can-focus">False</property>
56 <property name="icon-name">edit-delete-symbolic</property>
57 </object>
58 </child>
51 </object> 59 </object>
52 </child> 60 </child>
53 </object> 61 </object>
@@ -58,65 +66,12 @@ Author: Tobias Frisch
58 </packing> 66 </packing>
59 </child> 67 </child>
60 <child> 68 <child>
61 <object class="GtkBox"> 69 <object class="GtkBox" id="content_box">
62 <property name="visible">True</property> 70 <property name="visible">True</property>
63 <property name="can-focus">False</property> 71 <property name="can-focus">False</property>
64 <property name="orientation">vertical</property> 72 <property name="orientation">vertical</property>
65 <child> 73 <child>
66 <object class="GtkLabel" id="text_label"> 74 <placeholder/>
67 <property name="visible">True</property>
68 <property name="can-focus">False</property>
69 <property name="justify">center</property>
70 <property name="wrap">True</property>
71 <property name="xalign">0.5</property>
72 </object>
73 <packing>
74 <property name="expand">True</property>
75 <property name="fill">True</property>
76 <property name="position">0</property>
77 </packing>
78 </child>
79 <child>
80 <object class="GtkBox">
81 <property name="visible">True</property>
82 <property name="can-focus">False</property>
83 <property name="spacing">4</property>
84 <child>
85 <object class="GtkImage" id="read_receipt_image">
86 <property name="can-focus">False</property>
87 <property name="xalign">1</property>
88 <property name="icon-name">emblem-default-symbolic</property>
89 </object>
90 <packing>
91 <property name="expand">False</property>
92 <property name="fill">True</property>
93 <property name="pack-type">end</property>
94 <property name="position">0</property>
95 </packing>
96 </child>
97 <child>
98 <object class="GtkLabel" id="timestamp_label">
99 <property name="can-focus">False</property>
100 <property name="justify">right</property>
101 <property name="xalign">1</property>
102 <attributes>
103 <attribute name="weight" value="light"/>
104 </attributes>
105 </object>
106 <packing>
107 <property name="expand">False</property>
108 <property name="fill">True</property>
109 <property name="pack-type">end</property>
110 <property name="position">1</property>
111 </packing>
112 </child>
113 </object>
114 <packing>
115 <property name="expand">False</property>
116 <property name="fill">True</property>
117 <property name="pack-type">end</property>
118 <property name="position">1</property>
119 </packing>
120 </child> 75 </child>
121 </object> 76 </object>
122 <packing> 77 <packing>
@@ -126,22 +81,29 @@ Author: Tobias Frisch
126 </packing> 81 </packing>
127 </child> 82 </child>
128 <child> 83 <child>
129 <object class="GtkButton" id="accept_button"> 84 <object class="GtkRevealer" id="accept_revealer">
130 <property name="can-focus">True</property> 85 <property name="visible">True</property>
131 <property name="receives-default">True</property> 86 <property name="can-focus">False</property>
132 <property name="relief">none</property> 87 <property name="transition-type">slide-right</property>
88 <property name="reveal-child">True</property>
133 <child> 89 <child>
134 <object class="GtkImage"> 90 <object class="GtkButton" id="accept_button">
135 <property name="visible">True</property> 91 <property name="can-focus">True</property>
136 <property name="can-focus">False</property> 92 <property name="receives-default">True</property>
137 <property name="icon-name">emblem-ok-symbolic</property> 93 <property name="relief">none</property>
94 <child>
95 <object class="GtkImage">
96 <property name="visible">True</property>
97 <property name="can-focus">False</property>
98 <property name="icon-name">emblem-ok-symbolic</property>
99 </object>
100 </child>
138 </object> 101 </object>
139 </child> 102 </child>
140 </object> 103 </object>
141 <packing> 104 <packing>
142 <property name="expand">False</property> 105 <property name="expand">False</property>
143 <property name="fill">True</property> 106 <property name="fill">True</property>
144 <property name="pack-type">end</property>
145 <property name="position">2</property> 107 <property name="position">2</property>
146 </packing> 108 </packing>
147 </child> 109 </child>
diff --git a/resources/ui/message.ui b/resources/ui/message.ui
index 42bde4d..9e501c8 100644
--- a/resources/ui/message.ui
+++ b/resources/ui/message.ui
@@ -49,67 +49,13 @@ Author: Tobias Frisch
49 <property name="label-xalign">0</property> 49 <property name="label-xalign">0</property>
50 <property name="shadow-type">none</property> 50 <property name="shadow-type">none</property>
51 <child> 51 <child>
52 <object class="GtkBox"> 52 <object class="GtkBox" id="content_box">
53 <property name="visible">True</property> 53 <property name="visible">True</property>
54 <property name="can-focus">False</property> 54 <property name="can-focus">False</property>
55 <property name="orientation">vertical</property> 55 <property name="orientation">vertical</property>
56 <property name="spacing">4</property>
57 <child> 56 <child>
58 <object class="GtkLabel" id="text_label"> 57 <placeholder/>
59 <property name="visible">True</property>
60 <property name="can-focus">False</property>
61 <property name="wrap">True</property>
62 <property name="max-width-chars">64</property>
63 <property name="xalign">0</property>
64 </object>
65 <packing>
66 <property name="expand">True</property>
67 <property name="fill">True</property>
68 <property name="position">0</property>
69 </packing>
70 </child> 58 </child>
71 <child>
72 <object class="GtkBox">
73 <property name="visible">True</property>
74 <property name="can-focus">False</property>
75 <property name="spacing">4</property>
76 <child>
77 <object class="GtkImage" id="read_receipt_image">
78 <property name="can-focus">False</property>
79 <property name="icon-name">emblem-default-symbolic</property>
80 </object>
81 <packing>
82 <property name="expand">False</property>
83 <property name="fill">True</property>
84 <property name="pack-type">end</property>
85 <property name="position">0</property>
86 </packing>
87 </child>
88 <child>
89 <object class="GtkLabel" id="timestamp_label">
90 <property name="visible">True</property>
91 <property name="can-focus">False</property>
92 <attributes>
93 <attribute name="weight" value="light"/>
94 </attributes>
95 </object>
96 <packing>
97 <property name="expand">False</property>
98 <property name="fill">True</property>
99 <property name="pack-type">end</property>
100 <property name="position">1</property>
101 </packing>
102 </child>
103 </object>
104 <packing>
105 <property name="expand">False</property>
106 <property name="fill">True</property>
107 <property name="position">1</property>
108 </packing>
109 </child>
110 <style>
111 <class name="message-content"/>
112 </style>
113 </object> 59 </object>
114 </child> 60 </child>
115 <child type="label"> 61 <child type="label">
diff --git a/resources/ui/message_content.ui b/resources/ui/message_content.ui
new file mode 100644
index 0000000..bca5165
--- /dev/null
+++ b/resources/ui/message_content.ui
@@ -0,0 +1,187 @@
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="message_content_box">
26 <property name="visible">True</property>
27 <property name="can-focus">False</property>
28 <property name="orientation">vertical</property>
29 <property name="spacing">4</property>
30 <child>
31 <object class="GtkBox">
32 <property name="visible">True</property>
33 <property name="can-focus">False</property>
34 <property name="spacing">4</property>
35 <child>
36 <object class="GtkImage" id="read_receipt_image">
37 <property name="can-focus">False</property>
38 <property name="icon-name">emblem-default-symbolic</property>
39 </object>
40 <packing>
41 <property name="expand">False</property>
42 <property name="fill">True</property>
43 <property name="pack-type">end</property>
44 <property name="position">0</property>
45 </packing>
46 </child>
47 <child>
48 <object class="GtkLabel" id="timestamp_label">
49 <property name="visible">True</property>
50 <property name="can-focus">False</property>
51 <attributes>
52 <attribute name="weight" value="ultralight"/>
53 </attributes>
54 <style>
55 <class name="timestamp-label"/>
56 </style>
57 </object>
58 <packing>
59 <property name="expand">False</property>
60 <property name="fill">True</property>
61 <property name="pack-type">end</property>
62 <property name="position">1</property>
63 </packing>
64 </child>
65 </object>
66 <packing>
67 <property name="expand">False</property>
68 <property name="fill">True</property>
69 <property name="pack-type">end</property>
70 <property name="position">0</property>
71 </packing>
72 </child>
73 <child>
74 <object class="GtkStack">
75 <property name="visible">True</property>
76 <property name="can-focus">False</property>
77 <child>
78 <object class="GtkLabel" id="text_label">
79 <property name="visible">True</property>
80 <property name="can-focus">False</property>
81 <property name="wrap">True</property>
82 <property name="max-width-chars">64</property>
83 <property name="xalign">0</property>
84 </object>
85 <packing>
86 <property name="name">text_page</property>
87 </packing>
88 </child>
89 <child>
90 <object class="GtkRevealer" id="file_revealer">
91 <property name="visible">True</property>
92 <property name="can-focus">False</property>
93 <property name="transition-type">none</property>
94 <child>
95 <object class="GtkBox">
96 <property name="visible">True</property>
97 <property name="can-focus">False</property>
98 <property name="spacing">4</property>
99 <child>
100 <object class="GtkBox">
101 <property name="visible">True</property>
102 <property name="can-focus">False</property>
103 <property name="valign">center</property>
104 <property name="orientation">vertical</property>
105 <property name="spacing">4</property>
106 <child>
107 <object class="GtkLabel" id="filename_label">
108 <property name="visible">True</property>
109 <property name="can-focus">False</property>
110 </object>
111 <packing>
112 <property name="expand">False</property>
113 <property name="fill">True</property>
114 <property name="position">0</property>
115 </packing>
116 </child>
117 <child>
118 <object class="GtkProgressBar">
119 <property name="visible">True</property>
120 <property name="can-focus">False</property>
121 </object>
122 <packing>
123 <property name="expand">False</property>
124 <property name="fill">True</property>
125 <property name="position">1</property>
126 </packing>
127 </child>
128 </object>
129 <packing>
130 <property name="expand">True</property>
131 <property name="fill">True</property>
132 <property name="position">0</property>
133 </packing>
134 </child>
135 <child>
136 <object class="GtkButton" id="file_button">
137 <property name="visible">True</property>
138 <property name="can-focus">True</property>
139 <property name="receives-default">True</property>
140 <property name="halign">center</property>
141 <property name="valign">center</property>
142 <property name="relief">none</property>
143 <child>
144 <object class="GtkImage">
145 <property name="visible">True</property>
146 <property name="can-focus">False</property>
147 <property name="icon-name">folder-download-symbolic</property>
148 </object>
149 </child>
150 </object>
151 <packing>
152 <property name="expand">False</property>
153 <property name="fill">True</property>
154 <property name="pack-type">end</property>
155 <property name="position">1</property>
156 </packing>
157 </child>
158 </object>
159 </child>
160 </object>
161 <packing>
162 <property name="name">file_page</property>
163 <property name="position">1</property>
164 </packing>
165 </child>
166 <child>
167 <object class="GtkDrawingArea" id="preview_drawing_area">
168 <property name="visible">True</property>
169 <property name="can-focus">False</property>
170 </object>
171 <packing>
172 <property name="name">preview_page</property>
173 <property name="position">2</property>
174 </packing>
175 </child>
176 </object>
177 <packing>
178 <property name="expand">True</property>
179 <property name="fill">True</property>
180 <property name="position">1</property>
181 </packing>
182 </child>
183 <style>
184 <class name="message-content"/>
185 </style>
186 </object>
187</interface>
diff --git a/resources/ui/send_file.ui b/resources/ui/send_file.ui
index 38bd5e8..5603aea 100644
--- a/resources/ui/send_file.ui
+++ b/resources/ui/send_file.ui
@@ -78,6 +78,7 @@ Author: Tobias Frisch
78 <property name="spacing">4</property> 78 <property name="spacing">4</property>
79 <child> 79 <child>
80 <object class="GtkDrawingArea" id="file_drawing_area"> 80 <object class="GtkDrawingArea" id="file_drawing_area">
81 <property name="width-request">250</property>
81 <property name="height-request">250</property> 82 <property name="height-request">250</property>
82 <property name="visible">True</property> 83 <property name="visible">True</property>
83 <property name="can-focus">False</property> 84 <property name="can-focus">False</property>
diff --git a/src/event.c b/src/event.c
index c3e4ac6..2280785 100644
--- a/src/event.c
+++ b/src/event.c
@@ -190,7 +190,10 @@ event_joining_contact(MESSENGER_Application *app,
190 190
191 ui_chat_entry_update(handle, app, context); 191 ui_chat_entry_update(handle, app, context);
192 192
193 UI_MESSAGE_Handle *message = ui_message_new(UI_MESSAGE_STATUS); 193 UI_MESSAGE_Handle *message = ui_message_new(
194 UI_MESSAGE_STATUS,
195 UI_MESSAGE_CONTENT_TEXT
196 );
194 197
195 struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( 198 struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender(
196 msg 199 msg
@@ -209,7 +212,7 @@ event_joining_contact(MESSENGER_Application *app,
209 message->message_box 212 message->message_box
210 ); 213 );
211 214
212 ui_message_delete(message); 215 handle->chat->messages = g_list_append(handle->chat->messages, message);
213} 216}
214 217
215void 218void
@@ -259,7 +262,10 @@ event_invitation(UNUSED MESSENGER_Application *app,
259 if (!invitation) 262 if (!invitation)
260 return; 263 return;
261 264
262 UI_MESSAGE_Handle *message = ui_message_new(UI_MESSAGE_STATUS); 265 UI_MESSAGE_Handle *message = ui_message_new(
266 UI_MESSAGE_STATUS,
267 UI_MESSAGE_CONTENT_TEXT
268 );
263 269
264 const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( 270 const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender(
265 msg 271 msg
@@ -285,7 +291,7 @@ event_invitation(UNUSED MESSENGER_Application *app,
285 message->message_box 291 message->message_box
286 ); 292 );
287 293
288 ui_message_delete(message); 294 handle->chat->messages = g_list_append(handle->chat->messages, message);
289} 295}
290 296
291void 297void
@@ -301,7 +307,8 @@ event_receive_message(UNUSED MESSENGER_Application *app,
301 const int sent = GNUNET_CHAT_message_is_sent(msg); 307 const int sent = GNUNET_CHAT_message_is_sent(msg);
302 308
303 UI_MESSAGE_Handle *message = ui_message_new( 309 UI_MESSAGE_Handle *message = ui_message_new(
304 GNUNET_YES == sent? UI_MESSAGE_SENT : UI_MESSAGE_DEFAULT 310 GNUNET_YES == sent? UI_MESSAGE_SENT : UI_MESSAGE_DEFAULT,
311 UI_MESSAGE_CONTENT_TEXT
305 ); 312 );
306 313
307 const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( 314 const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender(
@@ -329,7 +336,7 @@ event_receive_message(UNUSED MESSENGER_Application *app,
329 message->message_box 336 message->message_box
330 ); 337 );
331 338
332 ui_message_delete(message); 339 handle->chat->messages = g_list_append(handle->chat->messages, message);
333 340
334 gtk_label_set_text(handle->text_label, text? text : ""); 341 gtk_label_set_text(handle->text_label, text? text : "");
335 gtk_label_set_text(handle->timestamp_label, time? time : ""); 342 gtk_label_set_text(handle->timestamp_label, time? time : "");
diff --git a/src/ui/chat.c b/src/ui/chat.c
index a8547ba..42ccb9e 100644
--- a/src/ui/chat.c
+++ b/src/ui/chat.c
@@ -26,6 +26,7 @@
26 26
27#include <gdk/gdkkeysyms.h> 27#include <gdk/gdkkeysyms.h>
28 28
29#include "message.h"
29#include "messenger.h" 30#include "messenger.h"
30#include "picker.h" 31#include "picker.h"
31#include "profile_entry.h" 32#include "profile_entry.h"
@@ -252,6 +253,8 @@ ui_chat_new(MESSENGER_Application *app)
252 UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle)); 253 UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle));
253 UI_MESSENGER_Handle *messenger = &(app->ui.messenger); 254 UI_MESSENGER_Handle *messenger = &(app->ui.messenger);
254 255
256 handle->messages = NULL;
257
255 handle->builder = gtk_builder_new_from_file( 258 handle->builder = gtk_builder_new_from_file(
256 "resources/ui/chat.ui" 259 "resources/ui/chat.ui"
257 ); 260 );
@@ -552,5 +555,17 @@ ui_chat_delete(UI_CHAT_Handle *handle)
552 555
553 g_object_unref(handle->builder); 556 g_object_unref(handle->builder);
554 557
558 GList *list = handle->messages;
559
560 while (list) {
561 if (list->data)
562 ui_message_delete((UI_MESSAGE_Handle*) list->data);
563
564 list = list->next;
565 }
566
567 if (handle->messages)
568 g_list_free(handle->messages);
569
555 g_free(handle); 570 g_free(handle);
556} 571}
diff --git a/src/ui/chat.h b/src/ui/chat.h
index ae0880e..f065f61 100644
--- a/src/ui/chat.h
+++ b/src/ui/chat.h
@@ -36,6 +36,8 @@ typedef struct UI_PICKER_Handle UI_PICKER_Handle;
36 36
37typedef struct UI_CHAT_Handle 37typedef struct UI_CHAT_Handle
38{ 38{
39 GList *messages;
40
39 GtkBuilder *builder; 41 GtkBuilder *builder;
40 GtkWidget *chat_box; 42 GtkWidget *chat_box;
41 43
diff --git a/src/ui/message.c b/src/ui/message.c
index cacf666..4c89edb 100644
--- a/src/ui/message.c
+++ b/src/ui/message.c
@@ -27,7 +27,8 @@
27#include "../application.h" 27#include "../application.h"
28 28
29UI_MESSAGE_Handle* 29UI_MESSAGE_Handle*
30ui_message_new(UI_MESSAGE_Type type) 30ui_message_new(UI_MESSAGE_Type type,
31 UI_MESSAGE_ContentType content_type)
31{ 32{
32 UI_MESSAGE_Handle* handle = g_malloc(sizeof(UI_MESSAGE_Handle)); 33 UI_MESSAGE_Handle* handle = g_malloc(sizeof(UI_MESSAGE_Handle));
33 34
@@ -62,12 +63,16 @@ ui_message_new(UI_MESSAGE_Type type)
62 gtk_builder_get_object(handle->builder, "sender_label") 63 gtk_builder_get_object(handle->builder, "sender_label")
63 ); 64 );
64 65
65 handle->text_label = GTK_LABEL(
66 gtk_builder_get_object(handle->builder, "text_label")
67 );
68
69 if (UI_MESSAGE_STATUS == handle->type) 66 if (UI_MESSAGE_STATUS == handle->type)
70 { 67 {
68 handle->deny_revealer = GTK_REVEALER(
69 gtk_builder_get_object(handle->builder, "deny_revealer")
70 );
71
72 handle->accept_revealer = GTK_REVEALER(
73 gtk_builder_get_object(handle->builder, "accept_revealer")
74 );
75
71 handle->deny_button = GTK_BUTTON( 76 handle->deny_button = GTK_BUTTON(
72 gtk_builder_get_object(handle->builder, "deny_button") 77 gtk_builder_get_object(handle->builder, "deny_button")
73 ); 78 );
@@ -78,18 +83,64 @@ ui_message_new(UI_MESSAGE_Type type)
78 } 83 }
79 else 84 else
80 { 85 {
86 handle->deny_revealer = NULL;
87 handle->accept_revealer = NULL;
88
81 handle->deny_button = NULL; 89 handle->deny_button = NULL;
82 handle->accept_button = NULL; 90 handle->accept_button = NULL;
83 } 91 }
84 92
93 GtkContainer *content_box = GTK_CONTAINER(
94 gtk_builder_get_object(handle->builder, "content_box")
95 );
96
97 GtkBuilder *builder = gtk_builder_new_from_file(
98 "resources/ui/message_content.ui"
99 );
100
85 handle->timestamp_label = GTK_LABEL( 101 handle->timestamp_label = GTK_LABEL(
86 gtk_builder_get_object(handle->builder, "timestamp_label") 102 gtk_builder_get_object(builder, "timestamp_label")
87 ); 103 );
88 104
89 handle->read_receipt_image = GTK_IMAGE( 105 handle->read_receipt_image = GTK_IMAGE(
90 gtk_builder_get_object(handle->builder, "read_receipt_image") 106 gtk_builder_get_object(builder, "read_receipt_image")
107 );
108
109 handle->text_label = GTK_LABEL(
110 gtk_builder_get_object(builder, "text_label")
111 );
112
113 handle->file_revealer = GTK_REVEALER(
114 gtk_builder_get_object(builder, "file_revealer")
91 ); 115 );
92 116
117 handle->preview_drawing_area = GTK_DRAWING_AREA(
118 gtk_builder_get_object(builder, "preview_drawing_area")
119 );
120
121 switch (handle->type)
122 {
123 case UI_MESSAGE_STATUS:
124 gtk_widget_set_visible(GTK_WIDGET(handle->timestamp_label), FALSE);
125 break;
126 default:
127 break;
128 }
129
130 switch (content_type)
131 {
132 case UI_MESSAGE_CONTENT_FILE:
133 gtk_revealer_set_reveal_child(handle->file_revealer, TRUE);
134 break;
135 default:
136 break;
137 }
138
139 gtk_container_add(content_box, GTK_WIDGET(
140 gtk_builder_get_object(builder, "message_content_box")
141 ));
142
143 g_object_unref(builder);
93 return handle; 144 return handle;
94} 145}
95 146
diff --git a/src/ui/message.h b/src/ui/message.h
index a17247c..b380960 100644
--- a/src/ui/message.h
+++ b/src/ui/message.h
@@ -39,6 +39,13 @@ typedef enum UI_MESSAGE_Type
39 UI_MESSAGE_STATUS = 2 39 UI_MESSAGE_STATUS = 2
40} UI_MESSAGE_Type; 40} UI_MESSAGE_Type;
41 41
42typedef enum UI_MESSAGE_ContentType
43{
44 UI_MESSAGE_CONTENT_TEXT = 0,
45 UI_MESSAGE_CONTENT_FILE = 1,
46 UI_MESSAGE_CONTENT_PREVIEW = 2
47} UI_MESSAGE_ContentType;
48
42typedef struct UI_MESSAGE_Handle 49typedef struct UI_MESSAGE_Handle
43{ 50{
44 UI_MESSAGE_Type type; 51 UI_MESSAGE_Type type;
@@ -49,17 +56,23 @@ typedef struct UI_MESSAGE_Handle
49 HdyAvatar *sender_avatar; 56 HdyAvatar *sender_avatar;
50 GtkLabel *sender_label; 57 GtkLabel *sender_label;
51 58
52 GtkLabel *text_label; 59 GtkRevealer *deny_revealer;
60 GtkRevealer *accept_revealer;
53 61
54 GtkButton *deny_button; 62 GtkButton *deny_button;
55 GtkButton *accept_button; 63 GtkButton *accept_button;
56 64
57 GtkLabel *timestamp_label; 65 GtkLabel *timestamp_label;
58 GtkImage *read_receipt_image; 66 GtkImage *read_receipt_image;
67
68 GtkLabel *text_label;
69 GtkRevealer *file_revealer;
70 GtkDrawingArea *preview_drawing_area;
59} UI_MESSAGE_Handle; 71} UI_MESSAGE_Handle;
60 72
61UI_MESSAGE_Handle* 73UI_MESSAGE_Handle*
62ui_message_new(UI_MESSAGE_Type type); 74ui_message_new(UI_MESSAGE_Type type,
75 UI_MESSAGE_ContentType content_type);
63 76
64void 77void
65ui_message_delete(UI_MESSAGE_Handle *handle); 78ui_message_delete(UI_MESSAGE_Handle *handle);
diff --git a/src/ui/new_contact.c b/src/ui/new_contact.c
index 3acae1a..7e6f9c6 100644
--- a/src/ui/new_contact.c
+++ b/src/ui/new_contact.c
@@ -69,7 +69,7 @@ handle_id_drawing_area_draw(GtkWidget* drawing_area,
69 GdkPixbuf *image = NULL; 69 GdkPixbuf *image = NULL;
70 70
71 if (!handle->image) 71 if (!handle->image)
72 goto render_image; 72 return FALSE;
73 73
74 uint w, h; 74 uint w, h;
75 zbar_image_get_size(handle->image, &w, &h); 75 zbar_image_get_size(handle->image, &w, &h);
diff --git a/src/ui/send_file.c b/src/ui/send_file.c
index cde2c4d..2d3f4a6 100644
--- a/src/ui/send_file.c
+++ b/src/ui/send_file.c
@@ -71,6 +71,146 @@ handle_dialog_destroy(UNUSED GtkWidget *window,
71 ui_send_file_dialog_cleanup((UI_SEND_FILE_Handle*) user_data); 71 ui_send_file_dialog_cleanup((UI_SEND_FILE_Handle*) user_data);
72} 72}
73 73
74static int
75handle_file_redraw_animation(gpointer user_data)
76{
77 UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_Handle*) user_data;
78
79 handle->redraw_animation = 0;
80
81 if (handle->file_drawing_area)
82 gtk_widget_queue_draw(GTK_WIDGET(handle->file_drawing_area));
83
84 return FALSE;
85}
86
87static gboolean
88handle_file_drawing_area_draw(GtkWidget* drawing_area,
89 cairo_t* cairo,
90 gpointer user_data)
91{
92 UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_Handle*) user_data;
93
94 GtkStyleContext* context = gtk_widget_get_style_context(drawing_area);
95
96 const guint width = gtk_widget_get_allocated_width(drawing_area);
97 const guint height = gtk_widget_get_allocated_height(drawing_area);
98
99 gtk_render_background(context, cairo, 0, 0, width, height);
100
101 GdkPixbuf *image = handle->image;
102
103 if (!handle->animation)
104 goto render_image;
105
106 if (handle->animation_iter)
107 gdk_pixbuf_animation_iter_advance(handle->animation_iter, NULL);
108 else
109 handle->animation_iter = gdk_pixbuf_animation_get_iter(
110 handle->animation, NULL
111 );
112
113 image = gdk_pixbuf_animation_iter_get_pixbuf(handle->animation_iter);
114
115 const int delay = gdk_pixbuf_animation_iter_get_delay_time(
116 handle->animation_iter
117 );
118
119 handle->redraw_animation = g_timeout_add(
120 delay, handle_file_redraw_animation, handle
121 );
122
123render_image:
124 if (!image)
125 return FALSE;
126
127 int dwidth = gdk_pixbuf_get_width(image);
128 int dheight = gdk_pixbuf_get_height(image);
129
130 double ratio_width = 1.0 * width / dwidth;
131 double ratio_height = 1.0 * height / dheight;
132
133 const double ratio = ratio_width < ratio_height? ratio_width : ratio_height;
134
135 dwidth = (int) (dwidth * ratio);
136 dheight = (int) (dheight * ratio);
137
138 double dx = (width - dwidth) * 0.5;
139 double dy = (height - dheight) * 0.5;
140
141 const int interp_type = (ratio >= 1.0?
142 GDK_INTERP_NEAREST :
143 GDK_INTERP_BILINEAR
144 );
145
146 GdkPixbuf* scaled = gdk_pixbuf_scale_simple(
147 image,
148 dwidth,
149 dheight,
150 interp_type
151 );
152
153 gtk_render_icon(context, cairo, scaled, dx, dy);
154
155 cairo_fill(cairo);
156
157 g_object_unref(scaled);
158 return FALSE;
159}
160
161static void
162_clear_file_preview_data(UI_SEND_FILE_Handle *handle)
163{
164 if (handle->image)
165 {
166 g_object_unref(handle->image);
167 handle->image = NULL;
168 }
169
170 if (handle->redraw_animation)
171 {
172 g_source_remove(handle->redraw_animation);
173 handle->redraw_animation = 0;
174 }
175
176 if (handle->animation_iter)
177 {
178 g_object_unref(handle->animation_iter);
179 handle->animation_iter = NULL;
180 }
181
182 if (handle->animation)
183 {
184 g_object_unref(handle->animation);
185 handle->animation = NULL;
186 }
187}
188
189static void
190handle_file_chooser_button_file_set(GtkFileChooserButton *file_chooser_button,
191 gpointer user_data)
192{
193 UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_Handle*) user_data;
194
195 _clear_file_preview_data(handle);
196
197 char *filename = gtk_file_chooser_get_filename(
198 GTK_FILE_CHOOSER(file_chooser_button)
199 );
200
201 if (filename)
202 {
203 handle->animation = gdk_pixbuf_animation_new_from_file(filename, NULL);
204
205 if (!handle->animation)
206 handle->image = gdk_pixbuf_new_from_file(filename, NULL);
207
208 g_free(filename);
209 }
210
211 gtk_widget_queue_draw(GTK_WIDGET(handle->file_drawing_area));
212}
213
74void 214void
75ui_send_file_dialog_init(MESSENGER_Application *app, 215ui_send_file_dialog_init(MESSENGER_Application *app,
76 UI_SEND_FILE_Handle *handle) 216 UI_SEND_FILE_Handle *handle)
@@ -99,6 +239,20 @@ ui_send_file_dialog_init(MESSENGER_Application *app,
99 gtk_builder_get_object(handle->builder, "file_chooser_button") 239 gtk_builder_get_object(handle->builder, "file_chooser_button")
100 ); 240 );
101 241
242 g_signal_connect(
243 handle->file_drawing_area,
244 "draw",
245 G_CALLBACK(handle_file_drawing_area_draw),
246 handle
247 );
248
249 g_signal_connect(
250 handle->file_chooser_button,
251 "file-set",
252 G_CALLBACK(handle_file_chooser_button_file_set),
253 handle
254 );
255
102 handle->cancel_button = GTK_BUTTON( 256 handle->cancel_button = GTK_BUTTON(
103 gtk_builder_get_object(handle->builder, "cancel_button") 257 gtk_builder_get_object(handle->builder, "cancel_button")
104 ); 258 );
@@ -127,22 +281,36 @@ ui_send_file_dialog_init(MESSENGER_Application *app,
127 G_CALLBACK(handle_dialog_destroy), 281 G_CALLBACK(handle_dialog_destroy),
128 handle 282 handle
129 ); 283 );
284
285 handle->image = NULL;
286 handle->animation = NULL;
287 handle->animation_iter = NULL;
288
289 handle->redraw_animation = 0;
130} 290}
131 291
132void 292void
133ui_send_file_dialog_update(UI_SEND_FILE_Handle *handle, 293ui_send_file_dialog_update(UI_SEND_FILE_Handle *handle,
134 const gchar *filename) 294 const gchar *filename)
135{ 295{
136 if ((!filename) || (!gtk_file_chooser_set_filename( 296 if (!handle->file_chooser_button)
137 GTK_FILE_CHOOSER(handle->file_chooser_button),
138 filename)))
139 return; 297 return;
140 298
141 // TODO: update preview 299 gtk_file_chooser_set_filename(
300 GTK_FILE_CHOOSER(handle->file_chooser_button),
301 filename
302 );
303
304 handle_file_chooser_button_file_set(
305 handle->file_chooser_button,
306 handle
307 );
142} 308}
143 309
144void 310void
145ui_send_file_dialog_cleanup(UI_SEND_FILE_Handle *handle) 311ui_send_file_dialog_cleanup(UI_SEND_FILE_Handle *handle)
146{ 312{
313 _clear_file_preview_data(handle);
314
147 g_object_unref(handle->builder); 315 g_object_unref(handle->builder);
148} 316}
diff --git a/src/ui/send_file.h b/src/ui/send_file.h
index cb58285..1a68681 100644
--- a/src/ui/send_file.h
+++ b/src/ui/send_file.h
@@ -39,6 +39,12 @@ typedef struct UI_SEND_FILE_Handle
39 39
40 GtkButton *cancel_button; 40 GtkButton *cancel_button;
41 GtkButton *send_button; 41 GtkButton *send_button;
42
43 GdkPixbuf *image;
44 GdkPixbufAnimation *animation;
45 GdkPixbufAnimationIter *animation_iter;
46
47 guint redraw_animation;
42} UI_SEND_FILE_Handle; 48} UI_SEND_FILE_Handle;
43 49
44void 50void