chatview.cpp 22.4 KB
Newer Older
1
/*
Guillaume Roguez's avatar
Guillaume Roguez committed
2
 *  Copyright (C) 2016-2018 Savoir-faire Linux Inc.
3
 *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
aviau's avatar
aviau committed
4
 *  Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
5
6
 *  Author: Nicolas Jäger <nicolas.jager@savoirfairelinux.com>
 *  Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 */

#include "chatview.h"

25
26
// std
#include <algorithm>
27

28
29
30
// GTK
#include <glib/gi18n.h>

31
32
33
34
// LRC
#include <api/contactmodel.h>
#include <api/conversationmodel.h>
#include <api/contact.h>
35

36
37
// Client
#include "utils/files.h"
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
struct _ChatView
{
    GtkBox parent;
};

struct _ChatViewClass
{
    GtkBoxClass parent_class;
};

typedef struct _ChatViewPrivate ChatViewPrivate;

struct _ChatViewPrivate
{
aviau's avatar
aviau committed
53
54
    GtkWidget *box_webkit_chat_container;
    GtkWidget *webkit_chat_container;
Stepan Salenikovich's avatar
Stepan Salenikovich committed
55
56
    GtkWidget *hbox_chat_info;
    GtkWidget *label_peer;
57
    GtkWidget *label_cm;
58
    GtkWidget *button_close_chatview;
59
    GtkWidget *button_placecall;
60
    GtkWidget *button_add_to_conversations;
61
    GtkWidget *button_place_audio_call;
Stepan Salenikovich's avatar
Stepan Salenikovich committed
62

63
64
    GSettings *settings;

65
66
67
    lrc::api::conversation::Info* conversation_;
    AccountContainer* accountContainer_;
    bool isTemporary_;
68

69
70
71
    QMetaObject::Connection new_interaction_connection;
    QMetaObject::Connection update_interaction_connection;
    QMetaObject::Connection update_add_to_conversations;
72
73

    gulong webkit_ready;
74
    gulong webkit_send_text;
75
76
77
78
79
80
81
82
};

G_DEFINE_TYPE_WITH_PRIVATE(ChatView, chat_view, GTK_TYPE_BOX);

#define CHAT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CHAT_VIEW_TYPE, ChatViewPrivate))

enum {
    NEW_MESSAGES_DISPLAYED,
83
    HIDE_VIEW_CLICKED,
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    LAST_SIGNAL
};

static guint chat_view_signals[LAST_SIGNAL] = { 0 };

static void
chat_view_dispose(GObject *object)
{
    ChatView *view;
    ChatViewPrivate *priv;

    view = CHAT_VIEW(object);
    priv = CHAT_VIEW_GET_PRIVATE(view);

98
99
100
    QObject::disconnect(priv->new_interaction_connection);
    QObject::disconnect(priv->update_interaction_connection);
    QObject::disconnect(priv->update_add_to_conversations);
aviau's avatar
aviau committed
101
102
103
104

    /* Destroying the box will also destroy its children, and we wouldn't
     * want that. So we remove the webkit_chat_container from the box. */
    if (priv->webkit_chat_container) {
105
106
107
        /* disconnect for webkit signals */
        g_signal_handler_disconnect(priv->webkit_chat_container, priv->webkit_ready);
        priv->webkit_ready = 0;
108
109
        g_signal_handler_disconnect(priv->webkit_chat_container, priv->webkit_send_text);
        priv->webkit_send_text = 0;
110

aviau's avatar
aviau committed
111
112
113
114
115
116
        gtk_container_remove(
            GTK_CONTAINER(priv->box_webkit_chat_container),
            GTK_WIDGET(priv->webkit_chat_container)
        );
        priv->webkit_chat_container = nullptr;
    }
117
118
119
120

    G_OBJECT_CLASS(chat_view_parent_class)->dispose(object);
}

121
122
123
124
125
126
static void
hide_chat_view(G_GNUC_UNUSED GtkWidget *widget, ChatView *self)
{
    g_signal_emit(G_OBJECT(self), chat_view_signals[HIDE_VIEW_CLICKED], 0);
}

127
128
129
130
131
132
133
134
135
136
137
138
static void
display_links_toggled(ChatView *self)
{
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
    if (priv->webkit_chat_container) {
        webkit_chat_container_set_display_links(
            WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
            g_settings_get_boolean(priv->settings, "enable-display-links")
        );
    }
}

139
140
141
142
static void
placecall_clicked(ChatView *self)
{
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
143
    if (!priv->conversation_) return;
144
    priv->accountContainer_->info.conversationModel->placeCall(priv->conversation_->uid);
145
146
}

