blob: 846704fdb36cccad9e49059f0ae52ddcf090ecfa [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
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400121 ui->smartList->setContextMenuPolicy(Qt::CustomContextMenu);
Edric Milaret627500d2015-03-27 16:41:40 -0400122
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500123 connect(ui->smartList, &SmartList::btnVideoClicked, this, &CallWidget::btnComBarVideoClicked);
Nicolas Jager41e4fcf2016-01-28 11:37:03 -0500124
Edric Milaret6b68a482016-02-01 15:23:44 -0500125 connect(RecentModel::instance().selectionModel(),
Olivier SOLDANO61065ec2016-11-11 16:31:34 -0500126 SIGNAL(currentChanged(QModelIndex,QModelIndex)),
127 this,
128 SLOT(smartListCurrentChanged(QModelIndex,QModelIndex)));
129
Olivier SOLDANO70279d32017-07-18 15:21:34 -0400130 //set most recent call to view
Olivier SOLDANOaf8f2822017-07-11 12:15:18 -0400131 connect(&RecentModel::instance(), &QAbstractItemModel::dataChanged, [=](const QModelIndex &topLeft, const QModelIndex &bottomRight,const QVector<int> &vec){
132 Q_UNUSED(bottomRight)
133 Q_UNUSED(vec)
Olivier SOLDANOaf8f2822017-07-11 12:15:18 -0400134
Olivier SOLDANO70279d32017-07-18 15:21:34 -0400135 if (topLeft.isValid() && RecentModel::instance().hasActiveCall(topLeft)){
136 ui->smartList->selectionModel()->setCurrentIndex(topLeft,QItemSelectionModel::ClearAndSelect);
Olivier SOLDANOaf8f2822017-07-11 12:15:18 -0400137 }
138 });
139
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500140 connect(RecentModel::instance().selectionModel(), &QItemSelectionModel::selectionChanged, [=](const QItemSelection &selected, const QItemSelection &deselected) {
141 // lambda used to focus on the correct smartList element when switching automatically between two calls
142 Q_UNUSED(deselected)
143 if (selected.size()) {
144 auto idx = selected.indexes().first();
145 auto realIdx = RecentModel::instance().peopleProxy()->mapFromSource(idx);
146 ui->smartList->selectionModel()->setCurrentIndex(realIdx, QItemSelectionModel::ClearAndSelect);
Anthony Léonardecfe7422017-05-04 14:14:37 -0400147 } else {
148 RecentModel::instance().selectionModel()->clearCurrentIndex();
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500149 ui->smartList->clearSelection();
Anthony Léonardecfe7422017-05-04 14:14:37 -0400150 ui->smartList->selectionModel()->clearCurrentIndex();
151 }
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500152 });
153
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400154 connect(&NameDirectory::instance(), SIGNAL(registeredNameFound(Account*,NameDirectory::LookupStatus,const QString&,const QString&)),
155 this, SLOT(contactLineEdit_registeredNameFound(Account*,NameDirectory::LookupStatus,const QString&,const QString&)));
156
157 connect(&AccountModel::instance(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
158 ui->currentAccountWidget, SLOT(update()));
159
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400160 connect(ui->searchBtn, SIGNAL(clicked(bool)), this, SLOT(searchBtnClicked()));
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400161
Olivier SOLDANOc1ca2df2017-09-06 16:01:46 -0400162 connect(ui->sendContactRequestWidget, &SendContactRequestWidget::sendCRclicked, [=]{Utils::slidePage(ui->stackedWidget, ui->messagingPage);});
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400163
Anthony Léonardd47179c2017-03-28 10:39:10 -0400164 connect(ui->contactRequestWidget, &ContactRequestWidget::choiceMade, [this]() {
Anthony Léonardecfe7422017-05-04 14:14:37 -0400165 if (getSelectedAccount()->pendingContactRequestModel()->rowCount() == 0)
166 ui->mainTabMenu->setCurrentWidget(ui->mainTabMenuPage1);
167 else
168 ui->contactRequestList->selectionModel()->clear();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400169 });
170
Anthony Léonard2d99df02017-04-19 16:35:19 -0400171 connect(AvailableAccountModel::instance().selectionModel(), &QItemSelectionModel::currentChanged,
Anthony Léonardd47179c2017-03-28 10:39:10 -0400172 this, &CallWidget::selectedAccountChanged);
173
174 // It needs to be called manually once to initialize the ui with the account selected at start.
175 // The second argument (previous) is set to an invalid QModelIndex as it is the first selection.
Anthony Léonard2d99df02017-04-19 16:35:19 -0400176 selectedAccountChanged(AvailableAccountModel::instance().selectionModel()->currentIndex(), QModelIndex());
177
178 // This connect() is used to initialise and track changes of profile's picture
179 connect(&ProfileModel::instance(), &ProfileModel::dataChanged,
180 ui->currentAccountWidget, &CurrentAccountWidget::setPhoto);
Anthony Léonardd47179c2017-03-28 10:39:10 -0400181
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400182 connect(ui->videoWidget, &VideoView::videoSettingsClicked, this, &CallWidget::settingsButtonClicked);
Olivier SOLDANO5cb1a422017-07-26 11:16:50 -0400183
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400184 connect(ui->smartList, &QListView::customContextMenuRequested, [=](const QPoint& pos){ setupSmartListMenu(pos);});
185
Olivier SOLDANO19193412017-06-06 12:03:36 -0400186 // setup searchingfor mini spinner
187 miniSpinner_ = new QMovie(":/images/waiting.gif");
188 ui->spinnerLabel->setMovie(miniSpinner_);
189 ui->spinnerLabel->hide();
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400190
Edric Milaret80e0b212015-10-16 10:07:43 -0400191 } catch (const std::exception& e) {
192 qDebug() << "INIT ERROR" << e.what();
Edric Milaret627500d2015-03-27 16:41:40 -0400193 }
Olivier SOLDANO2100f1c2017-09-06 16:45:20 -0400194
195 setupOutOfCallIM();
Edric Milaret627500d2015-03-27 16:41:40 -0400196}
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);
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400216
Edric Milareta0ebd062016-01-13 12:18:23 -0500217 connect(copyAction, &QAction::triggered, [=]() {
218 auto idx = ui->listMessageView->currentIndex();
219 if (idx.isValid()) {
220 auto text = ui->listMessageView->model()->data(idx);
221 QApplication::clipboard()->setText(text.value<QString>());
222 }
223 });
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400224
Edric Milaret70ae8782016-04-18 16:10:44 -0400225 QSettings settings;
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400226
Edric Milareta0ebd062016-01-13 12:18:23 -0500227 auto displayDate = new QAction(tr("Display date"), this);
228 displayDate->setCheckable(true);
Edric Milaret70ae8782016-04-18 16:10:44 -0400229 displayDate->setChecked(settings.value(SettingsKey::imShowDate).toBool());
Edric Milareta0ebd062016-01-13 12:18:23 -0500230 ui->listMessageView->addAction(displayDate);
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400231
Edric Milareta0ebd062016-01-13 12:18:23 -0500232 auto displayAuthor = new QAction(tr("Display author"), this);
233 displayAuthor->setCheckable(true);
Edric Milaret70ae8782016-04-18 16:10:44 -0400234 displayAuthor->setChecked(settings.value(SettingsKey::imShowAuthor).toBool());
Edric Milareta0ebd062016-01-13 12:18:23 -0500235 ui->listMessageView->addAction(displayAuthor);
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400236
Edric Milareta0ebd062016-01-13 12:18:23 -0500237 auto lamdba = [=](){
Edric Milaret70ae8782016-04-18 16:10:44 -0400238 QSettings settings;
239 settings.setValue(SettingsKey::imShowAuthor, displayAuthor->isChecked());
240 settings.setValue(SettingsKey::imShowDate, displayDate->isChecked());
241 emit imDelegate_->sizeHintChanged(QModelIndex());
Edric Milareta0ebd062016-01-13 12:18:23 -0500242 };
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400243
Edric Milareta0ebd062016-01-13 12:18:23 -0500244 connect(displayAuthor, &QAction::triggered, lamdba);
245 connect(displayDate, &QAction::triggered, lamdba);
Edric Milaret00a32252016-01-19 10:37:13 -0500246
247 connect(&::Media::RecordingModel::instance(),
248 SIGNAL(newTextMessage(::Media::TextRecording*, ContactMethod*)),
249 this,
250 SLOT(onIncomingMessage(::Media::TextRecording*, ContactMethod*)));
251}
252
253void
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400254CallWidget::onIncomingMessage(::Media::TextRecording* t, ContactMethod* cm)
255{
Edric Milaret00a32252016-01-19 10:37:13 -0500256 Q_UNUSED(cm)
257
258 if (!QApplication::focusWidget()) {
259 auto idx = t->instantTextMessagingModel()->
260 index(t->instantTextMessagingModel()->rowCount()-1, 0);
261 GlobalSystemTray::instance()
262 .showMessage("Ring",
263 QString(tr("Message incoming from %1")).arg(
264 idx.data((int)Media::TextRecording::Role::AuthorDisplayname).toString()));
265 QApplication::alert(this, 5000);
266 }
Edric Milareta0ebd062016-01-13 12:18:23 -0500267}
268
269void
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400270CallWidget::triggerDeleteContactDialog(ContactMethod *cm, Account *ac)
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400271{
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400272 auto dlg = new DeleteContactDialog(cm, ac);
273 dlg->exec();
274}
Edric Milareta0ebd062016-01-13 12:18:23 -0500275
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400276void
277CallWidget::setupSmartListMenu(const QPoint& pos)
278{
279 auto idx = ui->smartList->currentIndex();
Edric Milaret9949b342016-02-02 12:25:08 -0500280
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400281 if (not idx.isValid())
282 return;
283
284 QPoint globalPos = ui->smartList->mapToGlobal(pos);
285 QMenu menu;
286 QVector<ContactMethod*> contactMethods = RecentModel::instance()
287 .getContactMethods(RecentModel::instance().peopleProxy()->mapToSource(idx));
288
289 if (contactMethods.isEmpty())
290 return;
291
292 auto contactMethod = contactMethods.first();
293
294 if (contactMethods.size() == 1){
295 auto copyAction = new QAction(tr("Copy number"), this);
296 menu.addAction(copyAction);
297 connect(copyAction, &QAction::triggered, [contactMethod]() {
298 QApplication::clipboard()->setText(contactMethod->uri());
299 });
300
301 auto copyNameAction = new QAction(tr("Copy name"), this);
302 menu.addAction(copyNameAction);
303 connect(copyNameAction, &QAction::triggered, [contactMethod]() {
304 QApplication::clipboard()->setText(contactMethod->primaryName());
305 });
306 } else {
307 auto callMenu = menu.addMenu(tr("Call Number"));
308 auto copyMenu = menu.addMenu(tr("Copy Number"));
309 for (auto cM : contactMethods) {
310 auto uri = cM->bestId();
311 auto copyAction = new QAction(tr("Copy %1").arg(uri), this);
312 copyMenu->addAction(copyAction);
313 connect(copyAction, &QAction::triggered, [uri]() {
314 QApplication::clipboard()->setText(uri);
Edric Milareta0ebd062016-01-13 12:18:23 -0500315 });
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400316 auto callAction = new QAction(tr("Call %1").arg(uri), this);
317 callMenu->addAction(callAction);
318 connect(callAction, &QAction::triggered, [cM]() {
319 Call* c = CallModel::instance().dialingCall(cM);
320 c->performAction(Call::Action::ACCEPT);
Edric Milaretac21b3d2016-09-01 12:45:49 -0400321 });
Edric Milaret9949b342016-02-02 12:25:08 -0500322 }
Olivier SOLDANOcc28a0d2017-07-21 13:53:31 -0400323 }
324
325 auto ac = getSelectedAccount();
326 if (ac && !ac->hasContact(contactMethod)) {
327 auto addExisting = new QAction(tr("Add to contacts"), this);
328 menu.addAction(addExisting);
329 connect(addExisting, &QAction::triggered, [this, contactMethod, ac]() {
330 /* uncomment and capture globalPos in lambda to reactivate popup
331 ContactPicker contactPicker(contactMethod);
332 contactPicker.move(globalPos.x(), globalPos.y() - (contactPicker.height()/2));
333 contactPicker.exec();
334 */
335 ac->addContact(contactMethod);
336 });
337 } else if (ac) {
338 auto removeExisting = new QAction(tr("Remove from contacts"), this);
339 menu.addAction(removeExisting);
340 connect(removeExisting, &QAction::triggered, [this, contactMethod, ac]() {
341 triggerDeleteContactDialog(contactMethod, ac);
342 });
343 }
344
345 menu.exec(globalPos);
Edric Milareta0ebd062016-01-13 12:18:23 -0500346}
347
Anthony Léonarda86a8972016-12-15 10:33:47 -0500348void CallWidget::setupQRCode(QString ringID)
Edric Milarete19c4cd2016-02-12 10:19:44 -0500349{
Anthony Léonarda86a8972016-12-15 10:33:47 -0500350 auto rcode = QRcode_encodeString(ringID.toStdString().c_str(),
Edric Milaret6d0e5312016-04-04 16:30:22 -0400351 0, //Let the version be decided by libqrencode
352 QR_ECLEVEL_L, // Lowest level of error correction
Edric Milarete19c4cd2016-02-12 10:19:44 -0500353 QR_MODE_8, // 8-bit data mode
354 1);
355 if (not rcode) {
356 qWarning() << "Failed to generate QR code: " << strerror(errno);
357 return;
358 }
359
360 auto margin = 5;
361 int qrwidth = rcode->width + margin * 2;
362 QImage result(QSize(qrwidth, qrwidth), QImage::Format_Mono);
363 QPainter painter;
364 painter.begin(&result);
365 painter.setClipRect(QRect(0, 0, qrwidth, qrwidth));
366 painter.setPen(QPen(Qt::black, 0.1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
367 painter.setBrush(Qt::black);
368 painter.fillRect(QRect(0, 0, qrwidth, qrwidth), Qt::white);
Edric Milaret74474f52016-05-16 13:36:23 -0400369 unsigned char* p;
Edric Milarete19c4cd2016-02-12 10:19:44 -0500370 p = rcode->data;
371 for(int y = 0; y < rcode->width; y++) {
Edric Milaret74474f52016-05-16 13:36:23 -0400372 unsigned char* row = (p + (y * rcode->width));
Edric Milarete19c4cd2016-02-12 10:19:44 -0500373 for(int x = 0; x < rcode->width; x++) {
374 if(*(row + x) & 0x1) {
375 painter.drawRect(margin + x, margin + y, 1, 1);
376 }
377 }
378
379 }
380 painter.end();
381 QRcode_free(rcode);
Edric Milaret6d0e5312016-04-04 16:30:22 -0400382 ui->qrLabel->setPixmap(QPixmap::fromImage(result.scaled(QSize(qrSize_, qrSize_), Qt::KeepAspectRatio)));
Edric Milarete19c4cd2016-02-12 10:19:44 -0500383}
384
Olivier SOLDANO2100f1c2017-09-06 16:45:20 -0400385bool
Edric Milaret67007d12015-05-07 09:40:09 -0400386CallWidget::findRingAccount()
387{
Anthony Léonard266dd302017-03-31 14:38:32 -0400388 bool ringAccountFound = false;
Edric Milareta3e47282015-10-23 15:20:30 -0400389 auto a_count = AccountModel::instance().rowCount();
Edric Milaret627500d2015-03-27 16:41:40 -0400390 for (int i = 0; i < a_count; ++i) {
Edric Milareta3e47282015-10-23 15:20:30 -0400391 auto idx = AccountModel::instance().index(i, 0);
Edric Milaret627500d2015-03-27 16:41:40 -0400392 auto protocol = idx.data(static_cast<int>(Account::Role::Proto));
Edric Milaret74474f52016-05-16 13:36:23 -0400393 if (static_cast<Account::Protocol>(protocol.toUInt()) == Account::Protocol::RING) {
Anthony Léonard266dd302017-03-31 14:38:32 -0400394 ringAccountFound = true;
Edric Milareta3e47282015-10-23 15:20:30 -0400395 auto account = AccountModel::instance().getAccountByModelIndex(idx);
Edric Milaret68779c42015-07-09 16:53:03 -0400396 if (account->displayName().isEmpty())
397 account->displayName() = account->alias();
Edric Milaret57467842016-08-30 13:06:11 -0400398 if (account->needsMigration()) {
399 WizardDialog dlg(WizardDialog::MIGRATION, account);
400 dlg.exec();
401 }
Edric Milaret627500d2015-03-27 16:41:40 -0400402 }
403 }
Olivier SOLDANO2100f1c2017-09-06 16:45:20 -0400404
Anthony Léonard266dd302017-03-31 14:38:32 -0400405 if (!ringAccountFound) {
Edric Milaret57467842016-08-30 13:06:11 -0400406 WizardDialog wizardDialog;
407 wizardDialog.exec();
Olivier SOLDANO2100f1c2017-09-06 16:45:20 -0400408 if (wizardDialog.result() != QDialog::Accepted) {
409 return false;
410 }
Edric Milaret57467842016-08-30 13:06:11 -0400411 }
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400412
413 ui->currentAccountWidget->update();
414
Olivier SOLDANO2100f1c2017-09-06 16:45:20 -0400415 return true;
Edric Milaret627500d2015-03-27 16:41:40 -0400416}
417
418void
Edric Milaret00d34f22016-05-09 16:30:29 -0400419CallWidget::callChangedSlot()
420{
421 if (not actualCall_)
422 return;
Olivier SOLDANO2c03dc72017-05-25 11:17:13 -0400423
Edric Milaret41941582016-09-14 12:59:04 -0400424 ui->callerIdLabel->setText(QString("%1")
Edric Milaret00d34f22016-05-09 16:30:29 -0400425 .arg(actualCall_->formattedName()));
426 ui->callerPhoto->setPixmap(
427 QPixmap::fromImage(
428 GlobalInstances::pixmapManipulator()
429 .callPhoto(actualCall_, QSize(130,130)).value<QImage>()));
Olivier SOLDANO2c03dc72017-05-25 11:17:13 -0400430 ui->callerBestIdLabel->setText(actualCall_->peerContactMethod()->bestId());
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400431
Olivier SOLDANO02971ce2016-11-04 15:38:29 -0400432 if(actualCall_->state() == Call::State::OVER || actualCall_->state() == Call::State::FAILURE){
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400433 ui->outboundCallLabel->setText(actualCall_->toHumanStateName(Call::State::INITIALIZATION));
434 } else {
435 ui->outboundCallLabel->setText(actualCall_->toHumanStateName());
436 }
Edric Milaret00d34f22016-05-09 16:30:29 -0400437}
438
439void
Nicolas Jager97a21b42015-12-03 16:55:45 -0500440CallWidget::callIncoming(Call* call)
Edric Milaret627500d2015-03-27 16:41:40 -0400441{
Edric Milaret00a32252016-01-19 10:37:13 -0500442 if (!QApplication::focusWidget()) {
443 GlobalSystemTray::instance()
444 .showMessage("Ring",
445 QString(tr("Call incoming from %1")).arg(call->formattedName()));
Edric Milaret2cf34292015-06-22 16:27:03 -0400446 QApplication::alert(this, 5000);
447 }
448
Edric Milaret6456baa2015-05-21 12:18:07 -0400449 setActualCall(call);
Edric Milaret627500d2015-03-27 16:41:40 -0400450}
451
452void
453CallWidget::on_acceptButton_clicked()
454{
455 if (actualCall_ != nullptr)
Edric Milaret53f57b62015-05-11 11:02:17 -0400456 actualCall_->performAction(Call::Action::ACCEPT);
Edric Milaret627500d2015-03-27 16:41:40 -0400457}
458
459void
460CallWidget::on_refuseButton_clicked()
461{
462 if (actualCall_ == nullptr)
463 return;
464 actualCall_->performAction(Call::Action::REFUSE);
Nicolas Jager13745062016-02-12 18:56:40 -0500465 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Edric Milaret6456baa2015-05-21 12:18:07 -0400466 setActualCall(nullptr);
Edric Milaret627500d2015-03-27 16:41:40 -0400467}
468
469void
Edric Milaret67007d12015-05-07 09:40:09 -0400470CallWidget::callStateChanged(Call* call, Call::State previousState)
471{
Edric Milaret627500d2015-03-27 16:41:40 -0400472 Q_UNUSED(previousState)
Edric Milaret4b1be4a2016-01-15 16:49:20 -0500473 if (call == nullptr
474 || call != actualCall_)
Edric Milaretb5b49072015-05-08 11:56:07 -0400475 return;
Edric Milareted0b2802015-10-01 15:10:02 -0400476
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500477 callStateToView(call);
478
Edric Milaret4b1be4a2016-01-15 16:49:20 -0500479 if (call->state() == Call::State::OVER) {
Edric Milaret6456baa2015-05-21 12:18:07 -0400480 setActualCall(nullptr);
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500481 ui->smartList->clearSelection();
Edric Milaret6b68a482016-02-01 15:23:44 -0500482 RecentModel::instance().selectionModel()->clear();
Edric Milaret627500d2015-03-27 16:41:40 -0400483 }
Edric Milaret627500d2015-03-27 16:41:40 -0400484}
485
486void
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400487CallWidget::atExit()
488{
Edric Milaret627500d2015-03-27 16:41:40 -0400489}
Edric Milaret67007d12015-05-07 09:40:09 -0400490
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400491void
492CallWidget::callStateToView(Call* value)
Edric Milaret6b68a482016-02-01 15:23:44 -0500493{
494 if (value) {
495 switch (value->state()) {
496 case Call::State::INCOMING:
497 if (not value->account()->isAutoAnswer())
498 ui->stackedWidget->setCurrentWidget(ui->callInvitePage);
499 else
500 ui->stackedWidget->setCurrentWidget(ui->videoPage);
501 break;
502 case Call::State::CURRENT:
Edric Milareta86e3f52016-03-14 16:28:57 -0400503 case Call::State::CONFERENCE:
Edric Milaret854c6b44d2016-03-08 11:00:48 -0500504 case Call::State::HOLD:
Edric Milaret6b68a482016-02-01 15:23:44 -0500505 ui->stackedWidget->setCurrentWidget(ui->videoPage);
Olivier SOLDANO19193412017-06-06 12:03:36 -0400506 hideMiniSpinner();
Edric Milaret6b68a482016-02-01 15:23:44 -0500507 break;
Olivier SOLDANO02971ce2016-11-04 15:38:29 -0400508 case Call::State::OVER:
Olivier SOLDANOea6d71b2016-11-16 15:56:59 -0500509 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Olivier SOLDANO02971ce2016-11-04 15:38:29 -0400510 break;
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400511 case Call::State::FAILURE:
512 case Call::State::ERROR:
Olivier SOLDANO02971ce2016-11-04 15:38:29 -0400513 on_cancelButton_clicked();
Olivier SOLDANO19193412017-06-06 12:03:36 -0400514 hideMiniSpinner();
Edric Milaret6b68a482016-02-01 15:23:44 -0500515 break;
516 case Call::State::INITIALIZATION:
517 case Call::State::CONNECTED:
518 case Call::State::RINGING:
Olivier SOLDANO19193412017-06-06 12:03:36 -0400519 miniSpinner_->start();
520 ui->spinnerLabel->show();
Edric Milaret6b68a482016-02-01 15:23:44 -0500521 ui->stackedWidget->setCurrentWidget(ui->outboundCallPage);
522 break;
523 default:
Edric Milaret854c6b44d2016-03-08 11:00:48 -0500524 qWarning() << "Call state not handled doing nothing : "
525 << value->toHumanStateName();
Edric Milaret6b68a482016-02-01 15:23:44 -0500526 break;
527 }
Nicolas Jager13745062016-02-12 18:56:40 -0500528 }
Edric Milaret6b68a482016-02-01 15:23:44 -0500529}
530
Edric Milaret6456baa2015-05-21 12:18:07 -0400531void
532CallWidget::setActualCall(Call* value)
533{
534 actualCall_ = value;
Edric Milaret80e0b212015-10-16 10:07:43 -0400535 CallModel::instance().selectCall(value);
536 ui->videoWidget->pushRenderer(value);
Edric Milareta86e3f52016-03-14 16:28:57 -0400537 ui->instantMessagingWidget->setMediaText(actualCall_);
Edric Milaret6b68a482016-02-01 15:23:44 -0500538 callStateToView(value);
Edric Milaret00d34f22016-05-09 16:30:29 -0400539 if (actualCall_) {
540 callChangedConnection_ = connect(actualCall_,
541 SIGNAL(changed()),
542 this,
543 SLOT(callChangedSlot()));
544 } else
545 disconnect(callChangedConnection_);
546
Edric Milaret6456baa2015-05-21 12:18:07 -0400547}
Edric Milaretc7ab5502015-06-15 11:18:02 -0400548
549void
Edric Milareted0b2802015-10-01 15:10:02 -0400550CallWidget::on_cancelButton_clicked()
Edric Milaretd8528fa2015-07-07 14:13:51 -0400551{
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400552 if (actualCall_){
Edric Milaretd8528fa2015-07-07 14:13:51 -0400553 actualCall_->performAction(Call::Action::REFUSE);
Olivier SOLDANO2f9e6702016-11-02 14:20:57 -0400554 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
555 }
Edric Milaretd8528fa2015-07-07 14:13:51 -0400556}
Edric Milareted0b2802015-10-01 15:10:02 -0400557
558void
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400559CallWidget::on_smartList_clicked(const QModelIndex& index)
560{
561 RecentModel::instance().selectionModel()->setCurrentIndex(
562 RecentModel::instance().peopleProxy()->mapToSource(index),
563 QItemSelectionModel::ClearAndSelect);
564}
565
566void
Nicolas Jager97a21b42015-12-03 16:55:45 -0500567CallWidget::on_smartList_doubleClicked(const QModelIndex& index)
Edric Milareted0b2802015-10-01 15:10:02 -0400568{
Olivier SOLDANO70279d32017-07-18 15:21:34 -0400569 if (!index.isValid())
570 return;
571
Edric Milareta3e47282015-10-23 15:20:30 -0400572 auto realIndex = RecentModel::instance().peopleProxy()->mapToSource(index);
573 if (RecentModel::instance().hasActiveCall(realIndex))
Edric Milareted0b2802015-10-01 15:10:02 -0400574 return;
575
576 ContactMethod* m = nullptr;
577 if (auto cm = realIndex.data((int)Call::Role::ContactMethod).value<ContactMethod*>()) {
578 m = cm;
579 } else {
580 if (auto person = realIndex.data((int)Person::Role::Object).value<Person*>()) {
581 m = person->phoneNumbers().first();
582 }
583 }
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500584
Edric Milareta3e47282015-10-23 15:20:30 -0400585 if (m && !RecentModel::instance().index(0, 0, realIndex).isValid()) {
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500586
587 QPixmap map = QPixmap::fromImage(
588 GlobalInstances::pixmapManipulator().callPhoto(m, QSize(130,130)).value<QImage>());
589 ui->callingPhoto->setPixmap(map);
590
Edric Milareta3e47282015-10-23 15:20:30 -0400591 Call* c = CallModel::instance().dialingCall(m);
Edric Milareted0b2802015-10-01 15:10:02 -0400592 c->performAction(Call::Action::ACCEPT);
Edric Milaret6b68a482016-02-01 15:23:44 -0500593 setActualCall(c);
Edric Milareted0b2802015-10-01 15:10:02 -0400594 }
595}
596
597void
Olivier SOLDANO61065ec2016-11-11 16:31:34 -0500598CallWidget::smartListCurrentChanged(const QModelIndex &currentIdx, const QModelIndex &previousIdx)
599{
600 Q_UNUSED(previousIdx);
Anthony Léonardecfe7422017-05-04 14:14:37 -0400601 if (not currentIdx.isValid()) {
602 auto widget = ui->stackedWidget->currentWidget();
603 if (widget == ui->messagingPage || widget == ui->videoPage)
Olivier SOLDANOc1ca2df2017-09-06 16:01:46 -0400604 Utils::slidePage(ui->stackedWidget, ui->welcomePage);
Anthony Léonardecfe7422017-05-04 14:14:37 -0400605 if(actualCall_)
606 setActualCall(nullptr);
Edric Milareted0b2802015-10-01 15:10:02 -0400607 return;
Anthony Léonardecfe7422017-05-04 14:14:37 -0400608 }
Edric Milareted0b2802015-10-01 15:10:02 -0400609
Olivier SOLDANO703caba2016-11-15 16:18:55 -0500610 //catch call of current index
Olivier SOLDANO61065ec2016-11-11 16:31:34 -0500611 auto currentIdxCall = RecentModel::instance().getActiveCall(currentIdx);
Olivier SOLDANO703caba2016-11-15 16:18:55 -0500612
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400613 if (currentIdxCall) {
614 if (currentIdxCall != actualCall_) //if it is different from actual call, switch between the two
615 setActualCall(currentIdxCall);
616 } else { // if there is no call attached to this smartlist index (contact tab)
Edric Milareta0ebd062016-01-13 12:18:23 -0500617 setActualCall(nullptr);
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400618 showIMOutOfCall(currentIdx); // change page to contact request of messaging page with correct behaviour
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400619 }
620 /*
621 else { // if non defined behaviour disconnect instant messaging and return to welcome page
Edric Milareted0b2802015-10-01 15:10:02 -0400622 setActualCall(nullptr);
Edric Milaret7ef617b2016-02-01 15:40:57 -0500623 if (imConnection_)
624 disconnect(imConnection_);
Edric Milareted0b2802015-10-01 15:10:02 -0400625 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
626 }
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400627 */
Edric Milareted0b2802015-10-01 15:10:02 -0400628}
629
630void
Anthony Léonardd47179c2017-03-28 10:39:10 -0400631CallWidget::contactReqListCurrentChanged(const QModelIndex &currentIdx, const QModelIndex &previousIdx)
632{
633 Q_UNUSED(previousIdx)
634
Anthony Léonardecfe7422017-05-04 14:14:37 -0400635 if (currentIdx.isValid()) {
636 ui->contactRequestWidget->setCurrentContactRequest(currentIdx);
637 ui->stackedWidget->setCurrentWidget(ui->contactRequestPage);
638 } else {
639 ui->contactRequestWidget->setCurrentContactRequest(QModelIndex());
640 if (ui->stackedWidget->currentWidget() == ui->contactRequestPage)
Olivier SOLDANOc1ca2df2017-09-06 16:01:46 -0400641 Utils::slidePage(ui->stackedWidget, ui->welcomePage);
Anthony Léonardecfe7422017-05-04 14:14:37 -0400642 }
Anthony Léonardd47179c2017-03-28 10:39:10 -0400643}
644
645void
Edric Milareted0b2802015-10-01 15:10:02 -0400646CallWidget::placeCall()
647{
Nicolas Jager97a21b42015-12-03 16:55:45 -0500648 if (ui->ringContactLineEdit->text().isEmpty())
Edric Milareted0b2802015-10-01 15:10:02 -0400649 return;
Nicolas Jager97a21b42015-12-03 16:55:45 -0500650 Call* c = CallModel::instance().dialingCall(PhoneDirectoryModel::instance().getNumber(ui->ringContactLineEdit->text()));
Edric Milareted0b2802015-10-01 15:10:02 -0400651 c->performAction(Call::Action::ACCEPT);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500652 ui->ringContactLineEdit->clear();
Edric1bed3f92016-05-19 10:24:48 -0400653 ui->callingPhoto->setPixmap(
654 QPixmap::fromImage(
655 GlobalInstances::pixmapManipulator()
656 .callPhoto(c, QSize(130,130)).value<QImage>()));
Edric Milareted0b2802015-10-01 15:10:02 -0400657}
658
659void
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500660CallWidget::settingsButtonClicked()
Edric Milareted0b2802015-10-01 15:10:02 -0400661{
662 emit NavigationRequested(ScreenEnum::ConfScreen);
663}
664
665void
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400666CallWidget::searchContactLineEditEntry(const URI &uri)
667{
Olivier SOLDANO73573642017-06-16 11:22:12 -0400668 auto cm = PhoneDirectoryModel::instance().getNumber(uri, getSelectedAccount());
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400669 // if its a new CM, bring it to the top
670 if (cm->lastUsed() == 0)
671 cm->setLastUsed(QDateTime::currentDateTime().toTime_t());
672
673 // select cm
674 RecentModel::instance().selectionModel()->setCurrentIndex(RecentModel::instance().getIndex(cm),
675 QItemSelectionModel::ClearAndSelect);
676 ui->ringContactLineEdit->clear();
Anthony Léonard5cc76412017-04-21 16:52:25 -0400677 cm->setAccount(AvailableAccountModel::instance().currentDefaultAccount(cm));
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400678}
679
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400680bool
681CallWidget::uriNeedNameLookup(const URI uri_passed)
682{
683 if (uri_passed.protocolHint() == URI::ProtocolHint::RING_USERNAME ) {
684 return TRUE;
685 } else if (
686 uri_passed.protocolHint() != URI::ProtocolHint::RING && // not a RingID
687 uri_passed.schemeType() == URI::SchemeType::NONE // scheme type not specified
688 ){
Anthony Léonard2d99df02017-04-19 16:35:19 -0400689 // if no scheme type has been specified, determine ring vs sip by the current selected account
690 auto idx = AvailableAccountModel::instance().selectionModel()->currentIndex();
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400691 if (idx.isValid()) {
692 auto account = idx.data((int)Ring::Role::Object).value<Account *>();
693 if (account && account->protocol() == Account::Protocol::RING)
694 return TRUE;
695 }
696 }
697
698 return FALSE;
699}
700
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400701void
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400702CallWidget::processContactLineEdit()
Nicolas Jager97a21b42015-12-03 16:55:45 -0500703{
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400704 auto contactLineText = ui->ringContactLineEdit->text();
705 URI uri_passed = URI(contactLineText);
Anthony Léonard5cc76412017-04-21 16:52:25 -0400706 Account* ac = getSelectedAccount();
Nicolas Jager5e845d52016-02-18 13:26:12 -0500707
Olivier SOLDANO63178ee2016-11-04 16:50:08 -0400708 if (!contactLineText.isNull() && !contactLineText.isEmpty()){
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400709 if (uriNeedNameLookup(uri_passed)){
Anthony Léonard2d99df02017-04-19 16:35:19 -0400710 NameDirectory::instance().lookupName(ac, QString(), uri_passed);
Olivier SOLDANO63178ee2016-11-04 16:50:08 -0400711 } else {
712 searchContactLineEditEntry(uri_passed);
713 }
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400714 }
Nicolas Jager97a21b42015-12-03 16:55:45 -0500715}
716
717void
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400718CallWidget::on_ringContactLineEdit_returnPressed()
Nicolas Jager97a21b42015-12-03 16:55:45 -0500719{
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -0400720 processContactLineEdit();
721}
722
723void
724CallWidget::searchBtnClicked()
725{
726 processContactLineEdit();
Nicolas Jager97a21b42015-12-03 16:55:45 -0500727}
728
729void
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500730CallWidget::btnComBarVideoClicked()
Nicolas Jager97a21b42015-12-03 16:55:45 -0500731{
732 if (not highLightedIndex_.isValid())
733 return;
734
735 on_smartList_doubleClicked(highLightedIndex_);
736}
Edric Milaretab12d022015-12-04 16:09:44 -0500737
738void
Anthony Léonardd47179c2017-03-28 10:39:10 -0400739CallWidget::selectedAccountChanged(const QModelIndex &current, const QModelIndex &previous)
740{
741 Q_UNUSED(previous)
742
743 if (current.isValid()) {
Olivier SOLDANO97c4c2d2017-05-08 13:22:44 -0400744 if (ui->selectBar->isHidden()){
745 ui->selectBar->show();
746 }
Anthony Léonard2d99df02017-04-19 16:35:19 -0400747 auto ac = current.data(static_cast<int>(Account::Role::Object)).value<Account*>();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400748
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400749 // First, we get back to the welcome view (except if in call)
750
751 if (ui->stackedWidget->currentWidget() != ui->videoPage &&
752 ui->stackedWidget->currentWidget() != ui->welcomePage) {
Olivier SOLDANOc1ca2df2017-09-06 16:01:46 -0400753 Utils::slidePage(ui->stackedWidget, ui->welcomePage);
Anthony Léonardd47179c2017-03-28 10:39:10 -0400754 }
755
Anthony Léonard266dd302017-03-31 14:38:32 -0400756 // We setup the ringIdLabel and the QRCode
757 auto protocol = ac->protocol();
758 if (protocol == Account::Protocol::RING) {
759 ui->ringIdLabel->setText((ac->registeredName().isEmpty())?ac->username():ac->registeredName());
760 setupQRCode(ac->username());
761 } else {
762 ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND"));
763 }
764
Anthony Léonardd47179c2017-03-28 10:39:10 -0400765 // Then, we update the pending CR list with those from the newly selected account
766 if (disconnect(crListSelectionConnection_)) {
Anthony Léonardecfe7422017-05-04 14:14:37 -0400767 ui->contactRequestList->selectionModel()->clear();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400768 // The selection model must be deleted by the application (see QT doc).
Olivier SOLDANO69361192017-04-20 10:32:05 -0400769 QItemSelectionModel* sMod = ui->contactRequestList->selectionModel();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400770 delete sMod;
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400771 RecentModel::instance().selectionModel()->clear();
Anthony Léonardd47179c2017-03-28 10:39:10 -0400772 }
773
Olivier SOLDANO69361192017-04-20 10:32:05 -0400774 ui->contactRequestList->setItemModel(ac->pendingContactRequestModel());
Anthony Léonard2d99df02017-04-19 16:35:19 -0400775
776 // We modify the currentAccountWidget to reflect the new selected account
777 // if the event wasn't triggered by this widget
778 ui->currentAccountWidget->changeSelectedIndex(current.row());
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400779
780 if (actualCall_){
781 // keep call on foreground
782 callStateToView(actualCall_);
783 }
Olivier SOLDANO97c4c2d2017-05-08 13:22:44 -0400784 } else {
785 ui->selectBar->hide();
786 ui->ringIdLabel->setText("");
Anthony Léonardd47179c2017-03-28 10:39:10 -0400787 }
788}
789
790void
Edric Milaret6b68a482016-02-01 15:23:44 -0500791CallWidget::showIMOutOfCall(const QModelIndex& nodeIdx)
Edric Milaretab12d022015-12-04 16:09:44 -0500792{
Edric Milaretab12d022015-12-04 16:09:44 -0500793 ui->contactMethodComboBox->clear();
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400794 QString name = nodeIdx.data(static_cast<int>(Ring::Role::Name)).toString();
795 QString number = nodeIdx.data(static_cast<int>(Ring::Role::Number)).toString();
796
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400797 if (getSelectedAccount()->isIp2ip()){
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400798 ui->imMessageEdit->setPlaceholderText("No messaging possible out of call (SIP) ");
799 ui->imMessageEdit->setEnabled(false);
800 ui->sendIMButton->hide();
801 } else {
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400802 ui->imMessageEdit->setPlaceholderText("Type your message here");
803 ui->imMessageEdit->setEnabled(true);
804 ui->sendIMButton->show();
805 }
806
Olivier SOLDANO31b9aac2017-07-14 15:50:09 -0400807 ui->imNameLabel->setText(QString(tr("%1", "%1 is the contact username"))
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400808 .arg(name));
809
Olivier SOLDANO1f41a0d2017-08-18 16:30:20 -0400810 if ( !getSelectedAccount()->isIp2ip() && name != number ){
Olivier SOLDANO483f9682017-07-26 11:57:49 -0400811 ui->imIdLabel->show();
812 ui->imIdLabel->setText(QString(tr("%1", "%1 is the contact unique identifier"))
813 .arg(number));
814 } else {
815 ui->imIdLabel->hide();
816 }
817
Edric Milaretab12d022015-12-04 16:09:44 -0500818 auto cmVector = RecentModel::instance().getContactMethods(nodeIdx);
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400819 ui->contactMethodComboBox->setVisible(cmVector.size() > 1);
Edric Milaretab12d022015-12-04 16:09:44 -0500820 foreach (const ContactMethod* cm, cmVector) {
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400821 ui->contactMethodComboBox->addItem(cm->bestId());
Edric Milaretab12d022015-12-04 16:09:44 -0500822 }
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400823
Anthony Léonard041ad392017-07-14 16:44:09 -0400824 ui->sendContactRequestPageButton->setVisible(shouldDisplayInviteButton(*cmVector[0]));
825
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -0500826 ui->stackedWidget->setCurrentWidget(ui->messagingPage);
Olivier SOLDANO2742f552017-08-03 14:54:30 -0400827 ui->imMessageEdit->clear();
828 ui->imMessageEdit->setFocus();
Edric Milaret70ae8782016-04-18 16:10:44 -0400829 disconnect(imClickedConnection_);
830 imClickedConnection_ = connect(ui->listMessageView, &QListView::clicked, [this](const QModelIndex& index) {
831 auto urlList = index.data(static_cast<int>(Media::TextRecording::Role::LinkList)).value<QList<QUrl>>();
832 if (urlList.size() == 1)
833 QDesktopServices::openUrl(urlList.at(0));
834 else if (urlList.size()) {
835 //TODO Handle multiple url in one message
836 }
837 });
Edric Milaretab12d022015-12-04 16:09:44 -0500838}
839
840void
Edric Milaret6a785af2016-03-07 15:39:30 -0500841CallWidget::on_sendIMButton_clicked()
Edric Milaretab12d022015-12-04 16:09:44 -0500842{
Edric Milaret6a785af2016-03-07 15:39:30 -0500843 if (ui->imMessageEdit->text().trimmed().isEmpty())
Edric Milaretab12d022015-12-04 16:09:44 -0500844 return;
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400845
846 auto idx = RecentModel::instance().selectionModel()->currentIndex();
847 auto cmVec = RecentModel::instance().getContactMethods(idx);
848 if (cmVec.size() > 0) {
849 auto cm = cmVec[0];
850 if(!cm) {
851 qWarning() << "Contact Method not found";
852 return;
853 }
854 QMap<QString, QString> msg;
855 msg["text/plain"] = ui->imMessageEdit->text();
856 cm->sendOfflineTextMessage(msg);
857 ui->imMessageEdit->clear();
Edric Milaretab12d022015-12-04 16:09:44 -0500858 } else {
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400859 qWarning() << "No contact method found for messaging";
Edric Milaretab12d022015-12-04 16:09:44 -0500860 }
861}
862
863void
Edric Milaret6a785af2016-03-07 15:39:30 -0500864CallWidget::on_imMessageEdit_returnPressed()
Edric Milaretab12d022015-12-04 16:09:44 -0500865{
Edric Milaret6a785af2016-03-07 15:39:30 -0500866 on_sendIMButton_clicked();
Edric Milaretab12d022015-12-04 16:09:44 -0500867}
868
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400869void CallWidget::on_contactMethodComboBox_currentIndexChanged(int index)
Edric Milaretab12d022015-12-04 16:09:44 -0500870{
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400871 auto idx = RecentModel::instance().selectionModel()->currentIndex();
872 auto cmVec = RecentModel::instance().getContactMethods(idx);
873 ContactMethod* cm {};
874
875 if (index < cmVec.size() && index >= 0 ){
876 cm = cmVec[index];
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400877 }
878
879 if (cm){
Anthony Léonard041ad392017-07-14 16:44:09 -0400880 ui->sendContactRequestPageButton->setVisible(shouldDisplayInviteButton(*cm));
Olivier SOLDANO815d92f2017-07-13 14:05:36 -0400881 if (auto txtRecording = cm->textRecording()) {
882 ui->listMessageView->setModel(txtRecording->instantMessagingModel());
883 if (imConnection_)
884 disconnect(imConnection_);
885 imConnection_ = connect(txtRecording,
886 SIGNAL(messageInserted(QMap<QString,QString>,ContactMethod*,Media::Media::Direction)),
887 this,
888 SLOT(slotAccountMessageReceived(QMap<QString,QString>,ContactMethod*,Media::Media::Direction)));
889 auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0;
890 if (messagesPresent) {
891 ui->listMessageView->scrollToBottom();
892 txtRecording->setAllRead();
893 }
894 ui->listMessageView->setVisible(messagesPresent);
895 ui->noMessagesLabel->setVisible(!messagesPresent);
896 if (not messagesPresent) {
897 imVisibleConnection_ = connect(txtRecording->instantMessagingModel(),
898 &QAbstractItemModel::rowsInserted,
899 [this, txtRecording]() {
900 if (imVisibleConnection_)
901 disconnect(imVisibleConnection_);
902 auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0;
903 ui->listMessageView->setVisible(messagesPresent);
904 ui->noMessagesLabel->setVisible(!messagesPresent);
905 });
906 }
Edric Milaret4be72022016-01-19 10:24:13 -0500907 }
Edric Milaretab12d022015-12-04 16:09:44 -0500908 }
909}
910
911void
912CallWidget::slotAccountMessageReceived(const QMap<QString,QString> message,
913 ContactMethod* cm,
914 Media::Media::Direction dir)
915{
916 Q_UNUSED(message)
Edric Milaretab12d022015-12-04 16:09:44 -0500917 Q_UNUSED(dir)
918
919 ui->listMessageView->scrollToBottom();
Edric Milaret23fd3fa2016-01-15 15:37:35 -0500920 cm->textRecording()->setAllRead();
Edric Milaretab12d022015-12-04 16:09:44 -0500921}
Edric Milaretfa05d972016-01-13 16:22:04 -0500922
923void
Edric Milaret8001f6f2016-01-27 09:55:12 -0500924CallWidget::on_ringContactLineEdit_textChanged(const QString& text)
Edric Milaretfa05d972016-01-13 16:22:04 -0500925{
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400926 RecentModel::instance().peopleProxy()->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive, QRegExp::FixedString));
Edric Milaretfa05d972016-01-13 16:22:04 -0500927}
Edric Milareta0ebd062016-01-13 12:18:23 -0500928
Nicolas Jagerca850292016-01-17 14:11:10 -0500929void
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400930CallWidget::backToWelcomePage()
Edric Milareta0ebd062016-01-13 12:18:23 -0500931{
Edric Milaret6b68a482016-02-01 15:23:44 -0500932 RecentModel::instance().selectionModel()->clear();
Anthony Léonard7c630322017-05-03 15:51:14 -0400933 disconnect(imConnection_);
Nicolas Jagerca850292016-01-17 14:11:10 -0500934}
935
Olivier SOLDANO19193412017-06-06 12:03:36 -0400936void CallWidget::hideMiniSpinner()
937{
938 if(ui->spinnerLabel->isVisible()){
939 miniSpinner_->stop();
940 ui->spinnerLabel->hide();
941 }
942}
943
Nicolas Jagerca850292016-01-17 14:11:10 -0500944void
Olivier SOLDANO2bcdfd72017-05-02 14:37:19 -0400945CallWidget::on_imBackButton_clicked()
946{
947 backToWelcomePage();
948}
949
950void
Edric Milaret1e598592016-09-02 10:10:01 -0400951CallWidget::on_qrButton_toggled(bool checked)
952{
953 ui->qrLabel->setVisible(checked);
954}
955
956void
Edric Milaret4097d2f2016-02-09 14:41:50 -0500957CallWidget::on_shareButton_clicked()
958{
Edric Milaret1e598592016-09-02 10:10:01 -0400959 Utils::InvokeMailto(tr("Contact me on Ring"), tr("My RingId is : ") + ui->ringIdLabel->text());
Edric Milaret4097d2f2016-02-09 14:41:50 -0500960}
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400961
962void
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400963CallWidget::contactLineEdit_registeredNameFound(Account* account,NameDirectory::LookupStatus status,
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400964 const QString& address,const QString& name)
965{
966 URI uri = URI(ui->ringContactLineEdit->text());
967 QString username_to_lookup = uri.userinfo();
968
969 if (username_to_lookup.compare(name) != 0){
970 return;
971 }
972
973 switch (status)
974 {
975 case NameDirectory::LookupStatus::SUCCESS:
976 {
977 uri = URI("ring:" + address);
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400978 qDebug() << "contactLineEdit username to search: " << username_to_lookup;
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400979 qDebug() << uri;
980 searchContactLineEditEntry(uri);
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400981 auto cm = PhoneDirectoryModel::instance().getNumber(uri);
Olivier SOLDANO9657fd12017-03-27 16:06:53 -0400982 cm->setAccount(account);
Anthony Léonardaa90e1a2016-10-12 11:24:17 -0400983 break;
984 }
985 case NameDirectory::LookupStatus::INVALID_NAME:
986 {
987 qDebug() << "Invalid Ring username";
988 break;
989 }
990 case NameDirectory::LookupStatus::ERROR:
991 case NameDirectory::LookupStatus::NOT_FOUND:
992 default:
993 {
994 qDebug() << "Could not resolve Ring username";
995 break;
996 }
997 }
998}
Olivier SOLDANOdd878662017-03-27 16:00:06 -0400999
1000void
1001CallWidget::on_sendContactRequestPageButton_clicked()
1002{
1003 ui->sendContactRequestWidget->sendCR(RecentModel::instance().selectionModel()->currentIndex());
Olivier SOLDANO5d4a1ff2017-05-08 13:12:47 -04001004 // temporarly changed comportment waiting for message in payload implementation
1005 /*ui->sendContactRequestWidget->setup(RecentModel::instance().selectionModel()->currentIndex());
1006 slidePage(ui->sendContactRequestPage);*/
Olivier SOLDANOdd878662017-03-27 16:00:06 -04001007}
1008
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -04001009void
1010CallWidget::on_sendCRBackButton_clicked()
Olivier SOLDANOdd878662017-03-27 16:00:06 -04001011{
Anthony Léonardecfe7422017-05-04 14:14:37 -04001012 ui->stackedWidget->setCurrentWidget(ui->messagingPage);
Olivier SOLDANOdd878662017-03-27 16:00:06 -04001013}
Anthony Léonardd47179c2017-03-28 10:39:10 -04001014
1015void
1016CallWidget::on_pendingCRBackButton_clicked()
1017{
Olivier SOLDANO69361192017-04-20 10:32:05 -04001018 ui->contactRequestList->selectionModel()->clear();
Olivier SOLDANO8179e992017-07-19 15:59:19 -04001019 ui->stackedWidget->setCurrentWidget(ui->welcomePage);
Anthony Léonardd47179c2017-03-28 10:39:10 -04001020}
Anthony Léonard5cc76412017-04-21 16:52:25 -04001021
1022Account*
1023CallWidget::getSelectedAccount()
1024{
1025 auto idx = AvailableAccountModel::instance().selectionModel()->currentIndex();
1026 if (idx.isValid()) {
1027 auto ac = idx.data(static_cast<int>(Ring::Role::Object)).value<Account*>();
1028 return ac;
1029 }
1030 return nullptr;
1031}
Anthony Léonardecfe7422017-05-04 14:14:37 -04001032
Anthony Léonard041ad392017-07-14 16:44:09 -04001033bool
1034CallWidget::shouldDisplayInviteButton(ContactMethod &cm)
1035{
1036 // Displaying the button for a SIP ContactMethod is a nonsense
1037 if (cm.protocolHint() == URI::ProtocolHint::RING) {
1038 // If we know that the other accepted us
1039 if (cm.isConfirmed())
1040 return false;
1041
1042 // If not sure, we still check if the contact method is linked to a
1043 // Ring account or if the selected account is a RING one.
1044 if(auto linkedAccount = cm.account())
1045 return linkedAccount->protocol() == Account::Protocol::RING;
1046 else if (auto acc = getSelectedAccount())
1047 return acc->protocol() == Account::Protocol::RING;
1048 }
1049 return false;
1050}
1051
Olivier SOLDANO8179e992017-07-19 15:59:19 -04001052void CallWidget::on_contactRequestList_clicked(const QModelIndex &index)
Anthony Léonardecfe7422017-05-04 14:14:37 -04001053{
Olivier SOLDANO8179e992017-07-19 15:59:19 -04001054 RecentModel::instance().selectionModel()->clear();
1055 contactReqListCurrentChanged(index, QModelIndex());
Anthony Léonardecfe7422017-05-04 14:14:37 -04001056}