chatview.cpp 21.5 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
167
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
static gchar*
file_to_manipulate(GtkWindow* top_window, bool send)
{
    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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
    } 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()));
                if (auto filename = file_to_manipulate(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))), false))
                    model->acceptTransfer(priv->conversation_->uid, interactionId, filename);
                else
                    model->cancelTransfer(priv->conversation_->uid, interactionId);
            } 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);
        }
246
247
248
    }
}

249
250
251
252
253
254
static void
chat_view_init(ChatView *view)
{
    gtk_widget_init_template(GTK_WIDGET(view));

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

257
    g_signal_connect(priv->button_close_chatview, "clicked", G_CALLBACK(hide_chat_view), view);
258
    g_signal_connect_swapped(priv->button_placecall, "clicked", G_CALLBACK(placecall_clicked), view);
259
    g_signal_connect_swapped(priv->button_add_to_conversations, "clicked", G_CALLBACK(button_add_to_conversations_clicked), view);
260
    g_signal_connect_swapped(priv->button_place_audio_call, "clicked", G_CALLBACK(place_audio_call_clicked), view);
261
262
263
264
265
266
267
268
269
270
}

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
271
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, box_webkit_chat_container);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
272
273
    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);
274
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_cm);
275
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_close_chatview);
276
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_placecall);
277
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_add_to_conversations);
278
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_place_audio_call);
279
280

    chat_view_signals[NEW_MESSAGES_DISPLAYED] = g_signal_new (
281
        "new-interactions-displayed",
282
283
284
285
286
287
288
        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);
289
290
291
292
293
294
295
296
297
298

    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);
299
300
}

aviau's avatar
aviau committed
301
static void
302
print_interaction_to_buffer(ChatView* self, uint64_t interactionId, const lrc::api::interaction::Info& interaction)
aviau's avatar
aviau committed
303
304
305
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

306
    if (!priv->conversation_) return;
307
308
309
310
    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
311
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
312
        *priv->accountContainer_->info.conversationModel,
313
314
        interactionId,
        interaction
aviau's avatar
aviau committed
315
    );
316
317
}

318
static void
319
update_interaction(ChatView* self, uint64_t interactionId, const lrc::api::interaction::Info& interaction)
320
321
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
322
323
    webkit_chat_container_update_interaction(
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
324
        *priv->accountContainer_->info.conversationModel,
325
326
        interactionId,
        interaction
327
    );
328
}
329

330
331
332
333
334
static void
load_participants_images(ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
335

336
    // Contact
337
    if (!priv->conversation_) return;
338
    auto contactUri = priv->conversation_->participants.front();
339
340
341
342
343
344
345
346
347
348
349
    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
350
351
    }

352
353
354
355
356
357
358
    // 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
        );
359
360
361
    }
}

362
static void
363
print_text_recording(ChatView *self)
364
365
366
367
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

368
    // Read interactions
369
    if (!priv->conversation_) return;
370
371
372
373
374
    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);
    }

375
376
    webkit_chat_container_print_history(
        WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
377
        *priv->accountContainer_->info.conversationModel,
378
379
        priv->conversation_->interactions
    );
380

381
    QObject::disconnect(priv->new_interaction_connection);
382
383
}

384
static void
385
update_add_to_conversations(ChatView *self)
386
387
388
{
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

389
    if (!priv->conversation_) return;
390
    auto participant = priv->conversation_->participants[0];
391
392
393
394
395
396
397
398
    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
    }
399
400
}

Stepan Salenikovich's avatar
Stepan Salenikovich committed
401
402
403
404
405
static void
update_contact_methods(ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
406
    if (!priv->conversation_) return;
407
    auto contactUri = priv->conversation_->participants.front();
408
409
410
411
412
413
414
415
416
417
418
    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
419
    }
Stepan Salenikovich's avatar
Stepan Salenikovich committed
420
421
422
}

static void
423
update_name(ChatView *self)
Stepan Salenikovich's avatar
Stepan Salenikovich committed
424
{
425
    g_return_if_fail(IS_CHAT_VIEW(self));
Stepan Salenikovich's avatar
Stepan Salenikovich committed
426
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
427
    if (!priv->conversation_) return;
428
    auto contactUri = priv->conversation_->participants.front();
429
430
431
432
433
434
435
436
    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
437
438
}