147
148
149
150
151
152
153
154
155
156
157
static void
place_audio_call_clicked(ChatView *self)
{
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    if (!priv->conversation_)
        return;

    priv->accountContainer_->info.conversationModel->placeAudioOnlyCall(priv->conversation_->uid);
}

158
static void
159
button_add_to_conversations_clicked(ChatView *self)
160
161
{
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
162
    if (!priv->conversation_) return;
163
    priv->accountContainer_->info.conversationModel->makePermanent(priv->conversation_->uid);
164
165
}

166
static gchar*
167
file_to_manipulate(GtkWindow* top_window, bool send)
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
{
    GtkWidget* dialog;
    GtkFileChooserAction action = send? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE;
    gint res;
    gchar* filename = nullptr;

    dialog = gtk_file_chooser_dialog_new(send? _("Send File") : _("Save File"),
                                         top_window,
                                         action,
                                         _("_Cancel"),
                                         GTK_RESPONSE_CANCEL,
                                         send? _("_Open"): _("_Save"),
                                         GTK_RESPONSE_ACCEPT,
                                         nullptr);

    res = gtk_dialog_run (GTK_DIALOG(dialog));

    if (res == GTK_RESPONSE_ACCEPT) {
        auto chooser = GTK_FILE_CHOOSER(dialog);
        filename = gtk_file_chooser_get_filename(chooser);
    }
    gtk_widget_destroy (dialog);

    return filename;
}

194
static void
195
webkit_chat_container_script_dialog(G_GNUC_UNUSED GtkWidget* webview, gchar *interaction, ChatView* self)
196
{
197
198
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
    auto order = std::string(interaction);
199
    if (!priv->conversation_) return;
200
201
202
203
204
205
206
207
208
209
    if (order == "ACCEPT") {
        priv->accountContainer_->info.conversationModel->makePermanent(priv->conversation_->uid);
    } else if (order == "REFUSE") {
        priv->accountContainer_->info.conversationModel->removeConversation(priv->conversation_->uid);
    } else if (order == "BLOCK") {
        priv->accountContainer_->info.conversationModel->removeConversation(priv->conversation_->uid, true);
    } else if (order.find("SEND:") == 0) {
        // Get text body
        auto toSend = order.substr(std::string("SEND:").size());
        priv->accountContainer_->info.conversationModel->sendMessage(priv->conversation_->uid, toSend);
210
211
212
213
214
215
216
217
218
    } else if (order.find("SEND_FILE") == 0) {
        if (auto model = priv->accountContainer_->info.conversationModel.get()) {
            if (auto filename = file_to_manipulate(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))), true))
                model->sendFile(priv->conversation_->uid, filename, g_path_get_basename(filename));
        }
    } else if (order.find("ACCEPT_FILE:") == 0) {
        if (auto model = priv->accountContainer_->info.conversationModel.get()) {
            try {
                auto interactionId = std::stoull(order.substr(std::string("ACCEPT_FILE:").size()));
219
220
221
222

                lrc::api::datatransfer::Info info = {};
                priv->accountContainer_->info.conversationModel->getTransferInfo(interactionId, info);

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
                // get prefered directory destination.
                auto* download_directory_variant = g_settings_get_value(priv->settings, "download-folder");
                char* download_directory_value;
                g_variant_get(download_directory_variant, "&s", &download_directory_value);
                std::string default_download_dir = g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD);
                auto current_value = std::string(download_directory_value);
                if (current_value.empty()) {
                    g_settings_set_value(priv->settings, "download-folder", g_variant_new("s", default_download_dir.c_str()));
                }
                // get full path
                std::string filename = current_value.empty()? default_download_dir.c_str() : download_directory_value;
                if (!filename.empty() && filename.back() != '/') filename += "/";
                filename += info.displayName;

                model->acceptTransfer(priv->conversation_->uid, interactionId, filename);
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
            } catch (...) {
                // ignore
            }
        }
    } else if (order.find("REFUSE_FILE:") == 0) {
        if (auto model = priv->accountContainer_->info.conversationModel.get()) {
            try {
                auto interactionId = std::stoull(order.substr(std::string("REFUSE_FILE:").size()));
                model->cancelTransfer(priv->conversation_->uid, interactionId);
            } catch (...) {
                // ignore
            }
        }
    } else if (order.find("OPEN_FILE:") == 0) {
        // Get text body
        auto filename {"file://" + order.substr(std::string("OPEN_FILE:").size())};
        filename.erase(std::find_if(filename.rbegin(), filename.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), filename.end());
        GError* error = nullptr;
        if (!gtk_show_uri(nullptr, filename.c_str(), GDK_CURRENT_TIME, &error)) {
            g_debug("Could not open file: %s", error->message);
            g_error_free(error);
        }
261
262
263
    }
}

