blob: 55411f31f0878ed16148f53b71ad894ba6cfb728 [file] [log] [blame]
Edric Milaret627500d2015-03-27 16:41:40 -04001/***************************************************************************
Anthony Léonard2fde81d2017-04-17 10:06:55 -04002 * Copyright (C) 2015-2017 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> *
Edric Milaret627500d2015-03-27 16:41:40 -04006 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 **************************************************************************/
20
21#include "callwidget.h"
22#include "ui_callwidget.h"
23
Edric Milaret43f3c1e2015-07-16 17:52:47 -040024#include <QClipboard>
Edric Milaret70ae8782016-04-18 16:10:44 -040025#include <QDesktopServices>
Edric Milaret43f3c1e2015-07-16 17:52:47 -040026
Edric Milaret53f57b62015-05-11 11:02:17 -040027#include <memory>
Edric Milaret627500d2015-03-27 16:41:40 -040028
Edric Milarete19c4cd2016-02-12 10:19:44 -050029#include "qrencode.h"
30
Edric Milaret43f3c1e2015-07-16 17:52:47 -040031//ERROR is defined in windows.h
32#include "utils.h"
33#undef ERROR
Edric Milareta0ebd062016-01-13 12:18:23 -050034#undef interface
Edric Milaret43f3c1e2015-07-16 17:52:47 -040035
Olivier SOLDANO69361192017-04-20 10:32:05 -040036//LRC
Edric Milaret627500d2015-03-27 16:41:40 -040037#include "audio/settings.h"
Olivier SOLDANO9657fd12017-03-27 16:06:53 -040038#include "accountmodel.h"
Edric Milaret627500d2015-03-27 16:41:40 -040039#include "personmodel.h"
Edric Milaret43f3c1e2015-07-16 17:52:47 -040040#include "person.h"
Edric Milaret627500d2015-03-27 16:41:40 -040041#include "fallbackpersoncollection.h"
Edric Milaret67007d12015-05-07 09:40:09 -040042#include "categorizedcontactmodel.h"
Edric Milaret6a642e22015-05-27 15:06:30 -040043#include "localhistorycollection.h"
Edric Milaret1b197eb2015-06-01 15:09:56 -040044#include "media/text.h"
45#include "media/recording.h"
Edric Milaret00a32252016-01-19 10:37:13 -050046#include "media/recordingmodel.h"
Edric Milareted0b2802015-10-01 15:10:02 -040047#include "recentmodel.h"
Edric Milaretab12d022015-12-04 16:09:44 -050048#include "contactmethod.h"
Edric Milareta0ebd062016-01-13 12:18:23 -050049#include "globalinstances.h"
Olivier SOLDANO63178ee2016-11-04 16:50:08 -040050#include <availableaccountmodel.h>
Anthony Léonardd47179c2017-03-28 10:39:10 -040051#include "pendingcontactrequestmodel.h"
Olivier SOLDANO69361192017-04-20 10:32:05 -040052#include "profilemodel.h"
53#include "profile.h"
54#include "peerprofilecollection.h"
55#include "localprofilecollection.h"
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -040056#include "callmodel.h"
Anthony Léonardd47179c2017-03-28 10:39:10 -040057
Olivier SOLDANO69361192017-04-20 10:32:05 -040058//Client
Edric Milaret559bda52015-04-29 17:02:31 -040059#include "wizarddialog.h"
Edric Milaret83b248c2015-06-02 11:42:23 -040060#include "windowscontactbackend.h"
Edric Milaret43f3c1e2015-07-16 17:52:47 -040061#include "contactpicker.h"
Edric Milaret2afd2bf2015-07-21 17:12:25 -040062#include "contactmethodpicker.h"
Edric Milaret2cf34292015-06-22 16:27:03 -040063#include "globalsystemtray.h"
Edric Milareted0b2802015-10-01 15:10:02 -040064#include "smartlistdelegate.h"
Edric Milaretab12d022015-12-04 16:09:44 -050065#include "imdelegate.h"
Edric Milareta0ebd062016-01-13 12:18:23 -050066#include "pixbufmanipulator.h"
Edric Milaret70ae8782016-04-18 16:10:44 -040067#include "settingskey.h"
Anthony Léonardf95f7f62017-04-04 11:01:51 -040068#include "contactrequestitemdelegate.h"
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -040069#include "deletecontactdialog.h"
Edric Milaret627500d2015-03-27 16:41:40 -040070
Edric Milaret25236d92016-03-28 09:40:58 -040071
Nicolas Jager97a21b42015-12-03 16:55:45 -050072CallWidget::CallWidget(QWidget* parent) :
Nicolas Jager74fe46f2016-02-29 14:55:09 -050073 NavWidget(parent),
Edric Milaret7d40a4a2015-05-13 13:01:15 -040074 ui(new Ui::CallWidget),
Edric Milaretab12d022015-12-04 16:09:44 -050075 menu_(new QMenu()),
76 imDelegate_(new ImDelegate())
Edric Milaret627500d2015-03-27 16:41:40 -040077{
78 ui->setupUi(this);
79
Edric Milaret6b68a482016-02-01 15:23:44 -050080 pageAnim_ = new QPropertyAnimation(ui->welcomePage, "pos", this);
Nicolas Jagerca850292016-01-17 14:11:10 -050081
Edric Milaret6456baa2015-05-21 12:18:07 -040082 setActualCall(nullptr);
Edric Milaret627500d2015-03-27 16:41:40 -040083 videoRenderer_ = nullptr;
84
Nicolas Jager74fe46f2016-02-29 14:55:09 -050085 connect(ui->settingsButton, &QPushButton::clicked, this, &CallWidget::settingsButtonClicked);
86
Edric Milaret3aca8e32015-06-12 10:01:40 -040087 connect(ui->videoWidget, SIGNAL(setChatVisibility(bool)),
88 ui->instantMessagingWidget, SLOT(setVisible(bool)));
89
Edric Milareted0b2802015-10-01 15:10:02 -040090 QPixmap logo(":/images/logo-ring-standard-coul.png");
91 ui->ringLogo->setPixmap(logo.scaledToHeight(100, Qt::SmoothTransformation));
92 ui->ringLogo->setAlignment(Qt::AlignHCenter);
93
Edric Milaret1e598592016-09-02 10:10:01 -040094 ui->qrLabel->hide();
Edric Milarete19c4cd2016-02-12 10:19:44 -050095
Edric Milaret627500d2015-03-27 16:41:40 -040096 try {
Edric Milareta3e47282015-10-23 15:20:30 -040097 callModel_ = &CallModel::instance();
Edric Milaret627500d2015-03-27 16:41:40 -040098
99 connect(callModel_, SIGNAL(incomingCall(Call*)),
100 this, SLOT(callIncoming(Call*)));
Edric Milaret627500d2015-03-27 16:41:40 -0400101 connect(callModel_, SIGNAL(callStateChanged(Call*, Call::State)),
102 this, SLOT(callStateChanged(Call*, Call::State)));
103
Edric Milaretfa05d972016-01-13 16:22:04 -0500104 RecentModel::instance().peopleProxy()->setFilterRole(static_cast<int>(Ring::Role::Name));
105 RecentModel::instance().peopleProxy()->setFilterCaseSensitivity(Qt::CaseInsensitive);
Edric Milareta3e47282015-10-23 15:20:30 -0400106 ui->smartList->setModel(RecentModel::instance().peopleProxy());
Edric Milaret6816fd72016-01-29 16:36:24 -0500107
Edric Milaret25236d92016-03-28 09:40:58 -0400108 PersonModel::instance().addCollection<PeerProfileCollection>(LoadOptions::FORCE_ENABLED);
109 ProfileModel::instance().addCollection<LocalProfileCollection>(LoadOptions::FORCE_ENABLED);
110
Edric Milareta3e47282015-10-23 15:20:30 -0400111 PersonModel::instance().
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400112 addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
113
Edric Milaret6b68a482016-02-01 15:23:44 -0500114 connect(ui->smartList, &QTreeView::entered, this, &CallWidget::on_entered);
115
116 smartListDelegate_ = new SmartListDelegate();
117 ui->smartList->setSmartListItemDelegate(smartListDelegate_);
118
Olivier SOLDANO69361192017-04-20 10:32:05 -0400119 ui->contactRequestList->setItemDelegate(new ContactRequestItemDelegate());
120
Edric Milaret627500d2015-03-27 16:41:40 -0400121 findRingAccount();
Edric Milareta0ebd062016-01-13 12:18:23 -0500122 setupOutOfCallIM();
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400123 ui->smartList->setContextMenuPolicy(Qt::CustomContextMenu);
Edric Milaret627500d2015-03-27 16:41:40 -0400124
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500125 connect(ui->smartList, &SmartList::btnVideoClicked, this, &CallWidget::btnComBarVideoClicked);
Nicolas Jager41e4fcf2016-01-28 11:37:03 -0500126
Edric Milaret6b68a482016-02-01 15:23:44 -0500127 connect(RecentModel::instance().selectionModel(),
Olivier SOLDANO61065ec2016-11-11 16:31:34 -0500128 SIGNAL(currentChanged(QModelIndex,QModelIndex)),
129 this,
130 SLOT(smartListCurrentChanged(QModelIndex,QModelIndex)));
131
Olivier SOLDANO70279d32017-07-18 15:21:34 -0400132 //set most recent call to view
Olivier SOLDANOaf8f2822017-07-11 12:15:18 -0400133 connect(&RecentModel::instance(), &QAbstractItemModel::dataChanged, [=](const QModelIndex &topLeft, const QModelIndex &bottomRight,const QVector<int> &vec){
134 Q_UNUSED(bottomRight)
135 Q_UNUSED(vec)
Olivier SOLDANOaf8f2822017-07-11 12:15:18 -0400136
Olivier SOLDANO70279d32017-07-18 15:21:34 -0400137 if (topLeft.isValid() && RecentModel::instance().hasActiveCall(topLeft)){
138 ui->smartList->selectionModel()->setCurrentIndex(topLeft,QItemSelectionModel::ClearAndSelect);
Olivier SOLDANOaf8f2822017-07-11 12:15:18 -0400139 }
140 });
141
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500142 connect(RecentModel::instance().selectionModel(), &QItemSelectionModel::selectionChanged, [=](const QItemSelection &selected, const QItemSelection &deselected) {
143 // lambda used to focus on the correct smartList element when switching automatically between two calls
144 Q_UNUSED(deselected)
145 if (selected.size()) {
146 auto idx = selected.indexes().first();
147 auto realIdx = RecentModel::instance().peopleProxy()->mapFromSource(idx);
148 ui->smartList->selectionModel()->setCurrentIndex(realIdx, QItemSelectionModel::ClearAndSelect);
Anthony Léonardecfe7422017-05-04 14:14:37 -0400149 } else {
150 RecentModel::instance().selectionModel()->clearCurrentIndex();
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500151 ui->smartList->clearSelection();
Anthony Léonardecfe7422017-05-04 14:14:37 -0400152 ui->smartList->selectionModel()->clearCurrentIndex();
153 }
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500154 });
155
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400156 connect(&NameDirectory::instance(), SIGNAL(registeredNameFound(Account*,NameDirectory::LookupStatus,const QString&,const QString&)),
157 this, SLOT(contactLineEdit_registeredNameFound(Account*,NameDirectory::LookupStatus,const QString&,const QString&)));
158
159 connect(&AccountModel::instance(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
160 ui->currentAccountWidget, SLOT(update()));
161
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400162 connect(ui->searchBtn, SIGNAL(clicked(bool)), this, SLOT(searchBtnClicked()));
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400163
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400164 connect(ui->sendContactRequestWidget, &SendContactRequestWidget::sendCRclicked, [=]{slidePage(ui->messagingPage);});
165
Anthony Léonardd47179c2017-03-28 10:39:10 -0400166 connect(ui->contactRequestWidget, &ContactRequestWidget::choiceMade, [this]() {
Anthony Léonardecfe7422017-05-04 14:14:37 -0400167 if (getSelectedAccount()->pendingContactRequestModel()->rowCount() == 0)
168 ui->mainTabMenu->setCurrentWidget(ui->mainTabMenuPage1);
169 else
170 ui->contactRequestList->selectionModel()->clear();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400171 });
172
Anthony Léonard2d99df02017-04-19 16:35:19 -0400173 connect(AvailableAccountModel::instance().selectionModel(), &QItemSelectionModel::currentChanged,
Anthony Léonardd47179c2017-03-28 10:39:10 -0400174 this, &CallWidget::selectedAccountChanged);
175
176 // It needs to be called manually once to initialize the ui with the account selected at start.
177 // The second argument (previous) is set to an invalid QModelIndex as it is the first selection.
Anthony Léonard2d99df02017-04-19 16:35:19 -0400178 selectedAccountChanged(AvailableAccountModel::instance().selectionModel()->currentIndex(), QModelIndex());
179
180 // This connect() is used to initialise and track changes of profile's picture
181 connect(&ProfileModel::instance(), &ProfileModel::dataChanged,
182 ui->currentAccountWidget, &CurrentAccountWidget::setPhoto);
Anthony Léonardd47179c2017-03-28 10:39:10 -0400183
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400184 connect(ui->videoWidget, &VideoView::videoSettingsClicked, this, &CallWidget::settingsButtonClicked);
Olivier SOLDANO5cb1a422017-07-26 11:16:50 -0400185
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400186 connect(ui->smartList, &QListView::customContextMenuRequested, [=](const QPoint& pos){ setupSmartListMenu(pos);});
187
Olivier SOLDANO19193412017-06-06 12:03:36 -0400188 // setup searchingfor mini spinner
189 miniSpinner_ = new QMovie(":/images/waiting.gif");
190 ui->spinnerLabel->setMovie(miniSpinner_);
191 ui->spinnerLabel->hide();
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400192
Edric Milaret80e0b212015-10-16 10:07:43 -0400193 } catch (const std::exception& e) {
194 qDebug() << "INIT ERROR" << e.what();
Edric Milaret627500d2015-03-27 16:41:40 -0400195 }
196}
197
198CallWidget::~CallWidget()
199{
200 delete ui;
Edric Milaretc7ab5502015-06-15 11:18:02 -0400201 delete menu_;
Edric Milaretab12d022015-12-04 16:09:44 -0500202 delete imDelegate_;
Edric Milaret6b68a482016-02-01 15:23:44 -0500203 delete pageAnim_;
204 delete smartListDelegate_;
Edric Milarete19c4cd2016-02-12 10:19:44 -0500205 delete shareMenu_;
206}
207
208void
Edric Milareta0ebd062016-01-13 12:18:23 -0500209CallWidget::setupOutOfCallIM()
210{
211 ui->listMessageView->setItemDelegate(imDelegate_);
212 ui->listMessageView->setContextMenuPolicy(Qt::ActionsContextMenu);
213
214 auto copyAction = new QAction(tr("Copy"), this);
215 ui->listMessageView->addAction(copyAction);
216 connect(copyAction, &QAction::triggered, [=]() {
217 auto idx = ui->listMessageView->currentIndex();
218 if (idx.isValid()) {
219 auto text = ui->listMessageView->model()->data(idx);
220 QApplication::clipboard()->setText(text.value<QString>());
221 }
222 });
Edric Milaret70ae8782016-04-18 16:10:44 -0400223 QSettings settings;
Edric Milareta0ebd062016-01-13 12:18:23 -0500224 auto displayDate = new QAction(tr("Display date"), this);
225 displayDate->setCheckable(true);
Edric Milaret70ae8782016-04-18 16:10:44 -0400226 displayDate->setChecked(settings.value(SettingsKey::imShowDate).toBool());
Edric Milareta0ebd062016-01-13 12:18:23 -0500227 ui->listMessageView->addAction(displayDate);
228 auto displayAuthor = new QAction(tr("Display author"), this);
229 displayAuthor->setCheckable(true);
Edric Milaret70ae8782016-04-18 16:10:44 -0400230 displayAuthor->setChecked(settings.value(SettingsKey::imShowAuthor).toBool());
Edric Milareta0ebd062016-01-13 12:18:23 -0500231 ui->listMessageView->addAction(displayAuthor);
232 auto lamdba = [=](){
Edric Milaret70ae8782016-04-18 16:10:44 -0400233 QSettings settings;
234 settings.setValue(SettingsKey::imShowAuthor, displayAuthor->isChecked());
235 settings.setValue(SettingsKey::imShowDate, displayDate->isChecked());
236 emit imDelegate_->sizeHintChanged(QModelIndex());
Edric Milareta0ebd062016-01-13 12:18:23 -0500237 };
238 connect(displayAuthor, &QAction::triggered, lamdba);
239 connect(displayDate, &QAction::triggered, lamdba);
Edric Milaret00a32252016-01-19 10:37:13 -0500240
241 connect(&::Media::RecordingModel::instance(),
242 SIGNAL(newTextMessage(::Media::TextRecording*, ContactMethod*)),
243 this,
244 SLOT(onIncomingMessage(::Media::TextRecording*, ContactMethod*)));
245}
246
247void
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400248CallWidget::onIncomingMessage(::Media::TextRecording* t, ContactMethod* cm)
249{
Edric Milaret00a32252016-01-19 10:37:13 -0500250 Q_UNUSED(cm)
251
252 if (!QApplication::focusWidget()) {
253 auto idx = t->instantTextMessagingModel()->
254 index(t->instantTextMessagingModel()->rowCount()-1, 0);
255 GlobalSystemTray::instance()
256 .showMessage("Ring",
257 QString(tr("Message incoming from %1")).arg(
258 idx.data((int)Media::TextRecording::Role::AuthorDisplayname).toString()));
259 QApplication::alert(this, 5000);
260 }
Edric Milareta0ebd062016-01-13 12:18:23 -0500261}
262
263void
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400264CallWidget::triggerDeleteContactDialog(ContactMethod *cm, Account *ac)
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400265{
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400266 auto dlg = new DeleteContactDialog(cm, ac);
267 dlg->exec();
268}
Edric Milareta0ebd062016-01-13 12:18:23 -0500269
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400270void
271CallWidget::setupSmartListMenu(const QPoint& pos)
272{
273 auto idx = ui->smartList->currentIndex();
Edric Milaret9949b342016-02-02 12:25:08 -0500274
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400275 if (not idx.isValid())
276 return;
277
278 QPoint globalPos = ui->smartList->mapToGlobal(pos);
279 QMenu menu;
280 QVector<ContactMethod*> contactMethods = RecentModel::instance()
281 .getContactMethods(RecentModel::instance().peopleProxy()->mapToSource(idx));
282
283 if (contactMethods.isEmpty())
284 return;
285
286 auto contactMethod = contactMethods.first();
287
288 if (contactMethods.size() == 1){
289 auto copyAction = new QAction(tr("Copy number"), this);
290 menu.addAction(copyAction);
291 connect(copyAction, &QAction::triggered, [contactMethod]() {
292 QApplication::clipboard()->setText(contactMethod->uri());
293 });
294
295 auto copyNameAction = new QAction(tr("Copy name"), this);
296 menu.addAction(copyNameAction);
297 connect(copyNameAction, &QAction::triggered, [contactMethod]() {
298 QApplication::clipboard()->setText(contactMethod->primaryName());
299 });
300 } else {
301 auto callMenu = menu.addMenu(tr("Call Number"));
302 auto copyMenu = menu.addMenu(tr("Copy Number"));
303 for (auto cM : contactMethods) {
304 auto uri = cM->bestId();
305 auto copyAction = new QAction(tr("Copy %1").arg(uri), this);
306 copyMenu->addAction(copyAction);
307 connect(copyAction, &QAction::triggered, [uri]() {
308 QApplication::clipboard()->setText(uri);
Edric Milareta0ebd062016-01-13 12:18:23 -0500309 });
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400310 auto callAction = new QAction(tr("Call %1").arg(uri), this);
311 callMenu->addAction(callAction);
312 connect(callAction, &QAction::triggered, [cM]() {
313 Call* c = CallModel::instance().dialingCall(cM);
314 c->performAction(Call::Action::ACCEPT);
Edric Milaretac21b3d2016-09-01 12:45:49 -0400315 });
Edric Milaret9949b342016-02-02 12:25:08 -0500316 }
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400317 }
318
319 auto ac = getSelectedAccount();
320 if (ac && !ac->hasContact(contactMethod)) {
321 auto addExisting = new QAction(tr("Add to contacts"), this);
322 menu.addAction(addExisting);
323 connect(addExisting, &QAction::triggered, [this, contactMethod, ac]() {
324 /* uncomment and capture globalPos in lambda to reactivate popup
325 ContactPicker contactPicker(contactMethod);
326 contactPicker.move(globalPos.x(), globalPos.y() - (contactPicker.height()/2));
327 contactPicker.exec();
328 */
329 ac->addContact(contactMethod);
330 });
331 } else if (ac) {
332 auto removeExisting = new QAction(tr("Remove from contacts"), this);
333 menu.addAction(removeExisting);
334 connect(removeExisting, &QAction::triggered, [this, contactMethod, ac]() {
335 triggerDeleteContactDialog(contactMethod, ac);
336 });
337 }
338
339 menu.exec(globalPos);
Edric Milareta0ebd062016-01-13 12:18:23 -0500340}
341
Anthony Léonarda86a8972016-12-15 10:33:47 -0500342void CallWidget::setupQRCode(QString ringID)
Edric Milarete19c4cd2016-02-12 10:19:44 -0500343{
Anthony Léonarda86a8972016-12-15 10:33:47 -0500344 auto rcode = QRcode_encodeString(ringID.toStdString().c_str(),
Edric Milaret6d0e5312016-04-04 16:30:22 -0400345 0, //Let the version be decided by libqrencode
346 QR_ECLEVEL_L, // Lowest level of error correction
Edric Milarete19c4cd2016-02-12 10:19:44 -0500347 QR_MODE_8, // 8-bit data mode
348 1);
349 if (not rcode) {
350 qWarning() << "Failed to generate QR code: " << strerror(errno);
351 return;
352 }
353
354 auto margin = 5;
355 int qrwidth = rcode->width + margin * 2;
356 QImage result(QSize(qrwidth, qrwidth), QImage::Format_Mono);
357 QPainter painter;
358 painter.begin(&result);
359 painter.setClipRect(QRect(0, 0, qrwidth, qrwidth));
360 painter.setPen(QPen(Qt::black, 0.1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
361 painter.setBrush(Qt::black);
362 painter.fillRect(QRect(0, 0, qrwidth, qrwidth), Qt::white);
Edric Milaret74474f52016-05-16 13:36:23 -0400363 unsigned char* p;
Edric Milarete19c4cd2016-02-12 10:19:44 -0500364 p = rcode->data;
365 for(int y = 0; y < rcode->width; y++) {
Edric Milaret74474f52016-05-16 13:36:23 -0400366 unsigned char* row = (p + (y * rcode->width));
Edric Milarete19c4cd2016-02-12 10:19:44 -0500367 for(int x = 0; x < rcode->width; x++) {
368 if(*(row + x) & 0x1) {
369 painter.drawRect(margin + x, margin + y, 1, 1);
370 }
371 }
372
373 }
374 painter.end();
375 QRcode_free(rcode);
Edric Milaret6d0e5312016-04-04 16:30:22 -0400376 ui->qrLabel->setPixmap(QPixmap::fromImage(result.scaled(QSize(qrSize_, qrSize_), Qt::KeepAspectRatio)));
Edric Milarete19c4cd2016-02-12 10:19:44 -0500377}
378
Edric Milaret67007d12015-05-07 09:40:09 -0400379void
380CallWidget::findRingAccount()
381{
Anthony Léonard266dd302017-03-31 14:38:32 -0400382 bool ringAccountFound = false;
Edric Milaret57467842016-08-30 13:06:11 -0400383
Edric Milareta3e47282015-10-23 15:20:30 -0400384 auto a_count = AccountModel::instance().rowCount();
Edric Milaret627500d2015-03-27 16:41:40 -0400385 for (int i = 0; i < a_count; ++i) {
Edric Milareta3e47282015-10-23 15:20:30 -0400386 auto idx = AccountModel::instance().index(i, 0);
Edric Milaret627500d2015-03-27 16:41:40 -0400387 auto protocol = idx.data(static_cast<int>(Account::Role::Proto));
Edric Milaret74474f52016-05-16 13:36:23 -0400388 if (static_cast<Account::Protocol>(protocol.toUInt()) == Account::Protocol::RING) {
Anthony Léonard266dd302017-03-31 14:38:32 -0400389 ringAccountFound = true;
Edric Milareta3e47282015-10-23 15:20:30 -0400390 auto account = AccountModel::instance().getAccountByModelIndex(idx);
Edric Milaret68779c42015-07-09 16:53:03 -0400391 if (account->displayName().isEmpty())
392 account->displayName() = account->alias();
Edric Milaret57467842016-08-30 13:06:11 -0400393 if (account->needsMigration()) {
394 WizardDialog dlg(WizardDialog::MIGRATION, account);
395 dlg.exec();
396 }
Edric Milaret627500d2015-03-27 16:41:40 -0400397 }
398 }
Anthony Léonard266dd302017-03-31 14:38:32 -0400399 if (!ringAccountFound) {
Edric Milaret57467842016-08-30 13:06:11 -0400400 WizardDialog wizardDialog;
401 wizardDialog.exec();
402 }
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400403
404 ui->currentAccountWidget->update();
405
Edric Milaret627500d2015-03-27 16:41:40 -0400406}
407
408void
Edric Milaret00d34f22016-05-09 16:30:29 -0400409CallWidget::callChangedSlot()
410{
411 if (not actualCall_)
412 return;
Olivier SOLDANO2c03dc72017-05-25 11:17:13 -0400413
Edric Milaret41941582016-09-14 12:59:04 -0400414 ui->callerIdLabel->setText(QString("%1")
Edric Milaret00d34f22016-05-09 16:30:29 -0400415 .arg(actualCall_->formattedName()));
416 ui->callerPhoto->setPixmap(
417 QPixmap::fromImage(
418 GlobalInstances::pixmapManipulator()
419 .callPhoto(actualCall_, QSize(130,130)).value<QImage>()));
Olivier SOLDANO2c03dc72017-05-25 11:17:13 -0400420 ui->callerBestIdLabel->setText(actualCall_->peerContactMethod()->bestId());
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400421
Olivier SOLDANO02971ce2016-11-04 15:38:29 -0400422 if(actualCall_->state() == Call::State::OVER || actualCall_->state() == Call::State::FAILURE){
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400423 ui->outboundCallLabel->setText(actualCall_->toHumanStateName(Call::State::INITIALIZATION));
424 } else {
425 ui->outboundCallLabel->setText(actualCall_->toHumanStateName());
426 }
Edric Milaret00d34f22016-05-09 16:30:29 -0400427}
428
429void
Nicolas Jager97a21b42015-12-03 16:55:45 -0500430CallWidget::callIncoming(Call* call)
Edric Milaret627500d2015-03-27 16:41:40 -0400431{
Edric Milaret00a32252016-01-19 10:37:13 -0500432 if (!QApplication::focusWidget()) {
433 GlobalSystemTray::instance()
434 .showMessage("Ring",
435 QString(tr("Call incoming from %1")).arg(call->formattedName()));
Edric Milaret2cf34292015-06-22 16:27:03 -0400436 QApplication::alert(this, 5000);
437 }
438
Edric Milaret6456baa2015-05-21 12:18:07 -0400439 setActualCall(call);
Edric Milaret627500d2015-03-27 16:41:40 -0400440}
441
442void
443CallWidget::on_acceptButton_clicked()
444{
445 if (actualCall_ != nullptr)
Edric Milaret53f57b62015-05-11 11:02:17 -0400446 actualCall_->performAction(Call::Action::ACCEPT);
Edric Milaret627500d2015-03-27 16:41:40 -0400447}
448
449void
450CallWidget::on_refuseButton_clicked()
451{
452 if (actualCall_ == nullptr)
453 return;
454 actualCall_->performAction(Call::Action::REFUSE);
Nicolas Jager13745062016-02-12 18:56:40 -0500455 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Edric Milaret6456baa2015-05-21 12:18:07 -0400456 setActualCall(nullptr);
Edric Milaret627500d2015-03-27 16:41:40 -0400457}
458
459void
Edric Milaret67007d12015-05-07 09:40:09 -0400460CallWidget::callStateChanged(Call* call, Call::State previousState)
461{
Edric Milaret627500d2015-03-27 16:41:40 -0400462 Q_UNUSED(previousState)
Edric Milaret4b1be4a2016-01-15 16:49:20 -0500463 if (call == nullptr
464 || call != actualCall_)
Edric Milaretb5b49072015-05-08 11:56:07 -0400465 return;
Edric Milareted0b2802015-10-01 15:10:02 -0400466
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500467 callStateToView(call);
468
Edric Milaret4b1be4a2016-01-15 16:49:20 -0500469 if (call->state() == Call::State::OVER) {
Edric Milaret6456baa2015-05-21 12:18:07 -0400470 setActualCall(nullptr);
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500471 ui->smartList->clearSelection();
Edric Milaret6b68a482016-02-01 15:23:44 -0500472 RecentModel::instance().selectionModel()->clear();
Edric Milaret627500d2015-03-27 16:41:40 -0400473 }
Edric Milaret627500d2015-03-27 16:41:40 -0400474}
475
476void
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400477CallWidget::atExit()
478{
Edric Milaret627500d2015-03-27 16:41:40 -0400479}
Edric Milaret67007d12015-05-07 09:40:09 -0400480
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400481void
482CallWidget::callStateToView(Call* value)
Edric Milaret6b68a482016-02-01 15:23:44 -0500483{
484 if (value) {
485 switch (value->state()) {
486 case Call::State::INCOMING:
487 if (not value->account()->isAutoAnswer())
488 ui->stackedWidget->setCurrentWidget(ui->callInvitePage);
489 else
490 ui->stackedWidget->setCurrentWidget(ui->videoPage);
491 break;
492 case Call::State::CURRENT:
Edric Milareta86e3f52016-03-14 16:28:57 -0400493 case Call::State::CONFERENCE:
Edric Milaret854c6b44d2016-03-08 11:00:48 -0500494 case Call::State::HOLD:
Edric Milaret6b68a482016-02-01 15:23:44 -0500495 ui->stackedWidget->setCurrentWidget(ui->videoPage);
Olivier SOLDANO19193412017-06-06 12:03:36 -0400496 hideMiniSpinner();
Edric Milaret6b68a482016-02-01 15:23:44 -0500497 break;
Olivier SOLDANO02971ce2016-11-04 15:38:29 -0400498 case Call::State::OVER:
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500499 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Olivier SOLDANO02971ce2016-11-04 15:38:29 -0400500 break;
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400501 case Call::State::FAILURE:
502 case Call::State::ERROR:
Olivier SOLDANO02971ce2016-11-04 15:38:29 -0400503 on_cancelButton_clicked();
Olivier SOLDANO19193412017-06-06 12:03:36 -0400504 hideMiniSpinner();
Edric Milaret6b68a482016-02-01 15:23:44 -0500505 break;
506 case Call::State::INITIALIZATION:
507 case Call::State::CONNECTED:
508 case Call::State::RINGING:
Olivier SOLDANO19193412017-06-06 12:03:36 -0400509 miniSpinner_->start();
510 ui->spinnerLabel->show();
Edric Milaret6b68a482016-02-01 15:23:44 -0500511 ui->stackedWidget->setCurrentWidget(ui->outboundCallPage);
512 break;
513 default:
Edric Milaret854c6b44d2016-03-08 11:00:48 -0500514 qWarning() << "Call state not handled doing nothing : "
515 << value->toHumanStateName();
Edric Milaret6b68a482016-02-01 15:23:44 -0500516 break;
517 }
Nicolas Jager13745062016-02-12 18:56:40 -0500518 }
Edric Milaret6b68a482016-02-01 15:23:44 -0500519}
520
Edric Milaret6456baa2015-05-21 12:18:07 -0400521void
522CallWidget::setActualCall(Call* value)
523{
524 actualCall_ = value;
Edric Milaret80e0b212015-10-16 10:07:43 -0400525 CallModel::instance().selectCall(value);
526 ui->videoWidget->pushRenderer(value);
Edric Milareta86e3f52016-03-14 16:28:57 -0400527 ui->instantMessagingWidget->setMediaText(actualCall_);
Edric Milaret6b68a482016-02-01 15:23:44 -0500528 callStateToView(value);
Edric Milaret00d34f22016-05-09 16:30:29 -0400529 if (actualCall_) {
530 callChangedConnection_ = connect(actualCall_,
531 SIGNAL(changed()),
532 this,
533 SLOT(callChangedSlot()));
534 } else
535 disconnect(callChangedConnection_);
536
Edric Milaret6456baa2015-05-21 12:18:07 -0400537}
Edric Milaretc7ab5502015-06-15 11:18:02 -0400538
539void
Edric Milareted0b2802015-10-01 15:10:02 -0400540CallWidget::on_cancelButton_clicked()
Edric Milaretd8528fa2015-07-07 14:13:51 -0400541{
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400542 if (actualCall_){
Edric Milaretd8528fa2015-07-07 14:13:51 -0400543 actualCall_->performAction(Call::Action::REFUSE);
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400544 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
545 }
Edric Milaretd8528fa2015-07-07 14:13:51 -0400546}
Edric Milareted0b2802015-10-01 15:10:02 -0400547
548void
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400549CallWidget::on_smartList_clicked(const QModelIndex& index)
550{
551 RecentModel::instance().selectionModel()->setCurrentIndex(
552 RecentModel::instance().peopleProxy()->mapToSource(index),
553 QItemSelectionModel::ClearAndSelect);
554}
555
556void
Nicolas Jager97a21b42015-12-03 16:55:45 -0500557CallWidget::on_smartList_doubleClicked(const QModelIndex& index)
Edric Milareted0b2802015-10-01 15:10:02 -0400558{
Olivier SOLDANO70279d32017-07-18 15:21:34 -0400559 if (!index.isValid())
560 return;
561
Edric Milareta3e47282015-10-23 15:20:30 -0400562 auto realIndex = RecentModel::instance().peopleProxy()->mapToSource(index);
563 if (RecentModel::instance().hasActiveCall(realIndex))
Edric Milareted0b2802015-10-01 15:10:02 -0400564 return;
565
566 ContactMethod* m = nullptr;
567 if (auto cm = realIndex.data((int)Call::Role::ContactMethod).value<ContactMethod*>()) {
568 m = cm;
569 } else {
570 if (auto person = realIndex.data((int)Person::Role::Object).value<Person*>()) {
571 m = person->phoneNumbers().first();
572 }
573 }
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500574
Edric Milareta3e47282015-10-23 15:20:30 -0400575 if (m && !RecentModel::instance().index(0, 0, realIndex).isValid()) {
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500576
577 QPixmap map = QPixmap::fromImage(
578 GlobalInstances::pixmapManipulator().callPhoto(m, QSize(130,130)).value<QImage>());
579 ui->callingPhoto->setPixmap(map);
580
Edric Milareta3e47282015-10-23 15:20:30 -0400581 Call* c = CallModel::instance().dialingCall(m);
Edric Milareted0b2802015-10-01 15:10:02 -0400582 c->performAction(Call::Action::ACCEPT);
Edric Milaret6b68a482016-02-01 15:23:44 -0500583 setActualCall(c);
Edric Milareted0b2802015-10-01 15:10:02 -0400584 }
585}
586
587void
Olivier SOLDANO61065ec2016-11-11 16:31:34 -0500588CallWidget::smartListCurrentChanged(const QModelIndex &currentIdx, const QModelIndex &previousIdx)
589{
590 Q_UNUSED(previousIdx);
Anthony Léonardecfe7422017-05-04 14:14:37 -0400591 if (not currentIdx.isValid()) {
592 auto widget = ui->stackedWidget->currentWidget();
593 if (widget == ui->messagingPage || widget == ui->videoPage)
594 slidePage(ui->welcomePage);
595 if(actualCall_)
596 setActualCall(nullptr);
Edric Milareted0b2802015-10-01 15:10:02 -0400597 return;
Anthony Léonardecfe7422017-05-04 14:14:37 -0400598 }
Edric Milareted0b2802015-10-01 15:10:02 -0400599
Olivier SOLDANO703caba2016-11-15 16:18:55 -0500600 //catch call of current index
Olivier SOLDANO61065ec2016-11-11 16:31:34 -0500601 auto currentIdxCall = RecentModel::instance().getActiveCall(currentIdx);
Olivier SOLDANO703caba2016-11-15 16:18:55 -0500602
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400603 if (currentIdxCall) {
604 if (currentIdxCall != actualCall_) //if it is different from actual call, switch between the two
605 setActualCall(currentIdxCall);
606 } else { // if there is no call attached to this smartlist index (contact tab)
Edric Milareta0ebd062016-01-13 12:18:23 -0500607 setActualCall(nullptr);
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400608 showIMOutOfCall(currentIdx); // change page to contact request of messaging page with correct behaviour
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400609 }
610 /*
611 else { // if non defined behaviour disconnect instant messaging and return to welcome page
Edric Milareted0b2802015-10-01 15:10:02 -0400612 setActualCall(nullptr);
Edric Milaret7ef617b2016-02-01 15:40:57 -0500613 if (imConnection_)
614 disconnect(imConnection_);
Edric Milareted0b2802015-10-01 15:10:02 -0400615 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
616 }
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400617 */
Edric Milareted0b2802015-10-01 15:10:02 -0400618}
619
620void
Anthony Léonardd47179c2017-03-28 10:39:10 -0400621CallWidget::contactReqListCurrentChanged(const QModelIndex &currentIdx, const QModelIndex &previousIdx)
622{
623 Q_UNUSED(previousIdx)
624
Anthony Léonardecfe7422017-05-04 14:14:37 -0400625 if (currentIdx.isValid()) {
626 ui->contactRequestWidget->setCurrentContactRequest(currentIdx);
627 ui->stackedWidget->setCurrentWidget(ui->contactRequestPage);
628 } else {
629 ui->contactRequestWidget->setCurrentContactRequest(QModelIndex());
630 if (ui->stackedWidget->currentWidget() == ui->contactRequestPage)
631 slidePage(ui->welcomePage);
632 }
Anthony Léonardd47179c2017-03-28 10:39:10 -0400633}
634
635void
Edric Milareted0b2802015-10-01 15:10:02 -0400636CallWidget::placeCall()
637{
Nicolas Jager97a21b42015-12-03 16:55:45 -0500638 if (ui->ringContactLineEdit->text().isEmpty())
Edric Milareted0b2802015-10-01 15:10:02 -0400639 return;
Nicolas Jager97a21b42015-12-03 16:55:45 -0500640 Call* c = CallModel::instance().dialingCall(PhoneDirectoryModel::instance().getNumber(ui->ringContactLineEdit->text()));
Edric Milareted0b2802015-10-01 15:10:02 -0400641 c->performAction(Call::Action::ACCEPT);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500642 ui->ringContactLineEdit->clear();
Edric1bed3f92016-05-19 10:24:48 -0400643 ui->callingPhoto->setPixmap(
644 QPixmap::fromImage(
645 GlobalInstances::pixmapManipulator()
646 .callPhoto(c, QSize(130,130)).value<QImage>()));
Edric Milareted0b2802015-10-01 15:10:02 -0400647}
648
649void
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500650CallWidget::settingsButtonClicked()
Edric Milareted0b2802015-10-01 15:10:02 -0400651{
652 emit NavigationRequested(ScreenEnum::ConfScreen);
653}
654
655void
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400656CallWidget::searchContactLineEditEntry(const URI &uri)
657{
Olivier SOLDANO73573642017-06-16 11:22:12 -0400658 auto cm = PhoneDirectoryModel::instance().getNumber(uri, getSelectedAccount());
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400659 // if its a new CM, bring it to the top
660 if (cm->lastUsed() == 0)
661 cm->setLastUsed(QDateTime::currentDateTime().toTime_t());
662
663 // select cm
664 RecentModel::instance().selectionModel()->setCurrentIndex(RecentModel::instance().getIndex(cm),
665 QItemSelectionModel::ClearAndSelect);
666 ui->ringContactLineEdit->clear();
Anthony Léonard5cc76412017-04-21 16:52:25 -0400667 cm->setAccount(AvailableAccountModel::instance().currentDefaultAccount(cm));
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400668}
669
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400670bool
671CallWidget::uriNeedNameLookup(const URI uri_passed)
672{
673 if (uri_passed.protocolHint() == URI::ProtocolHint::RING_USERNAME ) {
674 return TRUE;
675 } else if (
676 uri_passed.protocolHint() != URI::ProtocolHint::RING && // not a RingID
677 uri_passed.schemeType() == URI::SchemeType::NONE // scheme type not specified
678 ){
Anthony Léonard2d99df02017-04-19 16:35:19 -0400679 // if no scheme type has been specified, determine ring vs sip by the current selected account
680 auto idx = AvailableAccountModel::instance().selectionModel()->currentIndex();
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400681 if (idx.isValid()) {
682 auto account = idx.data((int)Ring::Role::Object).value<Account *>();
683 if (account && account->protocol() == Account::Protocol::RING)
684 return TRUE;
685 }
686 }
687
688 return FALSE;
689}
690
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400691void
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400692CallWidget::processContactLineEdit()
Nicolas Jager97a21b42015-12-03 16:55:45 -0500693{
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400694 auto contactLineText = ui->ringContactLineEdit->text();
695 URI uri_passed = URI(contactLineText);
Anthony Léonard5cc76412017-04-21 16:52:25 -0400696 Account* ac = getSelectedAccount();
Nicolas Jager5e845d52016-02-18 13:26:12 -0500697
Olivier SOLDANO63178ee2016-11-04 16:50:08 -0400698 if (!contactLineText.isNull() && !contactLineText.isEmpty()){
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400699 if (uriNeedNameLookup(uri_passed)){
Anthony Léonard2d99df02017-04-19 16:35:19 -0400700 NameDirectory::instance().lookupName(ac, QString(), uri_passed);
Olivier SOLDANO63178ee2016-11-04 16:50:08 -0400701 } else {
702 searchContactLineEditEntry(uri_passed);
703 }
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400704 }
Nicolas Jager97a21b42015-12-03 16:55:45 -0500705}
706
707void
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400708CallWidget::on_ringContactLineEdit_returnPressed()
Nicolas Jager97a21b42015-12-03 16:55:45 -0500709{
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400710 processContactLineEdit();
711}
712
713void
714CallWidget::searchBtnClicked()
715{
716 processContactLineEdit();
Nicolas Jager97a21b42015-12-03 16:55:45 -0500717}
718
719void
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500720CallWidget::btnComBarVideoClicked()
Nicolas Jager97a21b42015-12-03 16:55:45 -0500721{
722 if (not highLightedIndex_.isValid())
723 return;
724
725 on_smartList_doubleClicked(highLightedIndex_);
726}
Edric Milaretab12d022015-12-04 16:09:44 -0500727
728void
Anthony Léonardd47179c2017-03-28 10:39:10 -0400729CallWidget::selectedAccountChanged(const QModelIndex &current, const QModelIndex &previous)
730{
731 Q_UNUSED(previous)
732
733 if (current.isValid()) {
Olivier SOLDANO97c4c2d2017-05-08 13:22:44 -0400734 if (ui->selectBar->isHidden()){
735 ui->selectBar->show();
736 }
Anthony Léonard2d99df02017-04-19 16:35:19 -0400737 auto ac = current.data(static_cast<int>(Account::Role::Object)).value<Account*>();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400738
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400739 // First, we get back to the welcome view (except if in call)
740
741 if (ui->stackedWidget->currentWidget() != ui->videoPage &&
742 ui->stackedWidget->currentWidget() != ui->welcomePage) {
Anthony Léonardd47179c2017-03-28 10:39:10 -0400743 slidePage(ui->welcomePage);
744 }
745
Anthony Léonard266dd302017-03-31 14:38:32 -0400746 // We setup the ringIdLabel and the QRCode
747 auto protocol = ac->protocol();
748 if (protocol == Account::Protocol::RING) {
749 ui->ringIdLabel->setText((ac->registeredName().isEmpty())?ac->username():ac->registeredName());
750 setupQRCode(ac->username());
751 } else {
752 ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND"));
753 }
754
Anthony Léonardd47179c2017-03-28 10:39:10 -0400755 // Then, we update the pending CR list with those from the newly selected account
756 if (disconnect(crListSelectionConnection_)) {
Anthony Léonardecfe7422017-05-04 14:14:37 -0400757 ui->contactRequestList->selectionModel()->clear();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400758 // The selection model must be deleted by the application (see QT doc).
Olivier SOLDANO69361192017-04-20 10:32:05 -0400759 QItemSelectionModel* sMod = ui->contactRequestList->selectionModel();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400760 delete sMod;
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400761 RecentModel::instance().selectionModel()->clear();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400762 }
763
Olivier SOLDANO69361192017-04-20 10:32:05 -0400764 ui->contactRequestList->setItemModel(ac->pendingContactRequestModel());
Anthony Léonard2d99df02017-04-19 16:35:19 -0400765
766 // We modify the currentAccountWidget to reflect the new selected account
767 // if the event wasn't triggered by this widget
768 ui->currentAccountWidget->changeSelectedIndex(current.row());
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400769
770 if (actualCall_){
771 // keep call on foreground
772 callStateToView(actualCall_);
773 }
Olivier SOLDANO97c4c2d2017-05-08 13:22:44 -0400774 } else {
775 ui->selectBar->hide();
776 ui->ringIdLabel->setText("");
Anthony Léonardd47179c2017-03-28 10:39:10 -0400777 }
778}
779
780void
Edric Milaret6b68a482016-02-01 15:23:44 -0500781CallWidget::showIMOutOfCall(const QModelIndex& nodeIdx)
Edric Milaretab12d022015-12-04 16:09:44 -0500782{
Edric Milaretab12d022015-12-04 16:09:44 -0500783 ui->contactMethodComboBox->clear();
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400784 QString name = nodeIdx.data(static_cast<int>(Ring::Role::Name)).toString();
785 QString number = nodeIdx.data(static_cast<int>(Ring::Role::Number)).toString();
786
Olivier SOLDANO31b9aac2017-07-14 15:50:09 -0400787 ui->imNameLabel->setText(QString(tr("%1", "%1 is the contact username"))
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400788 .arg(name));
789
790 if (name != number){
791 ui->imIdLabel->show();
792 ui->imIdLabel->setText(QString(tr("%1", "%1 is the contact unique identifier"))
793 .arg(number));
794 } else {
795 ui->imIdLabel->hide();
796 }
797
Edric Milaretab12d022015-12-04 16:09:44 -0500798 auto cmVector = RecentModel::instance().getContactMethods(nodeIdx);
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400799 ui->contactMethodComboBox->setVisible(cmVector.size() > 1);
Edric Milaretab12d022015-12-04 16:09:44 -0500800 foreach (const ContactMethod* cm, cmVector) {
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400801 ui->contactMethodComboBox->addItem(cm->bestId());
Edric Milaretab12d022015-12-04 16:09:44 -0500802 }
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400803
Anthony Léonard041ad392017-07-14 16:44:09 -0400804 ui->sendContactRequestPageButton->setVisible(shouldDisplayInviteButton(*cmVector[0]));
805
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500806 ui->stackedWidget->setCurrentWidget(ui->messagingPage);
Edric Milaret70ae8782016-04-18 16:10:44 -0400807 disconnect(imClickedConnection_);
808 imClickedConnection_ = connect(ui->listMessageView, &QListView::clicked, [this](const QModelIndex& index) {
809 auto urlList = index.data(static_cast<int>(Media::TextRecording::Role::LinkList)).value<QList<QUrl>>();
810 if (urlList.size() == 1)
811 QDesktopServices::openUrl(urlList.at(0));
812 else if (urlList.size()) {
813 //TODO Handle multiple url in one message
814 }
815 });
Edric Milaretab12d022015-12-04 16:09:44 -0500816}
817
818void
Edric Milaret6a785af2016-03-07 15:39:30 -0500819CallWidget::on_sendIMButton_clicked()
Edric Milaretab12d022015-12-04 16:09:44 -0500820{
Edric Milaret6a785af2016-03-07 15:39:30 -0500821 if (ui->imMessageEdit->text().trimmed().isEmpty())
Edric Milaretab12d022015-12-04 16:09:44 -0500822 return;
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400823
824 auto idx = RecentModel::instance().selectionModel()->currentIndex();
825 auto cmVec = RecentModel::instance().getContactMethods(idx);
826 if (cmVec.size() > 0) {
827 auto cm = cmVec[0];
828 if(!cm) {
829 qWarning() << "Contact Method not found";
830 return;
831 }
832 QMap<QString, QString> msg;
833 msg["text/plain"] = ui->imMessageEdit->text();
834 cm->sendOfflineTextMessage(msg);
835 ui->imMessageEdit->clear();
Edric Milaretab12d022015-12-04 16:09:44 -0500836 } else {
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400837 qWarning() << "No contact method found for messaging";
Edric Milaretab12d022015-12-04 16:09:44 -0500838 }
839}
840
841void
Edric Milaret6a785af2016-03-07 15:39:30 -0500842CallWidget::on_imMessageEdit_returnPressed()
Edric Milaretab12d022015-12-04 16:09:44 -0500843{
Edric Milaret6a785af2016-03-07 15:39:30 -0500844 on_sendIMButton_clicked();
Edric Milaretab12d022015-12-04 16:09:44 -0500845}
846
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400847void CallWidget::on_contactMethodComboBox_currentIndexChanged(int index)
Edric Milaretab12d022015-12-04 16:09:44 -0500848{
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400849 auto idx = RecentModel::instance().selectionModel()->currentIndex();
850 auto cmVec = RecentModel::instance().getContactMethods(idx);
851 ContactMethod* cm {};
852
853 if (index < cmVec.size() && index >= 0 ){
854 cm = cmVec[index];
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400855 }
856
857 if (cm){
Anthony Léonard041ad392017-07-14 16:44:09 -0400858 ui->sendContactRequestPageButton->setVisible(shouldDisplayInviteButton(*cm));
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400859 if (auto txtRecording = cm->textRecording()) {
860 ui->listMessageView->setModel(txtRecording->instantMessagingModel());
861 if (imConnection_)
862 disconnect(imConnection_);
863 imConnection_ = connect(txtRecording,
864 SIGNAL(messageInserted(QMap<QString,QString>,ContactMethod*,Media::Media::Direction)),
865 this,
866 SLOT(slotAccountMessageReceived(QMap<QString,QString>,ContactMethod*,Media::Media::Direction)));
867 auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0;
868 if (messagesPresent) {
869 ui->listMessageView->scrollToBottom();
870 txtRecording->setAllRead();
871 }
872 ui->listMessageView->setVisible(messagesPresent);
873 ui->noMessagesLabel->setVisible(!messagesPresent);
874 if (not messagesPresent) {
875 imVisibleConnection_ = connect(txtRecording->instantMessagingModel(),
876 &QAbstractItemModel::rowsInserted,
877 [this, txtRecording]() {
878 if (imVisibleConnection_)
879 disconnect(imVisibleConnection_);
880 auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0;
881 ui->listMessageView->setVisible(messagesPresent);
882 ui->noMessagesLabel->setVisible(!messagesPresent);
883 });
884 }
Edric Milaret4be72022016-01-19 10:24:13 -0500885 }
Edric Milaretab12d022015-12-04 16:09:44 -0500886 }
887}
888
889void
890CallWidget::slotAccountMessageReceived(const QMap<QString,QString> message,
891 ContactMethod* cm,
892 Media::Media::Direction dir)
893{
894 Q_UNUSED(message)
Edric Milaretab12d022015-12-04 16:09:44 -0500895 Q_UNUSED(dir)
896
897 ui->listMessageView->scrollToBottom();
Edric Milaret23fd3fa2016-01-15 15:37:35 -0500898 cm->textRecording()->setAllRead();
Edric Milaretab12d022015-12-04 16:09:44 -0500899}
Edric Milaretfa05d972016-01-13 16:22:04 -0500900
901void
Edric Milaret8001f6f2016-01-27 09:55:12 -0500902CallWidget::on_ringContactLineEdit_textChanged(const QString& text)
Edric Milaretfa05d972016-01-13 16:22:04 -0500903{
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400904 RecentModel::instance().peopleProxy()->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive, QRegExp::FixedString));
Edric Milaretfa05d972016-01-13 16:22:04 -0500905}
Edric Milareta0ebd062016-01-13 12:18:23 -0500906
Nicolas Jagerca850292016-01-17 14:11:10 -0500907void
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400908CallWidget::backToWelcomePage()
Edric Milareta0ebd062016-01-13 12:18:23 -0500909{
Edric Milaret6b68a482016-02-01 15:23:44 -0500910 RecentModel::instance().selectionModel()->clear();
Anthony Léonard7c630322017-05-03 15:51:14 -0400911 disconnect(imConnection_);
Nicolas Jagerca850292016-01-17 14:11:10 -0500912}
913
Olivier SOLDANO19193412017-06-06 12:03:36 -0400914void CallWidget::hideMiniSpinner()
915{
916 if(ui->spinnerLabel->isVisible()){
917 miniSpinner_->stop();
918 ui->spinnerLabel->hide();
919 }
920}
921
Nicolas Jagerca850292016-01-17 14:11:10 -0500922void
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400923CallWidget::on_imBackButton_clicked()
924{
925 backToWelcomePage();
926}
927
928void
Edric Milaret6b68a482016-02-01 15:23:44 -0500929CallWidget::slidePage(QWidget* widget, bool toRight)
Nicolas Jagerca850292016-01-17 14:11:10 -0500930{
Edric Milaret6b68a482016-02-01 15:23:44 -0500931 short dir = (toRight ? -1 : 1);
Nicolas Jagerca850292016-01-17 14:11:10 -0500932 ui->stackedWidget->setCurrentWidget(widget);
Edric Milaret6b68a482016-02-01 15:23:44 -0500933 pageAnim_->setTargetObject(widget);
934 pageAnim_->setDuration(animDuration_);
935 pageAnim_->setStartValue(QPoint(widget->width() * dir, widget->y()));
936 pageAnim_->setEndValue(QPoint(widget->x(), widget->y()));
937 pageAnim_->setEasingCurve(QEasingCurve::OutQuad);
938 pageAnim_->start();
Nicolas Jagerca850292016-01-17 14:11:10 -0500939}
940
941void
Edric Milaret1e598592016-09-02 10:10:01 -0400942CallWidget::on_qrButton_toggled(bool checked)
943{
944 ui->qrLabel->setVisible(checked);
945}
946
947void
Edric Milaret4097d2f2016-02-09 14:41:50 -0500948CallWidget::on_shareButton_clicked()
949{
Edric Milaret1e598592016-09-02 10:10:01 -0400950 Utils::InvokeMailto(tr("Contact me on Ring"), tr("My RingId is : ") + ui->ringIdLabel->text());
Edric Milaret4097d2f2016-02-09 14:41:50 -0500951}
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400952
953void
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400954CallWidget::contactLineEdit_registeredNameFound(Account* account,NameDirectory::LookupStatus status,
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400955 const QString& address,const QString& name)
956{
957 URI uri = URI(ui->ringContactLineEdit->text());
958 QString username_to_lookup = uri.userinfo();
959
960 if (username_to_lookup.compare(name) != 0){
961 return;
962 }
963
964 switch (status)
965 {
966 case NameDirectory::LookupStatus::SUCCESS:
967 {
968 uri = URI("ring:" + address);
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400969 qDebug() << "contactLineEdit username to search: " << username_to_lookup;
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400970 qDebug() << uri;
971 searchContactLineEditEntry(uri);
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400972 auto cm = PhoneDirectoryModel::instance().getNumber(uri);
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400973 cm->setAccount(account);
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400974 break;
975 }
976 case NameDirectory::LookupStatus::INVALID_NAME:
977 {
978 qDebug() << "Invalid Ring username";
979 break;
980 }
981 case NameDirectory::LookupStatus::ERROR:
982 case NameDirectory::LookupStatus::NOT_FOUND:
983 default:
984 {
985 qDebug() << "Could not resolve Ring username";
986 break;
987 }
988 }
989}
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400990
991void
992CallWidget::on_sendContactRequestPageButton_clicked()
993{
994 ui->sendContactRequestWidget->sendCR(RecentModel::instance().selectionModel()->currentIndex());
Olivier SOLDANO5d4a1ff2017-05-08 13:12:47 -0400995 // temporarly changed comportment waiting for message in payload implementation
996 /*ui->sendContactRequestWidget->setup(RecentModel::instance().selectionModel()->currentIndex());
997 slidePage(ui->sendContactRequestPage);*/
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400998}
999
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -04001000void
1001CallWidget::on_sendCRBackButton_clicked()
Olivier SOLDANOdd878662017-03-27 16:00:06 -04001002{
Anthony Léonardecfe7422017-05-04 14:14:37 -04001003 ui->stackedWidget->setCurrentWidget(ui->messagingPage);
Olivier SOLDANOdd878662017-03-27 16:00:06 -04001004}
Anthony Léonardd47179c2017-03-28 10:39:10 -04001005
1006void
1007CallWidget::on_pendingCRBackButton_clicked()
1008{
Olivier SOLDANO69361192017-04-20 10:32:05 -04001009 ui->contactRequestList->selectionModel()->clear();
Olivier SOLDANO8179e992017-07-19 15:59:19 -04001010 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Anthony Léonardd47179c2017-03-28 10:39:10 -04001011}
Anthony Léonard5cc76412017-04-21 16:52:25 -04001012
1013Account*
1014CallWidget::getSelectedAccount()
1015{
1016 auto idx = AvailableAccountModel::instance().selectionModel()->currentIndex();
1017 if (idx.isValid()) {
1018 auto ac = idx.data(static_cast<int>(Ring::Role::Object)).value<Account*>();
1019 return ac;
1020 }
1021 return nullptr;
1022}
Anthony Léonardecfe7422017-05-04 14:14:37 -04001023
Anthony Léonard041ad392017-07-14 16:44:09 -04001024bool
1025CallWidget::shouldDisplayInviteButton(ContactMethod &cm)
1026{
1027 // Displaying the button for a SIP ContactMethod is a nonsense
1028 if (cm.protocolHint() == URI::ProtocolHint::RING) {
1029 // If we know that the other accepted us
1030 if (cm.isConfirmed())
1031 return false;
1032
1033 // If not sure, we still check if the contact method is linked to a
1034 // Ring account or if the selected account is a RING one.
1035 if(auto linkedAccount = cm.account())
1036 return linkedAccount->protocol() == Account::Protocol::RING;
1037 else if (auto acc = getSelectedAccount())
1038 return acc->protocol() == Account::Protocol::RING;
1039 }
1040 return false;
1041}
1042
Olivier SOLDANO8179e992017-07-19 15:59:19 -04001043void CallWidget::on_contactRequestList_clicked(const QModelIndex &index)
Anthony Léonardecfe7422017-05-04 14:14:37 -04001044{
Olivier SOLDANO8179e992017-07-19 15:59:19 -04001045 RecentModel::instance().selectionModel()->clear();
1046 contactReqListCurrentChanged(index, QModelIndex());
Anthony Léonardecfe7422017-05-04 14:14:37 -04001047}