aviau's avatar
aviau committed
439
440
441
442
443
444
445
446
447
448
449
450
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)
    );

451
    display_links_toggled(self);
452
453
454
455
    print_text_recording(self);
    load_participants_images(self);

    priv->new_interaction_connection = QObject::connect(
456
    &*priv->accountContainer_->info.conversationModel, &lrc::api::ConversationModel::newInteraction,
457
    [self, priv](const std::string& uid, uint64_t interactionId, lrc::api::interaction::Info interaction) {
458
        if (!priv->conversation_) return;
459
460
461
462
        if(uid == priv->conversation_->uid) {
            print_interaction_to_buffer(self, interactionId, interaction);
        }
    });
463

464
465
466
    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) {
467
        if (!priv->conversation_) return;
468
469
470
471
472
        if(uid == priv->conversation_->uid) {
            update_interaction(self, msgId, msg);
        }
    });

473
    if (!priv->conversation_) return;
474
    auto contactUri = priv->conversation_->participants.front();
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
    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
495
496
497
498
499
500
501
502
503
504
}

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);

505
    update_name(self);
506
    update_add_to_conversations(self);
507
    update_contact_methods(self);
aviau's avatar
aviau committed
508

509
    priv->webkit_ready = g_signal_connect_swapped(
aviau's avatar
aviau committed
510
511
512
513
514
515
        priv->webkit_chat_container,
        "ready",
        G_CALLBACK(webkit_chat_container_ready),
        self
    );

516
    priv->webkit_send_text = g_signal_connect(priv->webkit_chat_container,
517
518
        "script-dialog",
        G_CALLBACK(webkit_chat_container_script_dialog),
519
520
        self);

aviau's avatar
aviau committed
521
522
523
    if (webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)))
        webkit_chat_container_ready(self);

524
    gtk_widget_set_visible(priv->hbox_chat_info, TRUE);
aviau's avatar
aviau committed
525

526
}
Stepan Salenikovich's avatar
Stepan Salenikovich committed
527
528

GtkWidget *
529
530
531
chat_view_new (WebKitChatContainer* webkit_chat_container,
               AccountContainer* accountContainer,
               lrc::api::conversation::Info* conversation)
Stepan Salenikovich's avatar
Stepan Salenikovich committed
532
533
534
{
    ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL));

aviau's avatar
aviau committed
535
536
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
    priv->webkit_chat_container = GTK_WIDGET(webkit_chat_container);
537
538
    priv->conversation_ = conversation;
    priv->accountContainer_ = accountContainer;
aviau's avatar
aviau committed
539
540

    build_chat_view(self);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
541
542
543
    return (GtkWidget *)self;
}

544
void
545
chat_view_update_temporary(ChatView* self, bool showAddButton, bool showInvitation)
546
{
547
    g_return_if_fail(IS_CHAT_VIEW(self));
548
549
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

550
    priv->isTemporary_ = showAddButton;
551
552
553
554
    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_);
555
    if (!priv->conversation_) return;
556
    auto contactUri = priv->conversation_->participants.front();
557
558
559
560
561
562
563
564
    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),
565
                                             showInvitation,
566
567
568
569
                                             bestName);
    } catch (const std::out_of_range&) {
        // ContactModel::getContact() exception
    }
570
571
}

572
573
bool
chat_view_get_temporary(ChatView *self)
574
{
575
    g_return_val_if_fail(IS_CHAT_VIEW(self), false);
576
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
577
    return priv->isTemporary_;
578
579
}

580
581
lrc::api::conversation::Info
chat_view_get_conversation(ChatView *self)
582
{
583
    g_return_val_if_fail(IS_CHAT_VIEW(self), lrc::api::conversation::Info());
584
    auto priv = CHAT_VIEW_GET_PRIVATE(self);
585
    return *priv->conversation_;
586
}
587
588
589
590
591
592
593

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);
}