264
265
266
267
268
269
static void
chat_view_init(ChatView *view)
{
    gtk_widget_init_template(GTK_WIDGET(view));

    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(view);
270
    priv->settings = g_settings_new_full(get_ring_schema(), NULL, NULL);
271

272
    g_signal_connect(priv->button_close_chatview, "clicked", G_CALLBACK(hide_chat_view), view);
273
    g_signal_connect_swapped(priv->button_placecall, "clicked", G_CALLBACK(placecall_clicked), view);
274
    g_signal_connect_swapped(priv->button_add_to_conversations, "clicked", G_CALLBACK(button_add_to_conversations_clicked), view);
275
    g_signal_connect_swapped(priv->button_place_audio_call, "clicked", G_CALLBACK(place_audio_call_clicked), view);
276
277
278
279
280
281
282
283
284
285
}

static void
chat_view_class_init(ChatViewClass *klass)
{
    G_OBJECT_CLASS(klass)->dispose = chat_view_dispose;

    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
                                                "/cx/ring/RingGnome/chatview.ui");

aviau's avatar
aviau committed
286
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, box_webkit_chat_container);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
287
288
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, hbox_chat_info);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_peer);
289
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_cm);
290
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_close_chatview);
291
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_placecall);
292
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_add_to_conversations);
293
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_place_audio_call);
294
295

    chat_view_signals[NEW_MESSAGES_DISPLAYED] = g_signal_new (
296
        "new-interactions-displayed",
297
298
299
300
301
302
303
        G_TYPE_FROM_CLASS(klass),
        (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
        0,
        nullptr,
        nullptr,
        g_cclosure_marshal_VOID__VOID,
        G_TYPE_NONE, 0);
304
305
306
307
308
309
310
311
312
313

    chat_view_signals[HIDE_VIEW_CLICKED] = g_signal_new (
        "hide-view-clicked",
        G_TYPE_FROM_CLASS(klass),
        (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
        0,
        nullptr,
        nullptr,
        g_cclosure_marshal_VOID__VOID,
        G_TYPE_NONE, 0);
314
315
}

aviau's avatar
aviau committed
316
static void
317
print_interaction_to_buffer(ChatView* self, uint64_t interactionId, const lrc::api::interaction::Info& interaction)
aviau's avatar
aviau committed
318
319
320
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

321
    if (!priv->conversation_) return;
322
323
324
325
    if (interaction.status == lrc::api::interaction::Status::UNREAD)
        priv->accountContainer_->info.conversationModel->setInteractionRead(priv->conversation_->uid, interactionId);

    webkit_chat_container_print_new_interaction(
aviau's avatar
aviau committed
326
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
327
        *priv->accountContainer_->info.conversationModel,
328
329
        interactionId,
        interaction
aviau's avatar
aviau committed
330
    );
331
332
}

333
static void
334
update_interaction(ChatView* self, uint64_t interactionId, const lrc::api::interaction::Info& interaction)
335
336
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
337
338
    webkit_chat_container_update_interaction(
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
339
        *priv->accountContainer_->info.conversationModel,
340
341
        interactionId,
        interaction
342
    );
343
}
344

345
346
347
348
349
static void
load_participants_images(ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
350

351
    // Contact
352
    if (!priv->conversation_) return;
353
    auto contactUri = priv->conversation_->participants.front();
354
355
356
357
358
359
360
361
362
363
364
    try{
        auto& contact = priv->accountContainer_->info.contactModel->getContact(contactUri);
        if (!contact.profileInfo.avatar.empty()) {
            webkit_chat_container_set_sender_image(
                WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
                priv->accountContainer_->info.contactModel->getContactProfileId(contactUri),
                contact.profileInfo.avatar
                );
        }
    } catch (const std::out_of_range&) {
        // ContactModel::getContact() exception
365
366
    }

367
368
369
370
371
372
373
    // For this account
    if (!priv->accountContainer_->info.profileInfo.avatar.empty()) {
        webkit_chat_container_set_sender_image(
            WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
            priv->accountContainer_->info.contactModel->getContactProfileId(priv->accountContainer_->info.profileInfo.uri),
            priv->accountContainer_->info.profileInfo.avatar
        );
374
375
376
    }
}

