blob: 3d7b006c8cfa0938fd040dae3c7249dc63c23370 [file] [log] [blame]
Stepan Salenikovichd2cad062016-01-08 13:43:49 -05001/*
Guillaume Roguez77c579d2018-01-30 15:54:02 -05002 * Copyright (C) 2016-2018 Savoir-faire Linux Inc.
Stepan Salenikovichd2cad062016-01-08 13:43:49 -05003 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
aviau039001d2016-09-29 16:39:05 -04004 * Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
Sébastien Blin55bff9d2017-10-03 15:15:23 -04005 * Author: Nicolas Jäger <nicolas.jager@savoirfairelinux.com>
6 * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
Stepan Salenikovichd2cad062016-01-08 13:43:49 -05007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include "chatview.h"
24
Sébastien Blin55bff9d2017-10-03 15:15:23 -040025// std
26#include <algorithm>
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050027
Guillaume Roguez5b137be2018-02-21 10:44:58 -050028// GTK
29#include <glib/gi18n.h>
30
Nicolas Jager759faea2017-03-22 16:22:00 -040031// LRC
Sébastien Blin55bff9d2017-10-03 15:15:23 -040032#include <api/contactmodel.h>
33#include <api/conversationmodel.h>
34#include <api/contact.h>
Nicolas Jager759faea2017-03-22 16:22:00 -040035
Sébastien Blin55bff9d2017-10-03 15:15:23 -040036// Client
37#include "utils/files.h"
Stepan Salenikovichce06adb2016-02-19 12:53:53 -050038
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050039struct _ChatView
40{
41 GtkBox parent;
42};
43
44struct _ChatViewClass
45{
46 GtkBoxClass parent_class;
47};
48
49typedef struct _ChatViewPrivate ChatViewPrivate;
50
51struct _ChatViewPrivate
52{
aviau039001d2016-09-29 16:39:05 -040053 GtkWidget *box_webkit_chat_container;
54 GtkWidget *webkit_chat_container;
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -050055 GtkWidget *hbox_chat_info;
56 GtkWidget *label_peer;
AmarOkcba03952017-07-17 10:13:49 -040057 GtkWidget *label_cm;
Stepan Salenikovich8043a562016-03-18 13:56:40 -040058 GtkWidget *button_close_chatview;
Stepan Salenikoviche9933242016-06-21 18:08:48 -040059 GtkWidget *button_placecall;
Sébastien Blin55bff9d2017-10-03 15:15:23 -040060 GtkWidget *button_add_to_conversations;
Nicolas Jagerd29ae952017-12-04 16:00:12 -050061 GtkWidget *button_place_audio_call;
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050062
Sébastien Blin70dc0b72017-07-31 16:24:41 -040063 GSettings *settings;
64
Sébastien Blin55bff9d2017-10-03 15:15:23 -040065 lrc::api::conversation::Info* conversation_;
66 AccountContainer* accountContainer_;
67 bool isTemporary_;
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050068
Sébastien Blin55bff9d2017-10-03 15:15:23 -040069 QMetaObject::Connection new_interaction_connection;
70 QMetaObject::Connection update_interaction_connection;
71 QMetaObject::Connection update_add_to_conversations;
Stepan Salenikovich1f731212016-11-10 11:55:10 -050072
73 gulong webkit_ready;
AmarOkb4253242017-07-13 11:21:39 -040074 gulong webkit_send_text;
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050075};
76
77G_DEFINE_TYPE_WITH_PRIVATE(ChatView, chat_view, GTK_TYPE_BOX);
78
79#define CHAT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CHAT_VIEW_TYPE, ChatViewPrivate))
80
81enum {
82 NEW_MESSAGES_DISPLAYED,
Stepan Salenikovich8043a562016-03-18 13:56:40 -040083 HIDE_VIEW_CLICKED,
Stepan Salenikovichd2cad062016-01-08 13:43:49 -050084 LAST_SIGNAL
85};
86
87static guint chat_view_signals[LAST_SIGNAL] = { 0 };
88
89static void
90chat_view_dispose(GObject *object)
91{
92 ChatView *view;
93 ChatViewPrivate *priv;
94
95 view = CHAT_VIEW(object);
96 priv = CHAT_VIEW_GET_PRIVATE(view);
97
Sébastien Blin55bff9d2017-10-03 15:15:23 -040098 QObject::disconnect(priv->new_interaction_connection);
99 QObject::disconnect(priv->update_interaction_connection);
100 QObject::disconnect(priv->update_add_to_conversations);
aviau039001d2016-09-29 16:39:05 -0400101
102 /* Destroying the box will also destroy its children, and we wouldn't
103 * want that. So we remove the webkit_chat_container from the box. */
104 if (priv->webkit_chat_container) {
Stepan Salenikovich1f731212016-11-10 11:55:10 -0500105 /* disconnect for webkit signals */
106 g_signal_handler_disconnect(priv->webkit_chat_container, priv->webkit_ready);
107 priv->webkit_ready = 0;
AmarOkb4253242017-07-13 11:21:39 -0400108 g_signal_handler_disconnect(priv->webkit_chat_container, priv->webkit_send_text);
109 priv->webkit_send_text = 0;
Stepan Salenikovich1f731212016-11-10 11:55:10 -0500110
aviau039001d2016-09-29 16:39:05 -0400111 gtk_container_remove(
112 GTK_CONTAINER(priv->box_webkit_chat_container),
113 GTK_WIDGET(priv->webkit_chat_container)
114 );
115 priv->webkit_chat_container = nullptr;
116 }
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500117
118 G_OBJECT_CLASS(chat_view_parent_class)->dispose(object);
119}
120
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500121static void
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400122hide_chat_view(G_GNUC_UNUSED GtkWidget *widget, ChatView *self)
123{
124 g_signal_emit(G_OBJECT(self), chat_view_signals[HIDE_VIEW_CLICKED], 0);
125}
126
127static void
Sébastien Blin70dc0b72017-07-31 16:24:41 -0400128display_links_toggled(ChatView *self)
129{
130 auto priv = CHAT_VIEW_GET_PRIVATE(self);
131 if (priv->webkit_chat_container) {
132 webkit_chat_container_set_display_links(
133 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
134 g_settings_get_boolean(priv->settings, "enable-display-links")
135 );
136 }
137}
138
139static void
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400140placecall_clicked(ChatView *self)
141{
142 auto priv = CHAT_VIEW_GET_PRIVATE(self);
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500143 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400144 priv->accountContainer_->info.conversationModel->placeCall(priv->conversation_->uid);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400145}
146
147static void
Nicolas Jagerd29ae952017-12-04 16:00:12 -0500148place_audio_call_clicked(ChatView *self)
149{
150 auto priv = CHAT_VIEW_GET_PRIVATE(self);
151
152 if (!priv->conversation_)
153 return;
154
155 priv->accountContainer_->info.conversationModel->placeAudioOnlyCall(priv->conversation_->uid);
156}
157
158static void
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400159button_add_to_conversations_clicked(ChatView *self)
Nicolas Jager759faea2017-03-22 16:22:00 -0400160{
161 auto priv = CHAT_VIEW_GET_PRIVATE(self);
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500162 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400163 priv->accountContainer_->info.conversationModel->makePermanent(priv->conversation_->uid);
Nicolas Jager759faea2017-03-22 16:22:00 -0400164}
165
Guillaume Roguez5b137be2018-02-21 10:44:58 -0500166static gchar*
167file_to_manipulate(GtkWindow* top_window, bool send)
168{
169 GtkWidget* dialog;
170 GtkFileChooserAction action = send? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE;
171 gint res;
172 gchar* filename = nullptr;
173
174 dialog = gtk_file_chooser_dialog_new(send? _("Send File") : _("Save File"),
175 top_window,
176 action,
177 _("_Cancel"),
178 GTK_RESPONSE_CANCEL,
179 send? _("_Open"): _("_Save"),
180 GTK_RESPONSE_ACCEPT,
181 nullptr);
182
183 res = gtk_dialog_run (GTK_DIALOG(dialog));
184
185 if (res == GTK_RESPONSE_ACCEPT) {
186 auto chooser = GTK_FILE_CHOOSER(dialog);
187 filename = gtk_file_chooser_get_filename(chooser);
188 }
189 gtk_widget_destroy (dialog);
190
191 return filename;
192}
193
Nicolas Jager759faea2017-03-22 16:22:00 -0400194static void
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400195webkit_chat_container_script_dialog(G_GNUC_UNUSED GtkWidget* webview, gchar *interaction, ChatView* self)
AmarOkb4253242017-07-13 11:21:39 -0400196{
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400197 auto priv = CHAT_VIEW_GET_PRIVATE(self);
198 auto order = std::string(interaction);
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500199 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400200 if (order == "ACCEPT") {
201 priv->accountContainer_->info.conversationModel->makePermanent(priv->conversation_->uid);
202 } else if (order == "REFUSE") {
203 priv->accountContainer_->info.conversationModel->removeConversation(priv->conversation_->uid);
204 } else if (order == "BLOCK") {
205 priv->accountContainer_->info.conversationModel->removeConversation(priv->conversation_->uid, true);
206 } else if (order.find("SEND:") == 0) {
207 // Get text body
208 auto toSend = order.substr(std::string("SEND:").size());
209 priv->accountContainer_->info.conversationModel->sendMessage(priv->conversation_->uid, toSend);
Guillaume Roguez5b137be2018-02-21 10:44:58 -0500210 } else if (order.find("SEND_FILE") == 0) {
211 if (auto model = priv->accountContainer_->info.conversationModel.get()) {
212 if (auto filename = file_to_manipulate(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))), true))
213 model->sendFile(priv->conversation_->uid, filename, g_path_get_basename(filename));
214 }
215 } else if (order.find("ACCEPT_FILE:") == 0) {
216 if (auto model = priv->accountContainer_->info.conversationModel.get()) {
217 try {
218 auto interactionId = std::stoull(order.substr(std::string("ACCEPT_FILE:").size()));
219 if (auto filename = file_to_manipulate(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))), false))
220 model->acceptTransfer(priv->conversation_->uid, interactionId, filename);
221 else
222 model->cancelTransfer(priv->conversation_->uid, interactionId);
223 } catch (...) {
224 // ignore
225 }
226 }
227 } else if (order.find("REFUSE_FILE:") == 0) {
228 if (auto model = priv->accountContainer_->info.conversationModel.get()) {
229 try {
230 auto interactionId = std::stoull(order.substr(std::string("REFUSE_FILE:").size()));
231 model->cancelTransfer(priv->conversation_->uid, interactionId);
232 } catch (...) {
233 // ignore
234 }
235 }
236 } else if (order.find("OPEN_FILE:") == 0) {
237 // Get text body
238 auto filename {"file://" + order.substr(std::string("OPEN_FILE:").size())};
239 filename.erase(std::find_if(filename.rbegin(), filename.rend(),
240 std::not1(std::ptr_fun<int, int>(std::isspace))).base(), filename.end());
241 GError* error = nullptr;
242 if (!gtk_show_uri(nullptr, filename.c_str(), GDK_CURRENT_TIME, &error)) {
243 g_debug("Could not open file: %s", error->message);
244 g_error_free(error);
245 }
AmarOkb4253242017-07-13 11:21:39 -0400246 }
247}
248
249static void
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500250chat_view_init(ChatView *view)
251{
252 gtk_widget_init_template(GTK_WIDGET(view));
253
254 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(view);
Sébastien Blin70dc0b72017-07-31 16:24:41 -0400255 priv->settings = g_settings_new_full(get_ring_schema(), NULL, NULL);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500256
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400257 g_signal_connect(priv->button_close_chatview, "clicked", G_CALLBACK(hide_chat_view), view);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400258 g_signal_connect_swapped(priv->button_placecall, "clicked", G_CALLBACK(placecall_clicked), view);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400259 g_signal_connect_swapped(priv->button_add_to_conversations, "clicked", G_CALLBACK(button_add_to_conversations_clicked), view);
Nicolas Jagerd29ae952017-12-04 16:00:12 -0500260 g_signal_connect_swapped(priv->button_place_audio_call, "clicked", G_CALLBACK(place_audio_call_clicked), view);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500261}
262
263static void
264chat_view_class_init(ChatViewClass *klass)
265{
266 G_OBJECT_CLASS(klass)->dispose = chat_view_dispose;
267
268 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
269 "/cx/ring/RingGnome/chatview.ui");
270
aviau039001d2016-09-29 16:39:05 -0400271 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, box_webkit_chat_container);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500272 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, hbox_chat_info);
273 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_peer);
AmarOkcba03952017-07-17 10:13:49 -0400274 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_cm);
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400275 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_close_chatview);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400276 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_placecall);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400277 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_add_to_conversations);
Nicolas Jagerd29ae952017-12-04 16:00:12 -0500278 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_place_audio_call);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500279
280 chat_view_signals[NEW_MESSAGES_DISPLAYED] = g_signal_new (
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400281 "new-interactions-displayed",
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500282 G_TYPE_FROM_CLASS(klass),
283 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
284 0,
285 nullptr,
286 nullptr,
287 g_cclosure_marshal_VOID__VOID,
288 G_TYPE_NONE, 0);
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400289
290 chat_view_signals[HIDE_VIEW_CLICKED] = g_signal_new (
291 "hide-view-clicked",
292 G_TYPE_FROM_CLASS(klass),
293 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
294 0,
295 nullptr,
296 nullptr,
297 g_cclosure_marshal_VOID__VOID,
298 G_TYPE_NONE, 0);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500299}
300
301static void
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400302print_interaction_to_buffer(ChatView* self, uint64_t interactionId, const lrc::api::interaction::Info& interaction)
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500303{
aviau039001d2016-09-29 16:39:05 -0400304 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
305
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500306 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400307 if (interaction.status == lrc::api::interaction::Status::UNREAD)
308 priv->accountContainer_->info.conversationModel->setInteractionRead(priv->conversation_->uid, interactionId);
309
310 webkit_chat_container_print_new_interaction(
aviau039001d2016-09-29 16:39:05 -0400311 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
Guillaume Roguez5b137be2018-02-21 10:44:58 -0500312 *priv->accountContainer_->info.conversationModel,
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400313 interactionId,
314 interaction
aviau039001d2016-09-29 16:39:05 -0400315 );
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500316}
317
aviaufc213552016-11-01 12:39:39 -0400318static void
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400319update_interaction(ChatView* self, uint64_t interactionId, const lrc::api::interaction::Info& interaction)
aviaufc213552016-11-01 12:39:39 -0400320{
321 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400322 webkit_chat_container_update_interaction(
323 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
Guillaume Roguez5b137be2018-02-21 10:44:58 -0500324 *priv->accountContainer_->info.conversationModel,
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400325 interactionId,
326 interaction
aviaufc213552016-11-01 12:39:39 -0400327 );
aviaufc213552016-11-01 12:39:39 -0400328}
329
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500330static void
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400331load_participants_images(ChatView *self)
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500332{
333 g_return_if_fail(IS_CHAT_VIEW(self));
334 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
335
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400336 // Contact
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500337 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400338 auto contactUri = priv->conversation_->participants.front();
Guillaume Roguezc2095922017-12-14 14:07:10 -0500339 try{
340 auto& contact = priv->accountContainer_->info.contactModel->getContact(contactUri);
341 if (!contact.profileInfo.avatar.empty()) {
342 webkit_chat_container_set_sender_image(
343 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
344 priv->accountContainer_->info.contactModel->getContactProfileId(contactUri),
345 contact.profileInfo.avatar
346 );
347 }
348 } catch (const std::out_of_range&) {
349 // ContactModel::getContact() exception
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500350 }
351
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400352 // For this account
353 if (!priv->accountContainer_->info.profileInfo.avatar.empty()) {
354 webkit_chat_container_set_sender_image(
355 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
356 priv->accountContainer_->info.contactModel->getContactProfileId(priv->accountContainer_->info.profileInfo.uri),
357 priv->accountContainer_->info.profileInfo.avatar
358 );
359 }
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500360}
361
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500362static void
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400363print_text_recording(ChatView *self)
364{
365 g_return_if_fail(IS_CHAT_VIEW(self));
366 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
367
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500368 if (!priv->conversation_) return;
Sébastien Blin05317a72018-02-21 11:09:16 -0500369 webkit_chat_container_print_history(
370 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
Guillaume Roguez5b137be2018-02-21 10:44:58 -0500371 *priv->accountContainer_->info.conversationModel,
Sébastien Blin05317a72018-02-21 11:09:16 -0500372 priv->conversation_->interactions
373 );
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400374
375 QObject::disconnect(priv->new_interaction_connection);
376}
377
378static void
379update_add_to_conversations(ChatView *self)
Sébastien Blinf3681aa2017-07-19 16:53:49 -0400380{
381 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
382
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500383 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400384 auto participant = priv->conversation_->participants[0];
Guillaume Roguezc2095922017-12-14 14:07:10 -0500385 try {
386 auto contactInfo = priv->accountContainer_->info.contactModel->getContact(participant);
387 if(contactInfo.profileInfo.type != lrc::api::profile::Type::TEMPORARY
388 && contactInfo.profileInfo.type != lrc::api::profile::Type::PENDING)
389 gtk_widget_hide(priv->button_add_to_conversations);
390 } catch (const std::out_of_range&) {
391 // ContactModel::getContact() exception
392 }
Stepan Salenikovich5039c9b2016-02-12 14:09:51 -0500393}
394
395static void
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500396update_contact_methods(ChatView *self)
397{
398 g_return_if_fail(IS_CHAT_VIEW(self));
399 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500400 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400401 auto contactUri = priv->conversation_->participants.front();
Guillaume Roguezc2095922017-12-14 14:07:10 -0500402 try {
403 auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
404 auto bestId = std::string(contactInfo.registeredName).empty() ? contactInfo.profileInfo.uri : contactInfo.registeredName;
405 if (contactInfo.profileInfo.alias == bestId) {
406 gtk_widget_hide(priv->label_cm);
407 } else {
408 gtk_label_set_text(GTK_LABEL(priv->label_cm), bestId.c_str());
409 gtk_widget_show(priv->label_cm);
410 }
411 } catch (const std::out_of_range&) {
412 // ContactModel::getContact() exception
AmarOkcba03952017-07-17 10:13:49 -0400413 }
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500414}
415
416static void
Sébastien Blinf3681aa2017-07-19 16:53:49 -0400417update_name(ChatView *self)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500418{
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400419 g_return_if_fail(IS_CHAT_VIEW(self));
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500420 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500421 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400422 auto contactUri = priv->conversation_->participants.front();
Guillaume Roguezc2095922017-12-14 14:07:10 -0500423 try {
424 auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
425 auto alias = contactInfo.profileInfo.alias;
426 alias.erase(std::remove(alias.begin(), alias.end(), '\r'), alias.end());
427 gtk_label_set_text(GTK_LABEL(priv->label_peer), alias.c_str());
428 } catch (const std::out_of_range&) {
429 // ContactModel::getContact() exception
430 }
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500431}
432
aviau039001d2016-09-29 16:39:05 -0400433static void
aviau039001d2016-09-29 16:39:05 -0400434webkit_chat_container_ready(ChatView* self)
435{
436 /* The webkit chat container has loaded the javascript libraries, we can
437 * now use it. */
438
439 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
440
441 webkit_chat_container_clear(
442 WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)
443 );
444
Sébastien Blin70dc0b72017-07-31 16:24:41 -0400445 display_links_toggled(self);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400446 print_text_recording(self);
447 load_participants_images(self);
Sébastien Blin70dc0b72017-07-31 16:24:41 -0400448
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400449 priv->new_interaction_connection = QObject::connect(
Nicolas Jager6635b0d2018-01-24 12:25:28 -0500450 &*priv->accountContainer_->info.conversationModel, &lrc::api::ConversationModel::newInteraction,
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400451 [self, priv](const std::string& uid, uint64_t interactionId, lrc::api::interaction::Info interaction) {
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500452 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400453 if(uid == priv->conversation_->uid) {
454 print_interaction_to_buffer(self, interactionId, interaction);
455 }
456 });
457
458 priv->update_interaction_connection = QObject::connect(
459 &*priv->accountContainer_->info.conversationModel, &lrc::api::ConversationModel::interactionStatusUpdated,
460 [self, priv](const std::string& uid, uint64_t msgId, lrc::api::interaction::Info msg) {
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500461 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400462 if(uid == priv->conversation_->uid) {
463 update_interaction(self, msgId, msg);
464 }
465 });
466
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500467 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400468 auto contactUri = priv->conversation_->participants.front();
Guillaume Roguezc2095922017-12-14 14:07:10 -0500469 try {
470 auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
471 priv->isTemporary_ = contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY
472 || contactInfo.profileInfo.type == lrc::api::profile::Type::PENDING;
473 webkit_chat_container_set_temporary(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container), priv->isTemporary_);
474 auto bestName = contactInfo.profileInfo.alias;
475 if (bestName.empty())
476 bestName = contactInfo.registeredName;
477 if (bestName.empty())
478 bestName = contactInfo.profileInfo.uri;
479 bestName.erase(std::remove(bestName.begin(), bestName.end(), '\r'), bestName.end());
480 webkit_chat_container_set_invitation(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
481 (contactInfo.profileInfo.type == lrc::api::profile::Type::PENDING),
482 bestName);
483 webkit_chat_disable_send_interaction(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
484 (contactInfo.profileInfo.type == lrc::api::profile::Type::SIP)
485 && priv->conversation_->callId.empty());
486 } catch (const std::out_of_range&) {
487 // ContactModel::getContact() exception
488 }
aviau039001d2016-09-29 16:39:05 -0400489}
490
491static void
492build_chat_view(ChatView* self)
493{
494 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
495
496 gtk_container_add(GTK_CONTAINER(priv->box_webkit_chat_container), priv->webkit_chat_container);
497 gtk_widget_show(priv->webkit_chat_container);
498
Sébastien Blinf3681aa2017-07-19 16:53:49 -0400499 update_name(self);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400500 update_add_to_conversations(self);
Stepan Salenikovich1f731212016-11-10 11:55:10 -0500501 update_contact_methods(self);
Stepan Salenikovich1f731212016-11-10 11:55:10 -0500502
503 priv->webkit_ready = g_signal_connect_swapped(
aviau039001d2016-09-29 16:39:05 -0400504 priv->webkit_chat_container,
505 "ready",
506 G_CALLBACK(webkit_chat_container_ready),
507 self
508 );
509
AmarOkb4253242017-07-13 11:21:39 -0400510 priv->webkit_send_text = g_signal_connect(priv->webkit_chat_container,
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400511 "script-dialog",
512 G_CALLBACK(webkit_chat_container_script_dialog),
AmarOkb4253242017-07-13 11:21:39 -0400513 self);
514
aviau039001d2016-09-29 16:39:05 -0400515 if (webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)))
aviau039001d2016-09-29 16:39:05 -0400516 webkit_chat_container_ready(self);
aviau039001d2016-09-29 16:39:05 -0400517
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400518 gtk_widget_set_visible(priv->hbox_chat_info, TRUE);
519
aviau039001d2016-09-29 16:39:05 -0400520}
521
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500522GtkWidget *
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400523chat_view_new (WebKitChatContainer* webkit_chat_container,
524 AccountContainer* accountContainer,
525 lrc::api::conversation::Info* conversation)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500526{
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500527 ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500528
aviau039001d2016-09-29 16:39:05 -0400529 ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
530 priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400531 priv->conversation_ = conversation;
532 priv->accountContainer_ = accountContainer;
aviau039001d2016-09-29 16:39:05 -0400533
534 build_chat_view(self);
Stepan Salenikovichd2cad062016-01-08 13:43:49 -0500535 return (GtkWidget *)self;
536}
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500537
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400538void
539chat_view_update_temporary(ChatView* self, bool newValue)
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500540{
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400541 g_return_if_fail(IS_CHAT_VIEW(self));
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400542 auto priv = CHAT_VIEW_GET_PRIVATE(self);
543
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400544 priv->isTemporary_ = newValue;
545 if (!priv->isTemporary_) {
546 gtk_widget_hide(priv->button_add_to_conversations);
547 }
548 webkit_chat_container_set_temporary(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container), priv->isTemporary_);
Sébastien Blin5851aaf2017-11-06 16:02:08 -0500549 if (!priv->conversation_) return;
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400550 auto contactUri = priv->conversation_->participants.front();
Guillaume Roguezc2095922017-12-14 14:07:10 -0500551 try {
552 auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
553 auto bestName = contactInfo.profileInfo.alias;
554 if (bestName.empty())
555 bestName = contactInfo.registeredName;
556 if (bestName.empty())
557 bestName = contactInfo.profileInfo.uri;
558 webkit_chat_container_set_invitation(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
559 newValue,
560 bestName);
561 } catch (const std::out_of_range&) {
562 // ContactModel::getContact() exception
563 }
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400564}
565
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400566bool
567chat_view_get_temporary(ChatView *self)
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400568{
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400569 g_return_val_if_fail(IS_CHAT_VIEW(self), false);
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400570 auto priv = CHAT_VIEW_GET_PRIVATE(self);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400571 return priv->isTemporary_;
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400572}
573
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400574lrc::api::conversation::Info
575chat_view_get_conversation(ChatView *self)
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400576{
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400577 g_return_val_if_fail(IS_CHAT_VIEW(self), lrc::api::conversation::Info());
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400578 auto priv = CHAT_VIEW_GET_PRIVATE(self);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400579 return *priv->conversation_;
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400580}
Stepan Salenikovichdaf3cb32016-10-12 16:39:42 -0400581
582void
583chat_view_set_header_visible(ChatView *self, gboolean visible)
584{
585 auto priv = CHAT_VIEW_GET_PRIVATE(self);
Stepan Salenikovichdaf3cb32016-10-12 16:39:42 -0400586 gtk_widget_set_visible(priv->hbox_chat_info, visible);
587}