blob: f418d502ffbe987783ec9a4144f5826d87c54a7e [file] [log] [blame]
Edric Milaret627500d2015-03-27 16:41:40 -04001/***************************************************************************
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04002 * Copyright (C) 2015-2018 by Savoir-faire Linux *
Edric Milaret627500d2015-03-27 16:41:40 -04003 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -04004 * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> *
5 * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> *
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04006 * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> *
Isa Nanic37ccc1c2018-10-26 14:16:28 -04007 * Author: Isa Nanic <isa.nanic@savoirfairelinux.com> *
Edric Milaret627500d2015-03-27 16:41:40 -04008 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 3 of the License, or *
12 * (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
21 **************************************************************************/
22
23#include "callwidget.h"
24#include "ui_callwidget.h"
25
Andreas Traczyk912242e2018-10-29 14:44:44 -040026#include <QScrollBar>
Edric Milaret43f3c1e2015-07-16 17:52:47 -040027#include <QClipboard>
Edric Milaret70ae8782016-04-18 16:10:44 -040028#include <QDesktopServices>
Isa Nanic601de1d2018-10-23 11:37:26 -040029#include <QComboBox>
Andreas Traczyk43c08232018-10-31 13:42:09 -040030#include <QWebEngineScript>
Edric Milaret43f3c1e2015-07-16 17:52:47 -040031
Sébastien Blin942d1022018-12-13 09:49:03 -050032#include <algorithm>
Edric Milaret53f57b62015-05-11 11:02:17 -040033#include <memory>
Edric Milaret627500d2015-03-27 16:41:40 -040034
Edric Milarete19c4cd2016-02-12 10:19:44 -050035#include "qrencode.h"
36
Edric Milaret43f3c1e2015-07-16 17:52:47 -040037//ERROR is defined in windows.h
38#include "utils.h"
39#undef ERROR
Edric Milareta0ebd062016-01-13 12:18:23 -050040#undef interface
Edric Milaret43f3c1e2015-07-16 17:52:47 -040041
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040042// lrc
Edric Milareta0ebd062016-01-13 12:18:23 -050043#include "globalinstances.h"
Olivier SOLDANO69361192017-04-20 10:32:05 -040044#include "profilemodel.h"
Olivier SOLDANO69361192017-04-20 10:32:05 -040045#include "localprofilecollection.h"
Anthony Léonardd47179c2017-03-28 10:39:10 -040046
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040047// client
Edric Milaret559bda52015-04-29 17:02:31 -040048#include "wizarddialog.h"
Edric Milaret83b248c2015-06-02 11:42:23 -040049#include "windowscontactbackend.h"
Edric Milaret2cf34292015-06-22 16:27:03 -040050#include "globalsystemtray.h"
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040051#include "conversationitemdelegate.h"
Edric Milareta0ebd062016-01-13 12:18:23 -050052#include "pixbufmanipulator.h"
Edric Milaret70ae8782016-04-18 16:10:44 -040053#include "settingskey.h"
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040054#include "lrcinstance.h"
Andreas Traczyk43c08232018-10-31 13:42:09 -040055#include "animationhelpers.h"
56#include "ringthemeutils.h"
Edric Milaret25236d92016-03-28 09:40:58 -040057
Nicolas Jager97a21b42015-12-03 16:55:45 -050058CallWidget::CallWidget(QWidget* parent) :
Nicolas Jager74fe46f2016-02-29 14:55:09 -050059 NavWidget(parent),
Edric Milaret7d40a4a2015-05-13 13:01:15 -040060 ui(new Ui::CallWidget),
Andreas Traczyk43c08232018-10-31 13:42:09 -040061 menu_(new QMenu())
Edric Milaret627500d2015-03-27 16:41:40 -040062{
63 ui->setupUi(this);
64
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040065 using namespace lrc::api;
Nicolas Jagerca850292016-01-17 14:11:10 -050066
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040067 QApplication::setEffectEnabled(Qt::UI_AnimateCombo, false);
Edric Milaret3aca8e32015-06-12 10:01:40 -040068
Sébastien Blincba5b522018-12-10 12:48:36 -050069 QPixmap logo(":/images/logo-jami-standard-coul.png");
Edric Milareted0b2802015-10-01 15:10:02 -040070 ui->ringLogo->setPixmap(logo.scaledToHeight(100, Qt::SmoothTransformation));
71 ui->ringLogo->setAlignment(Qt::AlignHCenter);
72
Edric Milaret1e598592016-09-02 10:10:01 -040073 ui->qrLabel->hide();
Edric Milarete19c4cd2016-02-12 10:19:44 -050074
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040075 videoRenderer_ = nullptr;
Edric Milaret627500d2015-03-27 16:41:40 -040076
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040077 // this line is not welcome here, and must be removed
78 ProfileModel::instance().addCollection<LocalProfileCollection>(LoadOptions::FORCE_ENABLED);
Edric Milaret627500d2015-03-27 16:41:40 -040079
Andreas Traczyk43c08232018-10-31 13:42:09 -040080 QSettings settings;
81
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040082 // select last used account if stored in registry
83 auto accountList = LRCInstance::accountModel().getAccountList();
84 if (!accountList.empty()) {
85 std::string accountIdToStartWith;
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040086 if (settings.contains(SettingsKey::selectedAccount)) {
87 accountIdToStartWith = settings
88 .value(SettingsKey::selectedAccount, true)
89 .value<QString>()
90 .toStdString();
91 if (Utils::indexInVector(accountList, accountIdToStartWith) == -1) {
92 accountIdToStartWith = accountList.at(0);
Olivier SOLDANOaf8f2822017-07-11 12:15:18 -040093 }
Andreas Traczykb8b13ba2018-08-21 16:30:16 -040094 }
95 else {
96 accountIdToStartWith = accountList.at(0);
97 }
98 setSelectedAccount(accountIdToStartWith);
Isa Nanic601de1d2018-10-23 11:37:26 -040099 // get account index and set the currentAccountComboBox
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400100 auto index = Utils::indexInVector(accountList, accountIdToStartWith);
101 if (index != -1) {
Isa Nanic601de1d2018-10-23 11:37:26 -0400102 ui->currentAccountComboBox->setCurrentIndex(index);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400103 }
Edric Milaret627500d2015-03-27 16:41:40 -0400104 }
Olivier SOLDANO2100f1c2017-09-06 16:45:20 -0400105
Andreas Traczyk43c08232018-10-31 13:42:09 -0400106 if (settings.contains(SettingsKey::mainSplitterState)) {
107 auto splitterStates = settings.value(SettingsKey::mainSplitterState).toByteArray();
108 ui->mainActivitySplitter->restoreState(splitterStates);
109 }
110
111 ui->mainActivitySplitter->setCollapsible(0, false);
Sébastien Blin93bd2062018-12-17 15:57:16 -0500112 ui->mainActivitySplitter->setCollapsible(1, false);
Andreas Traczyk43c08232018-10-31 13:42:09 -0400113 ui->splitter->setCollapsible(0, false);
114 ui->splitter->setCollapsible(1, false);
115
Isa Nanic601de1d2018-10-23 11:37:26 -0400116 //disable dropdown shadow on combobox
117 ui->currentAccountComboBox->view()->window()->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint);
118
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400119 // conversation list
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400120 ui->smartList->setContextMenuPolicy(Qt::CustomContextMenu);
121
122 // setup searchingfor mini spinner
123 miniSpinner_ = new QMovie(":/images/waiting.gif");
124 ui->spinnerLabel->setMovie(miniSpinner_);
125 ui->spinnerLabel->hide();
126
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400127 // connections
Isa Nanic37ccc1c2018-10-26 14:16:28 -0400128 connect(ui->currentAccountComboBox, &CurrentAccountComboBox::settingsButtonClicked,
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400129 this, &CallWidget::settingsButtonClicked);
130
Andreas Traczyk43c08232018-10-31 13:42:09 -0400131 connect(ui->videoWidget, &VideoView::setChatVisibility,
132 [this](bool visible) {
Sébastien Blin93bd2062018-12-17 15:57:16 -0500133 if (visible) {
134 ui->messagesWidget->show();
135 } else {
136 ui->messagesWidget->hide();
137 }
Andreas Traczyk43c08232018-10-31 13:42:09 -0400138 });
139
140 connect(ui->mainActivitySplitter, &QSplitter::splitterMoved,
141 [this](int pos, int index) {
142 QSettings settings;
143 settings.setValue(SettingsKey::mainSplitterState, ui->mainActivitySplitter->saveState());
144 });
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400145
146 connect(ui->videoWidget, &VideoView::videoSettingsClicked,
147 this, &CallWidget::settingsButtonClicked);
148
Sébastien Blin62b08ac2018-12-14 16:18:04 -0500149 connect(ui->videoWidget, &VideoView::toggleFullScreenClicked,
150 this, &CallWidget::slotToggleFullScreenClicked);
151
152 connect(ui->videoWidget, &VideoView::closing,
153 this, &CallWidget::slotVideoViewDestroyed);
154
Andreas Traczyk43c08232018-10-31 13:42:09 -0400155 connect(ui->btnConversations, &QPushButton::clicked,
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400156 this, &CallWidget::conversationsButtonClicked);
157
Andreas Traczyk43c08232018-10-31 13:42:09 -0400158 connect(ui->btnInvites, &QPushButton::clicked,
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400159 this, &CallWidget::invitationsButtonClicked);
160
Andreas Traczyk43c08232018-10-31 13:42:09 -0400161 connect(ui->smartList, &QTreeView::customContextMenuRequested,
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400162 this, &CallWidget::slotCustomContextMenuRequested);
163
164 connect(ui->smartList, &SmartListView::btnAcceptInviteClicked,
165 this, &CallWidget::slotAcceptInviteClicked);
166
167 connect(ui->smartList, &SmartListView::btnBlockInviteClicked,
168 this, &CallWidget::slotBlockInviteClicked);
169
170 connect(ui->smartList, &SmartListView::btnIgnoreInviteClicked,
171 this, &CallWidget::slotIgnoreInviteClicked);
172
173 connect(&LRCInstance::behaviorController(), &BehaviorController::showCallView,
174 this, &CallWidget::slotShowCallView);
175
176 connect(&LRCInstance::behaviorController(), &BehaviorController::showIncomingCallView,
177 this, &CallWidget::slotShowIncomingCallView);
178
179 connect(&LRCInstance::behaviorController(), &BehaviorController::showChatView,
180 this, &CallWidget::slotShowChatView);
Andreas Traczyk55f92cb2018-10-23 12:26:25 -0400181
Isa Nanic601de1d2018-10-23 11:37:26 -0400182 connect(ui->currentAccountComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
183 this, &CallWidget::slotAccountChanged);
184
Andreas Traczyk912242e2018-10-29 14:44:44 -0400185 connect(ui->sendContactRequestButton, &QPushButton::clicked,
186 this, &CallWidget::on_sendContactRequestButton_clicked);
187
188 connect(ui->btnAudioCall, &QPushButton::clicked,
189 this, &CallWidget::on_sendContactRequestButton_clicked);
190
191 connect(ui->btnVideoCall, &QPushButton::clicked,
192 this, &CallWidget::on_sendContactRequestButton_clicked);
193
Isa Nanic37ccc1c2018-10-26 14:16:28 -0400194 connect(ui->currentAccountComboBox, QOverload<int>::of(&CurrentAccountComboBox::currentIndexChanged),
195 [this] {
Andreas Traczyk43c08232018-10-31 13:42:09 -0400196 ui->btnConversations->setChecked(true);
197 ui->btnInvites->setChecked(false);
198 });
199
Andreas Traczyk55f92cb2018-10-23 12:26:25 -0400200 // set first view to welcome view
201 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Andreas Traczyk43c08232018-10-31 13:42:09 -0400202 ui->btnConversations->setChecked(true);
203
204 // chat view
205 ui->messageView->buildView();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500206
Andreas Traczykb81281e2018-12-13 13:13:28 -0500207 // hide the call stack
208 ui->callStackWidget->hide();
Andreas Traczykfc33a492018-12-14 13:53:13 -0500209
210 ui->containerWidget->setVisible(false);
Edric Milaret627500d2015-03-27 16:41:40 -0400211}
212
213CallWidget::~CallWidget()
214{
215 delete ui;
Edric Milaretc7ab5502015-06-15 11:18:02 -0400216 delete menu_;
Edric Milaret00a32252016-01-19 10:37:13 -0500217}
218
Andreas Traczykfc33a492018-12-14 13:53:13 -0500219void
220CallWidget::navigated(bool to)
221{
222 ui->containerWidget->setVisible(to);
223 if (to) {
224 updateSmartList();
225 connectConversationModel();
226 } else {
227 QObject::disconnect(smartlistSelectionConnection_);
228 smartListModel_.reset(nullptr);
229 }
230}
231
Andreas Traczykb81281e2018-12-13 13:13:28 -0500232int
233CallWidget::getLeftPanelWidth()
234{
235 return ui->currentAccountComboBox->width();
236}
237
Edric Milaret00a32252016-01-19 10:37:13 -0500238void
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400239CallWidget::onIncomingMessage(const std::string& convUid,
240 uint64_t interactionId,
241 const lrc::api::interaction::Info& interaction)
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400242{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400243 Q_UNUSED(interactionId);
Edric Milaret00a32252016-01-19 10:37:13 -0500244 if (!QApplication::focusWidget()) {
Andreas Traczyk43c08232018-10-31 13:42:09 -0400245 auto convModel = LRCInstance::getCurrentConversationModel();
246 auto conversation = Utils::getConversationFromUid(convUid, *convModel);
247 auto bestName = Utils::bestNameForConversation(*conversation, *convModel);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400248 Utils::showSystemNotification(this,
249 QString(tr("Message incoming from %1"))
Andreas Traczyk43c08232018-10-31 13:42:09 -0400250 .arg(QString::fromStdString(bestName)));
Edric Milaret00a32252016-01-19 10:37:13 -0500251 }
Andreas Traczyk1d8159a2018-12-13 15:48:24 -0500252 updateConversationsFilterWidget();
Andreas Traczyk43c08232018-10-31 13:42:09 -0400253 if (convUid != selectedConvUid()) {
254 return;
255 }
256
257 auto convModel = LRCInstance::getCurrentConversationModel();
258 convModel->clearUnreadInteractions(convUid);
259 auto currentConversation = Utils::getConversationFromUid(convUid, *convModel);
260 if (currentConversation == convModel->allFilteredConversations().end()) {
261 return;
262 }
263 ui->messageView->printNewInteraction(*convModel, interactionId, interaction);
Edric Milareta0ebd062016-01-13 12:18:23 -0500264}
265
266void
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400267CallWidget::setupSmartListContextMenu(const QPoint& pos)
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400268{
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400269 QPoint globalPos = ui->smartList->mapToGlobal(pos);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400270 auto index = ui->smartList->indexAt(pos);
271 if (not index.isValid()) {
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400272 return;
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400273 }
274
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400275 auto convModel = LRCInstance::getCurrentConversationModel();
276 auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID))
277 .value<QString>()
278 .toStdString();
279 auto conversation = Utils::getConversationFromUid(convUid, *convModel);
280 auto contactUid = (*conversation).participants.at(0);
281 auto contact = LRCInstance::getCurrentAccountInfo().contactModel.get()->getContact(contactUid);
282
283 if (!Utils::isContactValid(contactUid, *convModel)) {
284 return;
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400285 }
286
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400287 QMenu menu;
288
289 // video call
290 auto videoCallAction = new QAction(tr("Start video call"), this);
291 menu.addAction(videoCallAction);
292 connect(videoCallAction, &QAction::triggered,
293 [this, convUid, conversation, convModel]() {
294 convModel->placeCall(convUid);
295 ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid)));
296 if (convUid != selectedConvUid()) {
297 selectConversation(*conversation, *convModel);
298 }
299 });
300 // audio call
301 auto audioCallAction = new QAction(tr("Start audio call"), this);
302 menu.addAction(audioCallAction);
303 connect(audioCallAction, &QAction::triggered,
304 [this, convUid, conversation, convModel]() {
305 convModel->placeAudioOnlyCall(convUid);
306 ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid)));
307 if (convUid != selectedConvUid()) {
308 selectConversation(*conversation, *convModel);
309 }
310 });
311
312 if (contact.profileInfo.type == lrc::api::profile::Type::RING) {
313 // separator
314 menu.addSeparator();
315
316 // clear conversation
317 auto clearConversationAction = new QAction(tr("Clear conversation"), this);
318 menu.addAction(clearConversationAction);
319 connect(clearConversationAction, &QAction::triggered,
320 [convUid]() {
321 LRCInstance::getCurrentConversationModel()->clearHistory(convUid);
322 });
Sébastien Blin31fccce2018-12-13 11:27:05 -0500323 // remove contact
324 auto removeContactAction = new QAction(tr("Remove contact"), this);
325 menu.addAction(removeContactAction);
326 connect(removeContactAction, &QAction::triggered,
327 [convUid]() {
328 LRCInstance::getCurrentConversationModel()->removeConversation(convUid, false);
329 });
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400330 // block contact
331 auto blockContactAction = new QAction(tr("Block contact"), this);
332 menu.addAction(blockContactAction);
333 connect(blockContactAction, &QAction::triggered,
334 [convUid]() {
335 LRCInstance::getCurrentConversationModel()->removeConversation(convUid, true);
336 });
337
338 // separator
339 menu.addSeparator();
340
341 // copy number(infohash)
342 auto copyNumberAction = new QAction(tr("Copy number"), this);
343 menu.addAction(copyNumberAction);
344 connect(copyNumberAction, &QAction::triggered,
345 [contact]() {
346 QApplication::clipboard()->setText(
347 QString::fromStdString(contact.profileInfo.uri)
348 );
349 });
350 }
Andreas Traczyk43c08232018-10-31 13:42:09 -0400351 smartListModel_->isContextMenuOpen = true;
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400352 menu.exec(globalPos);
Andreas Traczyk43c08232018-10-31 13:42:09 -0400353 smartListModel_->isContextMenuOpen = false;
Edric Milareta0ebd062016-01-13 12:18:23 -0500354}
355
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400356void
357CallWidget::setupQRCode(QString ringID)
Edric Milarete19c4cd2016-02-12 10:19:44 -0500358{
Anthony Léonarda86a8972016-12-15 10:33:47 -0500359 auto rcode = QRcode_encodeString(ringID.toStdString().c_str(),
Edric Milaret6d0e5312016-04-04 16:30:22 -0400360 0, //Let the version be decided by libqrencode
361 QR_ECLEVEL_L, // Lowest level of error correction
Edric Milarete19c4cd2016-02-12 10:19:44 -0500362 QR_MODE_8, // 8-bit data mode
363 1);
364 if (not rcode) {
365 qWarning() << "Failed to generate QR code: " << strerror(errno);
366 return;
367 }
368
369 auto margin = 5;
370 int qrwidth = rcode->width + margin * 2;
371 QImage result(QSize(qrwidth, qrwidth), QImage::Format_Mono);
372 QPainter painter;
373 painter.begin(&result);
374 painter.setClipRect(QRect(0, 0, qrwidth, qrwidth));
375 painter.setPen(QPen(Qt::black, 0.1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
376 painter.setBrush(Qt::black);
377 painter.fillRect(QRect(0, 0, qrwidth, qrwidth), Qt::white);
Edric Milaret74474f52016-05-16 13:36:23 -0400378 unsigned char* p;
Edric Milarete19c4cd2016-02-12 10:19:44 -0500379 p = rcode->data;
380 for(int y = 0; y < rcode->width; y++) {
Edric Milaret74474f52016-05-16 13:36:23 -0400381 unsigned char* row = (p + (y * rcode->width));
Edric Milarete19c4cd2016-02-12 10:19:44 -0500382 for(int x = 0; x < rcode->width; x++) {
383 if(*(row + x) & 0x1) {
384 painter.drawRect(margin + x, margin + y, 1, 1);
385 }
386 }
387
388 }
389 painter.end();
390 QRcode_free(rcode);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400391 ui->qrLabel->setPixmap(QPixmap::fromImage(result.scaled(QSize(qrSize_, qrSize_),
392 Qt::KeepAspectRatio)));
Edric Milarete19c4cd2016-02-12 10:19:44 -0500393}
394
Edric Milaret627500d2015-03-27 16:41:40 -0400395void
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400396CallWidget::on_smartList_clicked(const QModelIndex& index)
Edric Milaret00d34f22016-05-09 16:30:29 -0400397{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400398 Q_UNUSED(index);
Edric Milaret627500d2015-03-27 16:41:40 -0400399}
400
401void
402CallWidget::on_acceptButton_clicked()
403{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400404 auto convModel = LRCInstance::getCurrentConversationModel();
405 auto callModel = LRCInstance::getCurrentCallModel();
406 auto conversation = Utils::getConversationFromUid(selectedConvUid(), *convModel);
407 callModel->accept(conversation->callId);
Edric Milaret627500d2015-03-27 16:41:40 -0400408}
409
410void
411CallWidget::on_refuseButton_clicked()
412{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400413 auto convModel = LRCInstance::getCurrentConversationModel();
414 auto conversation = Utils::getConversationFromUid(selectedConvUid(), *convModel);
415 LRCInstance::getCurrentCallModel()->hangUp(conversation->callId);
416 showConversationView();
Edric Milaret6456baa2015-05-21 12:18:07 -0400417}
Edric Milaretc7ab5502015-06-15 11:18:02 -0400418
419void
Edric Milareted0b2802015-10-01 15:10:02 -0400420CallWidget::on_cancelButton_clicked()
Edric Milaretd8528fa2015-07-07 14:13:51 -0400421{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400422 auto convModel = LRCInstance::getCurrentConversationModel();
423 auto conversation = Utils::getConversationFromUid(selectedConvUid(), *convModel);
424 LRCInstance::getCurrentCallModel()->hangUp(conversation->callId);
425 showConversationView();
Edric Milaretd8528fa2015-07-07 14:13:51 -0400426}
Edric Milareted0b2802015-10-01 15:10:02 -0400427
428void
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400429CallWidget::showConversationView()
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400430{
Andreas Traczyk43c08232018-10-31 13:42:09 -0400431 ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget);
432 ui->messageView->setFocus();
Sébastien Blin93bd2062018-12-17 15:57:16 -0500433 if (ui->messagesWidget->isHidden()) {
434 ui->messagesWidget->show();
435 }
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400436}
437
438void
439CallWidget::selectSmartlistItem(const std::string & convUid)
440{
441 if (convUid.empty()) {
442 return;
443 }
444 ui->smartList->selectionModel()->setCurrentIndex(QModelIndex(), QItemSelectionModel::Deselect);
445 auto convModel = LRCInstance::getCurrentConversationModel();
446 auto conversation = Utils::getConversationFromUid(convUid, *convModel);
447 if (conversation == convModel->allFilteredConversations().end()) {
448 return;
449 }
450 auto contactURI = QString::fromStdString((*conversation).participants[0]);
451 if (contactURI.isEmpty() ||
452 convModel->owner.contactModel->getContact(contactURI.toStdString()).profileInfo.type == lrc::api::profile::Type::TEMPORARY) {
453 return;
454 }
455 for (int row = 0; row < smartListModel_->rowCount(); row++) {
456 QModelIndex index = smartListModel_->index(row);
457 auto indexContactURI = index.data(SmartListModel::Role::URI).value<QString>();
458 if (indexContactURI == contactURI) {
459 ui->smartList->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
460 return;
461 }
462 }
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400463}
464
465void
Nicolas Jager97a21b42015-12-03 16:55:45 -0500466CallWidget::on_smartList_doubleClicked(const QModelIndex& index)
Edric Milareted0b2802015-10-01 15:10:02 -0400467{
Olivier SOLDANO70279d32017-07-18 15:21:34 -0400468 if (!index.isValid())
469 return;
470
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400471 LRCInstance::getCurrentConversationModel()->placeCall(selectedConvUid());
Edric Milareted0b2802015-10-01 15:10:02 -0400472
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400473 ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(selectedConvUid())));
474}
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500475
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400476QImage
477CallWidget::imageForConv(const std::string& convUid)
478{
479 return Utils::conversationPhoto(convUid, LRCInstance::getCurrentAccountInfo());
480}
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500481
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400482const std::string&
483CallWidget::selectedAccountId()
484{
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500485 return LRCInstance::getCurrAccId();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400486}
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500487
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400488const std::string&
489CallWidget::selectedConvUid()
490{
491 return LRCInstance::getSelectedConvUid();
Edric Milareted0b2802015-10-01 15:10:02 -0400492}
493
494void
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400495CallWidget::smartListSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
Olivier SOLDANO61065ec2016-11-11 16:31:34 -0500496{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400497 Q_UNUSED(deselected);
498 QModelIndexList indices = selected.indexes();
499
500 if (indices.isEmpty()) {
Edric Milareted0b2802015-10-01 15:10:02 -0400501 return;
Anthony Léonardecfe7422017-05-04 14:14:37 -0400502 }
Edric Milareted0b2802015-10-01 15:10:02 -0400503
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400504 auto selectedIndex = indices.at(0);
Olivier SOLDANO703caba2016-11-15 16:18:55 -0500505
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400506 if (not selectedIndex.isValid()) {
507 return;
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400508 }
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400509
510 selectConversation(selectedIndex);
Edric Milareted0b2802015-10-01 15:10:02 -0400511}
512
513void
514CallWidget::placeCall()
515{
Nicolas Jager97a21b42015-12-03 16:55:45 -0500516 if (ui->ringContactLineEdit->text().isEmpty())
Edric Milareted0b2802015-10-01 15:10:02 -0400517 return;
Nicolas Jager97a21b42015-12-03 16:55:45 -0500518 Call* c = CallModel::instance().dialingCall(PhoneDirectoryModel::instance().getNumber(ui->ringContactLineEdit->text()));
Edric Milareted0b2802015-10-01 15:10:02 -0400519 c->performAction(Call::Action::ACCEPT);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500520 ui->ringContactLineEdit->clear();
Andreas Traczyk43c08232018-10-31 13:42:09 -0400521 auto photoRect = ui->callingPhoto->frameGeometry();
Edric1bed3f92016-05-19 10:24:48 -0400522 ui->callingPhoto->setPixmap(
523 QPixmap::fromImage(
524 GlobalInstances::pixmapManipulator()
Andreas Traczyk43c08232018-10-31 13:42:09 -0400525 .callPhoto(c, QSize(photoRect.width(), photoRect.height()))
526 .value<QImage>()));
Edric Milareted0b2802015-10-01 15:10:02 -0400527}
528
529void
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400530CallWidget::conversationsButtonClicked()
531{
Andreas Traczyk43c08232018-10-31 13:42:09 -0400532 ui->btnConversations->setChecked(true);
533 ui->btnInvites->setChecked(false);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400534 setConversationFilter(lrc::api::profile::Type::RING);
535}
536
537void
538CallWidget::invitationsButtonClicked()
539{
Andreas Traczyk43c08232018-10-31 13:42:09 -0400540 ui->btnConversations->setChecked(false);
541 ui->btnInvites->setChecked(true);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400542 setConversationFilter(lrc::api::profile::Type::PENDING);
543}
544
545void
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500546CallWidget::settingsButtonClicked()
Edric Milareted0b2802015-10-01 15:10:02 -0400547{
Andreas Traczyk7548e732018-12-12 10:47:21 -0500548 emit NavigationRequested(ScreenEnum::SetttingsScreen);
Edric Milareted0b2802015-10-01 15:10:02 -0400549}
550
551void
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400552CallWidget::processContactLineEdit()
Nicolas Jager97a21b42015-12-03 16:55:45 -0500553{
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400554 auto contactLineText = ui->ringContactLineEdit->text();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400555 setConversationFilter(contactLineText);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500556}
557
558void
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400559CallWidget::on_ringContactLineEdit_returnPressed()
Nicolas Jager97a21b42015-12-03 16:55:45 -0500560{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400561 // select current temporary item and show conversation
562 auto convModel = LRCInstance::getCurrentConversationModel();
563 auto conversations = convModel->allFilteredConversations();
Andreas Traczyk43c08232018-10-31 13:42:09 -0400564 if (!conversations.empty() &&
565 Utils::isContactValid(conversations.at(0).participants.at(0), *convModel)) {
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400566 selectConversation(smartListModel_->index(0));
567 }
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400568}
569
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400570void CallWidget::slotAcceptInviteClicked(const QModelIndex & index)
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400571{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400572 auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>();
573 LRCInstance::getCurrentConversationModel()->makePermanent(convUid.toStdString());
Nicolas Jager97a21b42015-12-03 16:55:45 -0500574}
575
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400576void CallWidget::slotBlockInviteClicked(const QModelIndex & index)
Nicolas Jager97a21b42015-12-03 16:55:45 -0500577{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400578 auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>();
579 LRCInstance::getCurrentConversationModel()->removeConversation(convUid.toStdString(), true);
580}
581
582void CallWidget::slotIgnoreInviteClicked(const QModelIndex & index)
583{
584 auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>();
Sébastien Blin31fccce2018-12-13 11:27:05 -0500585 LRCInstance::getCurrentConversationModel()->removeConversation(convUid.toStdString(), false);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400586}
587
588void CallWidget::slotCustomContextMenuRequested(const QPoint& pos)
589{
590 setupSmartListContextMenu(pos);
591}
592
Isa Nanic601de1d2018-10-23 11:37:26 -0400593void CallWidget::slotAccountChanged(int index)
594{
595 auto accountList = LRCInstance::accountModel().getAccountList();
596 setSelectedAccount(accountList.at(index));
597}
598
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400599void CallWidget::slotShowCallView(const std::string& accountId,
600 const lrc::api::conversation::Info& convInfo)
601{
602 Q_UNUSED(accountId);
603 Q_UNUSED(convInfo);
Andreas Traczyk43c08232018-10-31 13:42:09 -0400604 qDebug() << "slotShowCallView";
605 ui->callStackWidget->show();
606 ui->callStackWidget->setCurrentWidget(ui->videoPage);
Sébastien Blin93bd2062018-12-17 15:57:16 -0500607 ui->videoWidget->showChatviewIfToggled();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400608 hideMiniSpinner();
609}
610
611void CallWidget::slotShowIncomingCallView(const std::string& accountId,
Andreas Traczyk43c08232018-10-31 13:42:09 -0400612 const lrc::api::conversation::Info& convInfo)
613{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400614 Q_UNUSED(accountId);
Andreas Traczyk43c08232018-10-31 13:42:09 -0400615 qDebug() << "slotShowIncomingCallView";
616
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400617 auto callModel = LRCInstance::getCurrentCallModel();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400618
619 if (!callModel->hasCall(convInfo.callId)) {
Nicolas Jager97a21b42015-12-03 16:55:45 -0500620 return;
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400621 }
Nicolas Jager97a21b42015-12-03 16:55:45 -0500622
Andreas Traczyk43c08232018-10-31 13:42:09 -0400623 auto convModel = LRCInstance::getCurrentConversationModel();
624 ui->callerPhoto->setPixmap(QPixmap::fromImage(imageForConv(convInfo.uid)));
625 auto bestName = QString::fromStdString(Utils::bestNameForConversation(convInfo, *convModel));
626 auto bestId = QString::fromStdString(Utils::bestIdForConversation(convInfo, *convModel));
627 auto finalBestId = (bestName != bestId) ? bestId : "";
628
629 auto call = callModel->getCall(convInfo.callId);
630 auto isCallSelected = selectedConvUid() == convInfo.uid;
631
632 if (call.isOutgoing) {
633 if (isCallSelected) {
634 miniSpinner_->start();
635 ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget);
636 ui->spinnerLabel->show();
637 ui->callStackWidget->setCurrentWidget(ui->outgoingCallPage);
638 ui->callStackWidget->show();
639 }
640 } else {
641 if (!QApplication::focusWidget()) {
642 auto formattedName = Utils::bestNameForConversation(convInfo, *convModel);
643 Utils::showSystemNotification(this,
644 QString(tr("Call incoming from %1")).arg(QString::fromStdString(formattedName)));
645 }
646 selectSmartlistItem(convInfo.uid);
647 auto selectedAccountId = LRCInstance::getCurrentAccountInfo().id;
648 auto accountProperties = LRCInstance::accountModel().getAccountConfig(selectedAccountId);
649 if (accountProperties.autoAnswer) {
650 ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget);
651 ui->callStackWidget->setCurrentWidget(ui->videoPage);
652 } else if (isCallSelected) {
653 ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget);
654 ui->callStackWidget->setCurrentWidget(ui->incomingCallPage);
655 ui->callStackWidget->show();
656 }
657 }
658
Sébastien Blin93bd2062018-12-17 15:57:16 -0500659 if (ui->messagesWidget->isHidden()) {
660 ui->messagesWidget->show();
661 }
662
Andreas Traczyk43c08232018-10-31 13:42:09 -0400663 // flashing index widget during call
664 for (int row = 0; row < smartListModel_->rowCount(); row++) {
665 QModelIndex index = smartListModel_->index(row);
666 auto indexUid = index.data(SmartListModel::Role::UID).value<QString>().toStdString();
667 if (indexUid == convInfo.uid) {
668 auto widget = ui->smartList->indexWidget(index);
669 if (!widget) {
670 auto blinkingWidget = new AnimatedOverlay(RingTheme::urgentOrange_);
671 ui->smartList->setIndexWidget(index, blinkingWidget);
672 blinkingWidget->show();
673 } else {
674 widget->show();
675 }
676 }
677 }
678
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400679 ui->videoWidget->pushRenderer(convInfo.callId);
Andreas Traczykfd0d7c02018-10-30 17:14:06 -0400680
Andreas Traczyk43c08232018-10-31 13:42:09 -0400681 QFontMetrics primaryCallLabelFontMetrics(ui->callingBestNameLabel->font());
682 QFontMetrics sencondaryCallLabelFontMetrics(ui->callingBestIdLabel->font());
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400683
Andreas Traczyk43c08232018-10-31 13:42:09 -0400684 QString elidedLabel = primaryCallLabelFontMetrics.elidedText(bestName, Qt::ElideRight, ui->callerBestNameLabel->width());
685 ui->callerBestNameLabel->setText(elidedLabel);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400686
Andreas Traczyk43c08232018-10-31 13:42:09 -0400687 elidedLabel = primaryCallLabelFontMetrics.elidedText(bestName, Qt::ElideRight, ui->callingBestNameLabel->width());
688 ui->callingBestNameLabel->setText(elidedLabel);
689
690 elidedLabel = sencondaryCallLabelFontMetrics.elidedText(finalBestId, Qt::ElideRight, ui->callingBestIdLabel->width());
691 ui->callingBestIdLabel->setText(elidedLabel);
692
693 ui->smartList->update();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400694}
695
696void CallWidget::slotShowChatView(const std::string& accountId,
Andreas Traczyk43c08232018-10-31 13:42:09 -0400697 const lrc::api::conversation::Info& convInfo)
698{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400699 Q_UNUSED(accountId);
700 Q_UNUSED(convInfo);
Andreas Traczyk43c08232018-10-31 13:42:09 -0400701
702 for (int row = 0; row < smartListModel_->rowCount(); row++) {
703 QModelIndex index = smartListModel_->index(row);
704 auto indexUid = index.data(SmartListModel::Role::UID).value<QString>().toStdString();
705 if (indexUid == convInfo.uid) {
706 if (auto widget = ui->smartList->indexWidget(index)) {
707 widget->hide();
708 widget->deleteLater();
709 ui->smartList->setIndexWidget(index, nullptr);
710 }
711 }
712 }
713
714 ui->callStackWidget->hide();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400715 showConversationView();
Nicolas Jager97a21b42015-12-03 16:55:45 -0500716}
Edric Milaretab12d022015-12-04 16:09:44 -0500717
718void
Sébastien Blin93bd2062018-12-17 15:57:16 -0500719CallWidget::slotToggleFullScreenClicked()
720{
721 if (ui->mainActivityWidget->isFullScreen()) {
722 ui->stackedWidget->addWidget(ui->mainActivityWidget);
723 ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget);
724 ui->mainActivityWidget->showNormal();
725 } else {
726 ui->stackedWidget->removeWidget(ui->mainActivityWidget);
727 ui->mainActivityWidget->setParent(0);
728 ui->mainActivityWidget->showFullScreen();
729 }
730}
731
732void
733CallWidget::slotVideoViewDestroyed(const std::string& callid)
734{
735 auto convUid = LRCInstance::getSelectedConvUid();
736 auto currentConversationModel = LRCInstance::getCurrentConversationModel();
737 auto callModel = LRCInstance::getCurrentCallModel();
738 auto conversation = Utils::getConversationFromUid(convUid, *currentConversationModel);
Sébastien Blin62b08ac2018-12-14 16:18:04 -0500739 if (conversation != currentConversationModel->allFilteredConversations().end() &&
740 callid != conversation->callId) {
741 return;
742 }
Sébastien Blin93bd2062018-12-17 15:57:16 -0500743 if (ui->mainActivityWidget->isFullScreen()) {
744 ui->stackedWidget->addWidget(ui->mainActivityWidget);
745 ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget);
746 ui->mainActivityWidget->showNormal();
747 }
748 showConversationView();
749}
750
751void
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400752CallWidget::setSelectedAccount(const std::string& accountId)
753{
754 LRCInstance::setSelectedAccountId(accountId);
755
756 // First, we get back to the welcome view (except if in call)
757 if (ui->stackedWidget->currentWidget() != ui->videoPage &&
758 ui->stackedWidget->currentWidget() != ui->welcomePage) {
759 Utils::setStackWidget(ui->stackedWidget, ui->welcomePage);
760 }
761
762 // We setup the ringIdLabel and the QRCode
763 auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountId);
764 auto id = accountInfo.registeredName.empty() ? accountInfo.profileInfo.uri : accountInfo.registeredName;
765 auto isRingAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING;
766 if (isRingAccount) {
767 ui->ringIdLabel->setText(QString::fromStdString(id));
768 setupQRCode(QString::fromStdString(accountInfo.profileInfo.uri));
769 }
770
771 updateSmartList();
772 currentTypeFilter_ = accountInfo.profileInfo.type;
773 LRCInstance::getCurrentConversationModel()->setFilter(accountInfo.profileInfo.type);
774 updateConversationsFilterWidget();
775 connectConversationModel();
776}
777
778void CallWidget::setConversationFilter(lrc::api::profile::Type filter)
779{
780 if (currentTypeFilter_ == filter) {
781 return;
782 }
783 currentTypeFilter_ = filter;
784 LRCInstance::getCurrentConversationModel()->setFilter(currentTypeFilter_);
785}
786
787void CallWidget::updateConversationsFilterWidget()
788{
789 auto invites = LRCInstance::getCurrentAccountInfo().contactModel->pendingRequestCount();
790 if (invites == 0 && currentTypeFilter_ == lrc::api::profile::Type::PENDING) {
791 currentTypeFilter_ = lrc::api::profile::Type::RING;
792 LRCInstance::getCurrentConversationModel()->setFilter(currentTypeFilter_);
793 }
794 ui->conversationsFilterWidget->setVisible(invites);
Andreas Traczyk1d8159a2018-12-13 15:48:24 -0500795 ui->conversationsFilterWidget->updateBadges();
Andreas Traczyk43c08232018-10-31 13:42:09 -0400796 ui->conversationsFilterWidget->update();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400797}
798
799void CallWidget::setConversationFilter(const QString & filter)
800{
801 LRCInstance::getCurrentConversationModel()->setFilter(filter.toStdString());
Anthony Léonardd47179c2017-03-28 10:39:10 -0400802}
803
804void
Edric Milaret6b68a482016-02-01 15:23:44 -0500805CallWidget::showIMOutOfCall(const QModelIndex& nodeIdx)
Edric Milaretab12d022015-12-04 16:09:44 -0500806{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400807 QString displayName = nodeIdx.data(static_cast<int>(SmartListModel::Role::DisplayName)).toString();
808 QString displayId = nodeIdx.data(static_cast<int>(SmartListModel::Role::DisplayID)).toString();
809 QString contactURI = nodeIdx.data(static_cast<int>(SmartListModel::Role::URI)).toString();
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400810
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400811 bool isContact = false;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500812 auto selectedAccountId = LRCInstance::getCurrAccId();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400813 auto& accountInfo = LRCInstance::accountModel().getAccountInfo(selectedAccountId);
814 bool isRINGAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING;
815 try {
816 accountInfo.contactModel->getContact(contactURI.toStdString());
817 isContact = true;
818 }
819 catch (...) {}
820
Olivier SOLDANO31b9aac2017-07-14 15:50:09 -0400821 ui->imNameLabel->setText(QString(tr("%1", "%1 is the contact username"))
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400822 .arg(displayName));
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400823
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400824 if (isRINGAccount && displayName != displayId){
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400825 ui->imIdLabel->show();
826 ui->imIdLabel->setText(QString(tr("%1", "%1 is the contact unique identifier"))
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400827 .arg(displayId));
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400828 } else {
829 ui->imIdLabel->hide();
830 }
831
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400832 bool shouldShowSendContactRequestBtn = !isContact && isRINGAccount;
Andreas Traczyk912242e2018-10-29 14:44:44 -0400833 ui->sendContactRequestButton->setVisible(shouldShowSendContactRequestBtn);
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400834
Andreas Traczyk43c08232018-10-31 13:42:09 -0400835 auto convModel = LRCInstance::getCurrentConversationModel();
836 auto currentConversation = Utils::getConversationFromUid(selectedConvUid(),
837 *convModel);
838 ui->messageView->clear();
839 ui->messageView->printHistory(*convModel, currentConversation->interactions);
840
Andreas Traczyk43c08232018-10-31 13:42:09 -0400841 // Contact Avatars
842 auto accInfo = &LRCInstance::getCurrentAccountInfo();
843 auto contactUri = currentConversation->participants.front();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400844 try {
Andreas Traczyk43c08232018-10-31 13:42:09 -0400845 auto& contact = accInfo->contactModel->getContact(contactUri);
Sébastien Blin942d1022018-12-13 09:49:03 -0500846 auto bestName = Utils::bestNameForConversation(*currentConversation, *convModel);
847 ui->messageView->setInvitation(
848 (contact.profileInfo.type == lrc::api::profile::Type::PENDING),
849 bestName,
850 accInfo->contactModel->getContactProfileId(contact.profileInfo.uri)
851 );
Andreas Traczyk43c08232018-10-31 13:42:09 -0400852 if (!contact.profileInfo.avatar.empty()) {
853 ui->messageView->setSenderImage(
854 accInfo->contactModel->getContactProfileId(contactUri),
855 contact.profileInfo.avatar);
856 } else {
857 auto avatar = Utils::conversationPhoto(selectedConvUid(), *accInfo);
858 QByteArray ba;
859 QBuffer bu(&ba);
860 avatar.save(&bu, "PNG");
861 std::string avatarString = ba.toBase64().toStdString();
862 ui->messageView->setSenderImage(
863 accInfo->contactModel->getContactProfileId(contactUri),
864 avatarString);
865 }
866 } catch (...) { }
Edric Milaretab12d022015-12-04 16:09:44 -0500867}
Edric Milaretfa05d972016-01-13 16:22:04 -0500868
869void
Edric Milaret8001f6f2016-01-27 09:55:12 -0500870CallWidget::on_ringContactLineEdit_textChanged(const QString& text)
Edric Milaretfa05d972016-01-13 16:22:04 -0500871{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400872 Q_UNUSED(text);
873 processContactLineEdit();
Edric Milaretfa05d972016-01-13 16:22:04 -0500874}
Edric Milareta0ebd062016-01-13 12:18:23 -0500875
Nicolas Jagerca850292016-01-17 14:11:10 -0500876void
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400877CallWidget::backToWelcomePage()
Edric Milareta0ebd062016-01-13 12:18:23 -0500878{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400879 deselectConversation();
Andreas Traczyk43c08232018-10-31 13:42:09 -0400880 ui->messageView->hideMessages();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400881 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Nicolas Jagerca850292016-01-17 14:11:10 -0500882}
883
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400884void
885CallWidget::hideMiniSpinner()
Olivier SOLDANO19193412017-06-06 12:03:36 -0400886{
887 if(ui->spinnerLabel->isVisible()){
888 miniSpinner_->stop();
889 ui->spinnerLabel->hide();
890 }
891}
892
Nicolas Jagerca850292016-01-17 14:11:10 -0500893void
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400894CallWidget::on_imBackButton_clicked()
895{
896 backToWelcomePage();
897}
898
899void
Edric Milaret1e598592016-09-02 10:10:01 -0400900CallWidget::on_qrButton_toggled(bool checked)
901{
902 ui->qrLabel->setVisible(checked);
903}
904
905void
Edric Milaret4097d2f2016-02-09 14:41:50 -0500906CallWidget::on_shareButton_clicked()
907{
Sébastien Blincba5b522018-12-10 12:48:36 -0500908 Utils::InvokeMailto(tr("Contact me on Jami"), tr("My Id is : ") + ui->ringIdLabel->text());
Edric Milaret4097d2f2016-02-09 14:41:50 -0500909}
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400910
911void
Andreas Traczyk912242e2018-10-29 14:44:44 -0400912CallWidget::on_sendContactRequestButton_clicked()
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400913{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400914 LRCInstance::getCurrentConversationModel()->makePermanent(selectedConvUid());
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400915}
916
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400917void
Anthony Léonardd47179c2017-03-28 10:39:10 -0400918CallWidget::on_pendingCRBackButton_clicked()
919{
Olivier SOLDANO8179e992017-07-19 15:59:19 -0400920 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Anthony Léonardd47179c2017-03-28 10:39:10 -0400921}
Anthony Léonard5cc76412017-04-21 16:52:25 -0400922
Andreas Traczyk912242e2018-10-29 14:44:44 -0400923void
924CallWidget::on_btnAudioCall_clicked()
925{
926 auto convUid = LRCInstance::getSelectedConvUid();
927 LRCInstance::getCurrentConversationModel()->placeAudioOnlyCall(convUid);
928 ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid)));
929}
930
931void
932CallWidget::on_btnVideoCall_clicked()
933{
934 auto convUid = LRCInstance::getSelectedConvUid();
935 LRCInstance::getCurrentConversationModel()->placeCall(convUid);
936 ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid)));
937}
938
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400939bool
940CallWidget::connectConversationModel()
Anthony Léonard5cc76412017-04-21 16:52:25 -0400941{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400942 auto currentConversationModel = LRCInstance::getCurrentAccountInfo().conversationModel.get();
943
944 if (ui->smartList->selectionModel()) {
945 ui->smartList->selectionModel()->setCurrentIndex(QModelIndex(), QItemSelectionModel::Deselect);
Anthony Léonard5cc76412017-04-21 16:52:25 -0400946 }
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400947
948 QObject::disconnect(modelSortedConnection_);
949 QObject::disconnect(modelUpdatedConnection_);
950 QObject::disconnect(filterChangedConnection_);
951 QObject::disconnect(newConversationConnection_);
952 QObject::disconnect(conversationRemovedConnection_);
953 QObject::disconnect(conversationClearedConnection);
954 QObject::disconnect(interactionStatusUpdatedConnection_);
955 QObject::disconnect(newInteractionConnection_);
Andreas Traczyk43c08232018-10-31 13:42:09 -0400956 QObject::disconnect(interactionRemovedConnection_);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400957
958 modelSortedConnection_ = QObject::connect(
959 currentConversationModel, &lrc::api::ConversationModel::modelSorted,
960 [this]() {
961 updateConversationsFilterWidget();
962 selectSmartlistItem(selectedConvUid());
963 ui->smartList->update();
Isa Nanic37ccc1c2018-10-26 14:16:28 -0400964 }
965 );
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400966 modelUpdatedConnection_ = QObject::connect(
967 currentConversationModel, &lrc::api::ConversationModel::conversationUpdated,
968 [this](const std::string& convUid) {
969 Q_UNUSED(convUid);
970 ui->smartList->update();
Isa Nanic37ccc1c2018-10-26 14:16:28 -0400971 }
972 );
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400973 filterChangedConnection_ = QObject::connect(
974 currentConversationModel, &lrc::api::ConversationModel::filterChanged,
975 [this]() {
976 updateSmartList();
977 updateConversationsFilterWidget();
978 ui->smartList->update();
Isa Nanic37ccc1c2018-10-26 14:16:28 -0400979 }
980 );
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400981 newConversationConnection_ = QObject::connect(
982 currentConversationModel, &lrc::api::ConversationModel::newConversation,
983 [this](const std::string& convUid) {
984 updateSmartList();
985 updateConversationForNewContact(convUid);
986 ui->conversationsFilterWidget->update();
Isa Nanic37ccc1c2018-10-26 14:16:28 -0400987 }
988 );
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400989 conversationRemovedConnection_ = QObject::connect(
990 currentConversationModel, &lrc::api::ConversationModel::conversationRemoved,
991 [this]() {
992 backToWelcomePage();
Isa Nanic37ccc1c2018-10-26 14:16:28 -0400993 }
994 );
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400995 conversationClearedConnection = QObject::connect(
996 currentConversationModel, &lrc::api::ConversationModel::conversationCleared,
997 [this](const std::string& convUid) {
Andreas Traczyk43c08232018-10-31 13:42:09 -0400998 ui->messageView->clear();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -0400999 // if currently selected,
1000 // switch to welcome screen (deselecting current smartlist item )
1001 if (convUid != selectedConvUid()) {
1002 return;
1003 }
1004 backToWelcomePage();
Isa Nanic37ccc1c2018-10-26 14:16:28 -04001005 }
1006 );
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001007 interactionStatusUpdatedConnection_ = QObject::connect(
1008 currentConversationModel, &lrc::api::ConversationModel::interactionStatusUpdated,
Andreas Traczyk43c08232018-10-31 13:42:09 -04001009 [this](const std::string& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction) {
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001010 if (convUid != selectedConvUid()) {
1011 return;
1012 }
Andreas Traczyk43c08232018-10-31 13:42:09 -04001013 auto& currentAccountInfo = LRCInstance::getCurrentAccountInfo();
1014 auto currentConversationModel = currentAccountInfo.conversationModel.get();
1015 currentConversationModel->clearUnreadInteractions(convUid);
1016 ui->conversationsFilterWidget->update();
1017 ui->messageView->updateInteraction(*currentConversationModel, interactionId, interaction);
Isa Nanic37ccc1c2018-10-26 14:16:28 -04001018 }
1019 );
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001020 newInteractionConnection_ = QObject::connect(
1021 currentConversationModel, &lrc::api::ConversationModel::newInteraction,
1022 [this](const std::string& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction) {
1023 onIncomingMessage(convUid, interactionId, interaction);
Isa Nanic37ccc1c2018-10-26 14:16:28 -04001024 }
1025 );
Andreas Traczyk43c08232018-10-31 13:42:09 -04001026 interactionRemovedConnection_ = QObject::connect(
1027 currentConversationModel, &lrc::api::ConversationModel::interactionRemoved,
1028 [this](const std::string& convUid, uint64_t interactionId) {
1029 Q_UNUSED(convUid);
1030 ui->messageView->removeInteraction(interactionId);
1031 }
1032 );
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001033 currentConversationModel->setFilter("");
1034 // clear search field
1035 ui->ringContactLineEdit->setText("");
1036 return true;
1037}
1038
1039void
1040CallWidget::updateConversationView(const std::string& convUid)
1041{
1042 if (convUid != selectedConvUid()) {
1043 return;
1044 }
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001045}
1046
1047void
1048CallWidget::selectConversation(const QModelIndex& index)
1049{
1050 auto currentConversationModel = LRCInstance::getCurrentConversationModel();
1051
1052 if (currentConversationModel == nullptr || !index.isValid()) {
1053 return;
1054 }
1055
1056 const auto item = currentConversationModel->filteredConversation(index.row());
1057
1058 if (selectConversation(item, *currentConversationModel)) {
Andreas Traczyk43c08232018-10-31 13:42:09 -04001059 showIMOutOfCall(index);
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001060 auto convUid = selectedConvUid();
1061 if (!lastConvUid_.compare(convUid)) {
1062 return;
1063 }
1064 lastConvUid_.assign(convUid);
1065 auto currentConversationModel = LRCInstance::getCurrentConversationModel();
1066 auto callModel = LRCInstance::getCurrentCallModel();
1067 auto conversation = Utils::getConversationFromUid(convUid, *currentConversationModel);
1068 const auto item = currentConversationModel->filteredConversation(index.row());
Andreas Traczyk43c08232018-10-31 13:42:09 -04001069 if (callModel->hasCall(conversation->callId) && item.callId == conversation->callId) {
1070 ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget);
1071 ui->callStackWidget->show();
1072 return;
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001073 }
Andreas Traczyk43c08232018-10-31 13:42:09 -04001074 ui->callStackWidget->hide();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001075 }
Anthony Léonard5cc76412017-04-21 16:52:25 -04001076}
Anthony Léonardecfe7422017-05-04 14:14:37 -04001077
Anthony Léonard041ad392017-07-14 16:44:09 -04001078bool
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001079CallWidget::selectConversation( const lrc::api::conversation::Info& item,
1080 lrc::api::ConversationModel& convModel)
Anthony Léonard041ad392017-07-14 16:44:09 -04001081{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001082 if (selectedConvUid() == item.uid) {
1083 return false;
1084 } else if (item.participants.size() > 0) {
1085 convModel.selectConversation(item.uid);
1086 LRCInstance::setSelectedConvId(item.uid);
1087 convModel.clearUnreadInteractions(item.uid);
1088 ui->conversationsFilterWidget->update();
1089 return true;
Anthony Léonard041ad392017-07-14 16:44:09 -04001090 }
Anthony Léonard041ad392017-07-14 16:44:09 -04001091}
1092
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001093void
1094CallWidget::deselectConversation()
Anthony Léonardecfe7422017-05-04 14:14:37 -04001095{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001096 auto currentConversationModel = LRCInstance::getCurrentConversationModel();
1097
1098 if (currentConversationModel == nullptr) {
1099 return;
1100 }
1101
1102 currentConversationModel->selectConversation("");
1103 LRCInstance::setSelectedConvId("");
1104
1105 ui->smartList->selectionModel()->clear();
1106 disconnect(imConnection_);
Anthony Léonardecfe7422017-05-04 14:14:37 -04001107}
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001108
1109void
1110CallWidget::updateConversationForNewContact(const std::string& convUid)
1111{
1112 auto convModel = LRCInstance::getCurrentConversationModel();
1113 if (convModel == nullptr) {
1114 return;
1115 }
1116 ui->ringContactLineEdit->setText("");
1117 auto selectedUid = selectedConvUid();
1118 auto it = Utils::getConversationFromUid(convUid, *convModel);
1119 if (it != convModel->allFilteredConversations().end()) {
1120 try {
1121 auto contact = convModel->owner.contactModel->getContact(it->participants[0]);
1122 if (!contact.profileInfo.uri.empty() && contact.profileInfo.uri.compare(selectedUid) == 0) {
1123 LRCInstance::setSelectedConvId(convUid);
1124 convModel->selectConversation(convUid);
1125 }
1126 } catch (...) {
1127 return;
1128 }
1129 }
1130}
1131
1132void
1133CallWidget::updateSmartList()
1134{
1135 auto& currentAccountInfo = LRCInstance::getCurrentAccountInfo();
Andreas Traczykfc33a492018-12-14 13:53:13 -05001136 smartListModel_.reset(new SmartListModel(currentAccountInfo, this));
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001137 ui->smartList->setModel(smartListModel_.get());
1138 ui->smartList->setItemDelegate(new ConversationItemDelegate());
1139
1140 // smartlist selection
1141 QObject::disconnect(smartlistSelectionConnection_);
1142 smartlistSelectionConnection_ = connect(ui->smartList->selectionModel(),
1143 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
1144 this,
1145 SLOT(smartListSelectionChanged(QItemSelection, QItemSelection)));
1146}
1147
1148void
Isa Nanic6e4a39a2018-12-04 14:26:02 -05001149CallWidget::updateComboBox()
1150{
1151 ui->currentAccountComboBox->updateComboBoxDisplay();
1152}
1153
1154void
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001155CallWidget::update()
1156{
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001157 updateSmartList();
1158 updateConversationsFilterWidget();
Isa Nanic6e4a39a2018-12-04 14:26:02 -05001159 updateComboBox();
Andreas Traczykb8b13ba2018-08-21 16:30:16 -04001160 connectConversationModel();
Isa Nanic601de1d2018-10-23 11:37:26 -04001161}