377
static void
378
print_text_recording(ChatView *self)
379
380
381
382
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

383
    // Read interactions
384
    if (!priv->conversation_) return;
385
386
387
388
389
    for (const auto& it: priv->conversation_->interactions) {
        if (it.second.status == lrc::api::interaction::Status::UNREAD)
            priv->accountContainer_->info.conversationModel->setInteractionRead(priv->conversation_->uid, it.first);
    }

390
391
    webkit_chat_container_print_history(
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
392
        *priv->accountContainer_->info.conversationModel,
393
394
        priv->conversation_->interactions
    );
395

396
    QObject::disconnect(priv->new_interaction_connection);
397
398
}

399
static void
400
update_add_to_conversations(ChatView *self)
401
402
403
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

404
    if (!priv->conversation_) return;
405
    auto participant = priv->conversation_->participants[0];
406
407
408
409
410
411
412
413
    try {
        auto contactInfo = priv->accountContainer_->info.contactModel->getContact(participant);
        if(contactInfo.profileInfo.type != lrc::api::profile::Type::TEMPORARY
           && contactInfo.profileInfo.type != lrc::api::profile::Type::PENDING)
            gtk_widget_hide(priv->button_add_to_conversations);
    } catch (const std::out_of_range&) {
        // ContactModel::getContact() exception
    }
414
415
}

Stepan Salenikovich's avatar
Stepan Salenikovich committed
416
417
418
419
420
static void
update_contact_methods(ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
421
    if (!priv->conversation_) return;
422
    auto contactUri = priv->conversation_->participants.front();
423
424
425
426
427
428
429
430
431
432
433
    try {
        auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
        auto bestId = std::string(contactInfo.registeredName).empty() ? contactInfo.profileInfo.uri : contactInfo.registeredName;
        if (contactInfo.profileInfo.alias == bestId) {
            gtk_widget_hide(priv->label_cm);
        } else {
            gtk_label_set_text(GTK_LABEL(priv->label_cm), bestId.c_str());
            gtk_widget_show(priv->label_cm);
        }
    } catch (const std::out_of_range&) {
        // ContactModel::getContact() exception
434
    }
Stepan Salenikovich's avatar
Stepan Salenikovich committed
435
436
437
}

static void
438
update_name(ChatView *self)
Stepan Salenikovich's avatar
Stepan Salenikovich committed
439
{
440
    g_return_if_fail(IS_CHAT_VIEW(self));
Stepan Salenikovich's avatar
Stepan Salenikovich committed
441
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
442
    if (!priv->conversation_) return;
443
    auto contactUri = priv->conversation_->participants.front();
444
445
446
447
448
449
450
451
    try {
        auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
        auto alias = contactInfo.profileInfo.alias;
        alias.erase(std::remove(alias.begin(), alias.end(), '\r'), alias.end());
        gtk_label_set_text(GTK_LABEL(priv->label_peer), alias.c_str());
    } catch (const std::out_of_range&) {
        // ContactModel::getContact() exception
    }
Stepan Salenikovich's avatar
Stepan Salenikovich committed
452
453
}

aviau's avatar
aviau committed
454
455
456
457
458
459
460
461
462
463
464
465
static void
webkit_chat_container_ready(ChatView* self)
{
    /* The webkit chat container has loaded the javascript libraries, we can
     * now use it. */

    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    webkit_chat_container_clear(
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)
    );

466
    display_links_toggled(self);
467
468
469
470
    print_text_recording(self);
    load_participants_images(self);

    priv->new_interaction_connection = QObject::connect(
471
    &*priv->accountContainer_->info.conversationModel, &lrc::api::ConversationModel::newInteraction,
472
    [self, priv](const std::string& uid, uint64_t interactionId, lrc::api::interaction::Info interaction) {
473
        if (!priv->conversation_) return;
474
475
476
477
        if(uid == priv->conversation_->uid) {
            print_interaction_to_buffer(self, interactionId, interaction);
        }
    });
478

479
480
481
    priv->update_interaction_connection = QObject::connect(
    &*priv->accountContainer_->info.conversationModel, &lrc::api::ConversationModel::interactionStatusUpdated,
    [self, priv](const std::string& uid, uint64_t msgId, lrc::api::interaction::Info msg) {
482
        if (!priv->conversation_) return;
483
484
485
486
487
        if(uid == priv->conversation_->uid) {
            update_interaction(self, msgId, msg);
        }
    });

488
    if (!priv->conversation_) return;
489
    auto contactUri = priv->conversation_->participants.front();
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
    try {
        auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
        priv->isTemporary_ = contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY
            || contactInfo.profileInfo.type == lrc::api::profile::Type::PENDING;
        webkit_chat_container_set_temporary(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container), priv->isTemporary_);
        auto bestName = contactInfo.profileInfo.alias;
        if (bestName.empty())
            bestName = contactInfo.registeredName;
        if (bestName.empty())
            bestName = contactInfo.profileInfo.uri;
        bestName.erase(std::remove(bestName.begin(), bestName.end(), '\r'), bestName.end());
        webkit_chat_container_set_invitation(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
                                             (contactInfo.profileInfo.type == lrc::api::profile::Type::PENDING),
                                             bestName);
        webkit_chat_disable_send_interaction(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
                                             (contactInfo.profileInfo.type == lrc::api::profile::Type::SIP)
                                             && priv->conversation_->callId.empty());
    } catch (const std::out_of_range&) {
        // ContactModel::getContact() exception
    }
aviau's avatar
aviau committed
510
511
512
513
514
515
516
517
518
519
}

static void
build_chat_view(ChatView* self)
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    gtk_container_add(GTK_CONTAINER(priv->box_webkit_chat_container), priv->webkit_chat_container);
    gtk_widget_show(priv->webkit_chat_container);

520
    update_name(self);
521
    update_add_to_conversations(self);
522
    update_contact_methods(self);
aviau's avatar
aviau committed
523

524
    priv->webkit_ready = g_signal_connect_swapped(
aviau's avatar
aviau committed
525
526
527
528
529
530
        priv->webkit_chat_container,
        "ready",
        G_CALLBACK(webkit_chat_container_ready),
        self
    );

531
    priv->webkit_send_text = g_signal_connect(priv->webkit_chat_container,
532
533
        "script-dialog",
        G_CALLBACK(webkit_chat_container_script_dialog),
534
535
        self);

aviau's avatar
aviau committed
536
537
538
    if (webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)))
        webkit_chat_container_ready(self);

539
    gtk_widget_set_visible(priv->hbox_chat_info, TRUE);
aviau's avatar
aviau committed
540

541
}
Stepan Salenikovich's avatar
Stepan Salenikovich committed
542
543

GtkWidget *
544
545
546
chat_view_new (WebKitChatContainer* webkit_chat_container,
               AccountContainer* accountContainer,
               lrc::api::conversation::Info* conversation)
Stepan Salenikovich's avatar
Stepan Salenikovich committed
547
548
549
{
    ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));

aviau's avatar
aviau committed
550
551
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
    priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
552
553
    priv->conversation_ = conversation;
    priv->accountContainer_ = accountContainer;
aviau's avatar
aviau committed
554
555

    build_chat_view(self);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
556
557
558
    return (GtkWidget *)self;
}

559
void
560
chat_view_update_temporary(ChatView* self, bool showAddButton, bool showInvitation)
561
{
562
    g_return_if_fail(IS_CHAT_VIEW(self));
563
564
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

565
    priv->isTemporary_ = showAddButton;
566
567
568
569
    if (!priv->isTemporary_) {
        gtk_widget_hide(priv->button_add_to_conversations);
    }
    webkit_chat_container_set_temporary(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container), priv->isTemporary_);
570
    if (!priv->conversation_) return;
571
    auto contactUri = priv->conversation_->participants.front();
572
573
574
575
576
577
578
579
    try {
        auto contactInfo = priv->accountContainer_->info.contactModel->getContact(contactUri);
        auto bestName = contactInfo.profileInfo.alias;
        if (bestName.empty())
            bestName = contactInfo.registeredName;
        if (bestName.empty())
            bestName = contactInfo.profileInfo.uri;
        webkit_chat_container_set_invitation(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
580
                                             showInvitation,
581
582
583
584
                                             bestName);
    } catch (const std::out_of_range&) {
        // ContactModel::getContact() exception
    }
585
586
}

587
588
bool
chat_view_get_temporary(ChatView *self)
589
{
590
    g_return_val_if_fail(IS_CHAT_VIEW(self), false);
591
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
592
    return priv->isTemporary_;
593
594
}

595
596
lrc::api::conversation::Info
chat_view_get_conversation(ChatView *self)
597
{
598
    g_return_val_if_fail(IS_CHAT_VIEW(self), lrc::api::conversation::Info());
599
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
600
    return *priv->conversation_;
601
}
602
603
604
605
606
607
608

void
chat_view_set_header_visible(ChatView *self, gboolean visible)
{
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
    gtk_widget_set_visible(priv->hbox_chat_info, visible);
}