callwidget.cpp 25 KB
Newer Older
Edric Milaret's avatar
Edric Milaret committed
1
/***************************************************************************
Nicolas Jager's avatar
Nicolas Jager committed
2
 * Copyright (C) 2015-2016 by Savoir-faire Linux                           *
Edric Milaret's avatar
Edric Milaret committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify    *
 * it under the terms of the GNU General Public License as published by    *
 * the Free Software Foundation; either version 3 of the License, or       *
 * (at your option) any later version.                                     *
 *                                                                         *
 * This program is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License       *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
 **************************************************************************/

#include "callwidget.h"
#include "ui_callwidget.h"

22 23
#include <QClipboard>

24
#include <memory>
Edric Milaret's avatar
Edric Milaret committed
25

26 27 28
//ERROR is defined in windows.h
#include "utils.h"
#undef ERROR
Edric Milaret's avatar
Edric Milaret committed
29
#undef interface
30

Edric Milaret's avatar
Edric Milaret committed
31 32
#include "audio/settings.h"
#include "personmodel.h"
33
#include "person.h"
Edric Milaret's avatar
Edric Milaret committed
34
#include "fallbackpersoncollection.h"
35
#include "categorizedcontactmodel.h"
Edric Milaret's avatar
Edric Milaret committed
36
#include "localhistorycollection.h"
37 38
#include "media/text.h"
#include "media/recording.h"
39
#include "media/recordingmodel.h"
40
#include "recentmodel.h"
41
#include "contactmethod.h"
Edric Milaret's avatar
Edric Milaret committed
42
#include "globalinstances.h"
43

44
#include "wizarddialog.h"
Edric Milaret's avatar
Edric Milaret committed
45
#include "windowscontactbackend.h"
46
#include "contactpicker.h"
47
#include "contactmethodpicker.h"
48
#include "globalsystemtray.h"
49 50 51
#include "historydelegate.h"
#include "contactdelegate.h"
#include "smartlistdelegate.h"
52
#include "imdelegate.h"
Edric Milaret's avatar
Edric Milaret committed
53
#include "pixbufmanipulator.h"
Edric Milaret's avatar
Edric Milaret committed
54

55
CallWidget::CallWidget(QWidget* parent) :
56
    NavWidget(END ,parent),
Edric Milaret's avatar
Edric Milaret committed
57
    ui(new Ui::CallWidget),
58 59
    menu_(new QMenu()),
    imDelegate_(new ImDelegate())
Edric Milaret's avatar
Edric Milaret committed
60 61 62
{
    ui->setupUi(this);

63
    pageAnim_ = new QPropertyAnimation(ui->welcomePage, "pos", this);
Nicolas Jager's avatar
Nicolas Jager committed
64

65
    setActualCall(nullptr);
Edric Milaret's avatar
Edric Milaret committed
66 67
    videoRenderer_ = nullptr;

68 69 70
    connect(ui->videoWidget, SIGNAL(setChatVisibility(bool)),
            ui->instantMessagingWidget, SLOT(setVisible(bool)));

71 72 73 74
    QPixmap logo(":/images/logo-ring-standard-coul.png");
    ui->ringLogo->setPixmap(logo.scaledToHeight(100, Qt::SmoothTransformation));
    ui->ringLogo->setAlignment(Qt::AlignHCenter);

Edric Milaret's avatar
Edric Milaret committed
75 76
    GlobalInstances::setPixmapManipulator(std::unique_ptr<Interfaces::PixbufManipulator>(new Interfaces::PixbufManipulator()));

Edric Milaret's avatar
Edric Milaret committed
77
    try {
Edric Milaret's avatar
Edric Milaret committed
78
        callModel_ = &CallModel::instance();
Edric Milaret's avatar
Edric Milaret committed
79 80 81 82 83 84

        connect(callModel_, SIGNAL(incomingCall(Call*)),
                this, SLOT(callIncoming(Call*)));
        connect(callModel_, SIGNAL(callStateChanged(Call*, Call::State)),
                this, SLOT(callStateChanged(Call*, Call::State)));

Edric Milaret's avatar
Edric Milaret committed
85
        connect(&AccountModel::instance()
86 87 88 89
                , SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>))
                , this
                , SLOT(findRingAccount(QModelIndex, QModelIndex, QVector<int>)));

90 91
        RecentModel::instance().peopleProxy()->setFilterRole(static_cast<int>(Ring::Role::Name));
        RecentModel::instance().peopleProxy()->setFilterCaseSensitivity(Qt::CaseInsensitive);
Edric Milaret's avatar
Edric Milaret committed
92
        ui->smartList->setModel(RecentModel::instance().peopleProxy());
93 94 95

        smartListDelegate_ = new SmartListDelegate();
        ui->smartList->setSmartListItemDelegate(smartListDelegate_);
Edric Milaret's avatar
Edric Milaret committed
96

Edric Milaret's avatar
Edric Milaret committed
97
        PersonModel::instance().
98
                addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
Edric Milaret's avatar
Edric Milaret committed
99

Edric Milaret's avatar
Edric Milaret committed
100 101 102
        CategorizedContactModel::instance().setSortAlphabetical(false);
        CategorizedContactModel::instance().setUnreachableHidden(true);
        ui->contactView->setModel(&CategorizedContactModel::instance());
103 104
        contactDelegate_ = new ContactDelegate();
        ui->contactView->setItemDelegate(contactDelegate_);
105

Edric Milaret's avatar
Edric Milaret committed
106
        CategorizedHistoryModel::instance().
107
                addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
108

Edric Milaret's avatar
Edric Milaret committed
109 110
        ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance().model());
        CategorizedHistoryModel::SortedProxy::instance().model()->sort(0, Qt::DescendingOrder);
111
        ui->historyList->setHeaderHidden(true);
Edric Milaret's avatar
Edric Milaret committed
112 113
        historyDelegate_ = new HistoryDelegate();
        ui->historyList->setItemDelegate(historyDelegate_);
114

Edric Milaret's avatar
Edric Milaret committed
115 116
        connect(CategorizedHistoryModel::SortedProxy::instance().model(), &QSortFilterProxyModel::layoutChanged, [=]() {
            auto idx = CategorizedHistoryModel::SortedProxy::instance().model()->index(0,0);
117 118 119 120
            if (idx.isValid())
                ui->historyList->setExpanded(idx, true);
        });

121 122 123 124 125
        connect(ui->smartList, &QTreeView::entered, this, &CallWidget::on_entered);

        smartListDelegate_ = new SmartListDelegate();
        ui->smartList->setSmartListItemDelegate(smartListDelegate_);

126 127 128 129 130 131 132 133 134
        ui->historyList->setContextMenuPolicy(Qt::CustomContextMenu);
        connect(ui->historyList, &QListView::customContextMenuRequested, [=](const QPoint& pos){
            if (ui->historyList->currentIndex().parent().isValid()) {
                QPoint globalPos = ui->historyList->mapToGlobal(pos);
                QMenu menu;

                ContactMethod* contactMethod = ui->historyList->currentIndex()
                        .data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();

135
                auto copyAction = new QAction(tr("Copy number"), this);
136 137 138 139
                menu.addAction(copyAction);
                connect(copyAction, &QAction::triggered, [=]() {
                    QApplication::clipboard()->setText(contactMethod->uri());
                });
140
                if (not contactMethod->contact() || contactMethod->contact()->isPlaceHolder()) {
141
                    auto addExisting = new QAction(tr("Add to contact"), this);
142 143
                    menu.addAction(addExisting);
                    connect(addExisting, &QAction::triggered, [=]() {
144
                        ContactPicker contactPicker(contactMethod);
145
                        contactPicker.move(globalPos.x(), globalPos.y() - (contactPicker.height()/2));
146
                        contactPicker.exec();
147 148 149 150 151
                    });
                }
                menu.exec(globalPos);
            }
        });
Edric Milaret's avatar
Edric Milaret committed
152

Edric Milaret's avatar
Edric Milaret committed
153
        findRingAccount();
Edric Milaret's avatar
Edric Milaret committed
154 155
        setupOutOfCallIM();
        setupSmartListMenu();
Edric Milaret's avatar
Edric Milaret committed
156

157 158
        connect(ui->smartList, &SmartList::btnVideoClicked, this, &CallWidget::on_btnvideo_clicked);

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
        connect(RecentModel::instance().selectionModel(),
                SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
                this,
                SLOT(smartListSelectionChanged(QItemSelection,QItemSelection)));

        connect(RecentModel::instance().selectionModel(), &QItemSelectionModel::selectionChanged, [=](const QItemSelection &selected, const QItemSelection &deselected) {
            Q_UNUSED(deselected)
            if (selected.size()) {
                auto idx = selected.indexes().first();
                auto realIdx = RecentModel::instance().peopleProxy()->mapFromSource(idx);
                ui->smartList->selectionModel()->setCurrentIndex(realIdx, QItemSelectionModel::ClearAndSelect);
            } else
                ui->smartList->clearSelection();
        });

Edric Milaret's avatar
Edric Milaret committed
174 175
    } catch (const std::exception& e) {
        qDebug() << "INIT ERROR" << e.what();
Edric Milaret's avatar
Edric Milaret committed
176 177 178 179 180 181
    }
}

CallWidget::~CallWidget()
{
    delete ui;
182
    delete menu_;
Edric Milaret's avatar
Edric Milaret committed
183
    delete contactDelegate_;
184
    delete imDelegate_;
185 186
    delete pageAnim_;
    delete smartListDelegate_;
Edric Milaret's avatar
Edric Milaret committed
187 188
}

Edric Milaret's avatar
Edric Milaret committed
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
void
CallWidget::setupOutOfCallIM()
{
    ui->listMessageView->setItemDelegate(imDelegate_);
    ui->listMessageView->setContextMenuPolicy(Qt::ActionsContextMenu);

    auto copyAction = new QAction(tr("Copy"), this);
    ui->listMessageView->addAction(copyAction);
    connect(copyAction, &QAction::triggered, [=]() {
        auto idx = ui->listMessageView->currentIndex();
        if (idx.isValid()) {
            auto text = ui->listMessageView->model()->data(idx);
            QApplication::clipboard()->setText(text.value<QString>());
        }
    });
    auto displayDate = new QAction(tr("Display date"), this);
    displayDate->setCheckable(true);
    ui->listMessageView->addAction(displayDate);
    auto displayAuthor = new QAction(tr("Display author"), this);
    displayAuthor->setCheckable(true);
    ui->listMessageView->addAction(displayAuthor);
    auto lamdba = [=](){
        int opts = 0;
        displayAuthor->isChecked() ? opts |= ImDelegate::DisplayOptions::AUTHOR : opts;
        displayDate->isChecked() ? opts |= ImDelegate::DisplayOptions::DATE : opts;
        imDelegate_->setDisplayOptions(static_cast<ImDelegate::DisplayOptions>(opts));
    };
    connect(displayAuthor, &QAction::triggered, lamdba);
    connect(displayDate, &QAction::triggered, lamdba);
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237

    connect(&::Media::RecordingModel::instance(),
            SIGNAL(newTextMessage(::Media::TextRecording*, ContactMethod*)),
            this,
            SLOT(onIncomingMessage(::Media::TextRecording*, ContactMethod*)));
}

void
CallWidget::onIncomingMessage(::Media::TextRecording* t, ContactMethod* cm) {
    Q_UNUSED(cm)

    if (!QApplication::focusWidget()) {
        auto idx = t->instantTextMessagingModel()->
                index(t->instantTextMessagingModel()->rowCount()-1, 0);
        GlobalSystemTray::instance()
                .showMessage("Ring",
                             QString(tr("Message incoming from %1")).arg(
                                 idx.data((int)Media::TextRecording::Role::AuthorDisplayname).toString()));
        QApplication::alert(this, 5000);
    }
Edric Milaret's avatar
Edric Milaret committed
238 239 240 241 242 243 244 245 246 247 248 249
}

void
CallWidget::setupSmartListMenu() {
    ui->smartList->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->smartList, &QListView::customContextMenuRequested, [=](const QPoint& pos){
        auto idx = ui->smartList->currentIndex();
        if (not idx.isValid())
            return;
        QPoint globalPos = ui->smartList->mapToGlobal(pos);
        QMenu menu;

250 251 252
        QVector<ContactMethod*> contactMethods = RecentModel::instance()
                .getContactMethods(RecentModel::instance().peopleProxy()->mapToSource(idx));
        if (contactMethods.isEmpty())
Edric Milaret's avatar
Edric Milaret committed
253
            return;
254 255 256 257 258 259 260

        if (contactMethods.size() == 1) {
            auto contactMethod = contactMethods.at(0);
            auto copyAction = new QAction(tr("Copy number"), this);
            menu.addAction(copyAction);
            connect(copyAction, &QAction::triggered, [contactMethod]() {
                QApplication::clipboard()->setText(contactMethod->uri());
Edric Milaret's avatar
Edric Milaret committed
261
            });
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
            if (not contactMethod->contact() || contactMethod->contact()->isPlaceHolder()) {
                auto addExisting = new QAction(tr("Add to contact"), this);
                menu.addAction(addExisting);
                connect(addExisting, &QAction::triggered, [globalPos, contactMethod]() {
                    ContactPicker contactPicker(contactMethod);
                    contactPicker.move(globalPos.x(), globalPos.y() - (contactPicker.height()/2));
                    contactPicker.exec();
                });
            }
        }
        else {
           auto callMenu = menu.addMenu(tr("Call Number"));
           auto copyMenu = menu.addMenu(tr("Copy Number"));
           for (auto cM : contactMethods) {
               auto uri = cM->uri();
               auto copyAction = new QAction(tr("Copy %1").arg(uri), this);
               copyMenu->addAction(copyAction);
               connect(copyAction, &QAction::triggered, [uri]() {
                   QApplication::clipboard()->setText(uri);
               });
               auto callAction = new QAction(tr("Call %1").arg(uri), this);
               callMenu->addAction(callAction);
               connect(callAction, &QAction::triggered, [cM]() {
                   Call* c = CallModel::instance().dialingCall(cM);
                   c->performAction(Call::Action::ACCEPT);
               });
           }
Edric Milaret's avatar
Edric Milaret committed
289 290 291 292 293
        }
        menu.exec(globalPos);
    });
}

Edric Milaret's avatar
Edric Milaret committed
294
void
295 296 297 298 299 300
CallWidget::findRingAccount(QModelIndex idx1, QModelIndex idx2, QVector<int> vec)
{
    Q_UNUSED(idx1)
    Q_UNUSED(idx2)
    Q_UNUSED(vec)

Edric Milaret's avatar
Edric Milaret committed
301
    auto a_count = AccountModel::instance().rowCount();
302 303
    auto found = false;
    for (int i = 0; i < a_count; ++i) {
Edric Milaret's avatar
Edric Milaret committed
304
        auto idx = AccountModel::instance().index(i, 0);
305 306 307
        auto protocol = idx.data(static_cast<int>(Account::Role::Proto));
        if ((Account::Protocol)protocol.toUInt() == Account::Protocol::RING) {
            auto username = idx.data(static_cast<int>(Account::Role::Username));
308
            ui->ringIdLabel->setText(username.toString());
309 310 311 312
            found = true;
            return;
        }
    }
313
    if (not found) {
314
        ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND"));
315 316 317 318 319 320
    }
}

void
CallWidget::findRingAccount()
{
Edric Milaret's avatar
Edric Milaret committed
321
    auto a_count = AccountModel::instance().rowCount();
Edric Milaret's avatar
Edric Milaret committed
322 323
    auto found = false;
    for (int i = 0; i < a_count; ++i) {
Edric Milaret's avatar
Edric Milaret committed
324
        auto idx = AccountModel::instance().index(i, 0);
Edric Milaret's avatar
Edric Milaret committed
325 326
        auto protocol = idx.data(static_cast<int>(Account::Role::Proto));
        if ((Account::Protocol)protocol.toUInt() == Account::Protocol::RING) {
Edric Milaret's avatar
Edric Milaret committed
327
            auto account = AccountModel::instance().getAccountByModelIndex(idx);
328 329 330
            if (account->displayName().isEmpty())
                account->displayName() = account->alias();
            auto username = account->username();
331
            ui->ringIdLabel->setText(username);
Edric Milaret's avatar
Edric Milaret committed
332 333 334 335 336
            found = true;
            return;
        }
    }
    if (!found) {
337
        ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND"));
Edric Milaret's avatar
Edric Milaret committed
338
        auto wizardDialog = new WizardDialog();
339 340
        wizardDialog->exec();
        delete wizardDialog;
Edric Milaret's avatar
Edric Milaret committed
341 342 343 344
    }
}

void
345
CallWidget::callIncoming(Call* call)
Edric Milaret's avatar
Edric Milaret committed
346
{
347 348 349 350
    if (!QApplication::focusWidget()) {
        GlobalSystemTray::instance()
                .showMessage("Ring",
                             QString(tr("Call incoming from %1")).arg(call->formattedName()));
351 352 353
        QApplication::alert(this, 5000);
    }

354 355 356 357 358 359
    ui->callerIdLabel->setText(QString(tr("%1", "%1 is the name of the caller"))
                               .arg(call->formattedName()));
    ui->callerPhoto->setPixmap(
                QPixmap::fromImage(
                    GlobalInstances::pixmapManipulator()
                    .callPhoto(call, QSize(130,130)).value<QImage>()));
360
    setActualCall(call);
Edric Milaret's avatar
Edric Milaret committed
361 362 363 364 365 366
}

void
CallWidget::on_acceptButton_clicked()
{
    if (actualCall_ != nullptr)
367
        actualCall_->performAction(Call::Action::ACCEPT);
Edric Milaret's avatar
Edric Milaret committed
368 369 370 371 372 373 374 375
}

void
CallWidget::on_refuseButton_clicked()
{
    if (actualCall_ == nullptr)
        return;
    actualCall_->performAction(Call::Action::REFUSE);
376
    setActualCall(nullptr);
Edric Milaret's avatar
Edric Milaret committed
377 378 379
}

void
380 381
CallWidget::callStateChanged(Call* call, Call::State previousState)
{
Edric Milaret's avatar
Edric Milaret committed
382
    Q_UNUSED(previousState)
383 384
    if (call == nullptr
            || call != actualCall_)
385
        return;
386

387
    if (call->state() == Call::State::OVER) {
388
        setActualCall(nullptr);
389
        ui->instantMessagingWidget->setMediaText(nullptr);
390
        RecentModel::instance().selectionModel()->clear();
391
    } else if (call->state() == Call::State::CURRENT) {
392
        ui->instantMessagingWidget->setMediaText(actualCall_);
Edric Milaret's avatar
Edric Milaret committed
393
    }
394
    callStateToView(call);
Edric Milaret's avatar
Edric Milaret committed
395 396 397
}

void
398 399
CallWidget::atExit()
{
Edric Milaret's avatar
Edric Milaret committed
400
}
401 402

void
403
CallWidget::on_contactView_doubleClicked(const QModelIndex& index)
404
{
405 406 407
    if (not index.isValid())
        return;

408
    ContactMethod* uri = nullptr;
409

Edric Milaret's avatar
Edric Milaret committed
410 411 412 413
    auto var = index.child(0,0).data(
                static_cast<int>(Person::Role::Object));
    if (var.isValid()) {
        Person* person = var.value<Person*>();
414 415 416 417 418 419 420 421 422 423
        if (person->phoneNumbers().size() == 1) {
            uri = person->phoneNumbers().at(0);
        } else if (person->phoneNumbers().size() > 1) {
            ContactMethodPicker dlg(person->phoneNumbers());
            auto pos = QCursor::pos();
            dlg.move(pos.x(), pos.y());
            if (dlg.exec())
                uri = dlg.getSelected();
        }
        if (uri) {
Edric Milaret's avatar
Edric Milaret committed
424
            auto outCall = CallModel::instance().dialingCall(uri);
425
            outCall->performAction(Call::Action::ACCEPT);
426 427
            ui->mainTabMenu->setCurrentIndex(0);
            ui->smartList->setFocus();
428 429 430
        }
    }
}
431

432
void
433
CallWidget::on_historyList_doubleClicked(const QModelIndex& index)
434
{
Edric Milaret's avatar
Edric Milaret committed
435 436 437
    if (not index.isValid())
        return;

438 439
    auto number = index.data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
    if (number) {
Edric Milaret's avatar
Edric Milaret committed
440
        auto outCall = CallModel::instance().dialingCall(number);
441
        outCall->performAction(Call::Action::ACCEPT);
442 443
        ui->mainTabMenu->setCurrentIndex(0);
        ui->smartList->setFocus();
444 445
    }
}
446

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
void CallWidget::callStateToView(Call* value)
{
    if (value) {
        switch (value->state()) {
        case Call::State::INCOMING:
            if (not value->account()->isAutoAnswer())
                ui->stackedWidget->setCurrentWidget(ui->callInvitePage);
            else
                ui->stackedWidget->setCurrentWidget(ui->videoPage);
            break;
        case Call::State::CURRENT:
            ui->stackedWidget->setCurrentWidget(ui->videoPage);
            break;
        case Call::State::OVER:
            ui->stackedWidget->setCurrentWidget(ui->welcomePage);
            break;
        case Call::State::INITIALIZATION:
        case Call::State::CONNECTED:
        case Call::State::RINGING:
        case Call::State::ERROR:
            ui->stackedWidget->setCurrentWidget(ui->outboundCallPage);
            break;
        default:
            break;
        }
472 473
    } else
        ui->stackedWidget->setCurrentWidget(ui->welcomePage);
474 475
}

476 477 478 479
void
CallWidget::setActualCall(Call* value)
{
    actualCall_ = value;
Edric Milaret's avatar
Edric Milaret committed
480 481
    CallModel::instance().selectCall(value);
    ui->videoWidget->pushRenderer(value);
482 483

    callStateToView(value);
484
}
485

486 487
void
CallWidget::on_cancelButton_clicked()
488 489 490 491
{
    if (actualCall_)
        actualCall_->performAction(Call::Action::REFUSE);
}
492 493

void
494
CallWidget::on_smartList_doubleClicked(const QModelIndex& index)
495
{
496 497 498
    ui->smartList->reset();
    ui->smartList->setCurrentIndex(index);

Edric Milaret's avatar
Edric Milaret committed
499 500
    auto realIndex = RecentModel::instance().peopleProxy()->mapToSource(index);
    if (RecentModel::instance().hasActiveCall(realIndex))
501 502 503 504 505 506 507 508 509 510
        return;

    ContactMethod* m = nullptr;
    if (auto cm = realIndex.data((int)Call::Role::ContactMethod).value<ContactMethod*>()) {
        m = cm;
    } else {
        if (auto person =  realIndex.data((int)Person::Role::Object).value<Person*>()) {
            m = person->phoneNumbers().first();
        }
    }
Edric Milaret's avatar
Edric Milaret committed
511 512
    if (m && !RecentModel::instance().index(0, 0, realIndex).isValid()) {
        Call* c = CallModel::instance().dialingCall(m);
513
        c->performAction(Call::Action::ACCEPT);
514
        setActualCall(c);
515 516 517 518
    }
}

void
519
CallWidget::smartListSelectionChanged(const QItemSelection& newSel, const QItemSelection& oldSel) {
520 521 522

    Q_UNUSED(oldSel)

523
    if (newSel.indexes().empty())
524 525
        return ui->stackedWidget->setCurrentWidget(ui->welcomePage);

526
    auto newIdx = newSel.indexes().first();
Edric Milaret's avatar
Edric Milaret committed
527
    if (not newIdx.isValid())
528 529
        return;

530
    auto newIdxCall = RecentModel::instance().getActiveCall(newIdx);
Edric Milaret's avatar
Edric Milaret committed
531
    if (newIdxCall && newIdxCall != actualCall_) {
532
        setActualCall(newIdxCall);
Edric Milaret's avatar
Edric Milaret committed
533 534
    } else if (newIdxCall == nullptr){
        setActualCall(nullptr);
535
        ui->instantMessagingWidget->hide();
536
        showIMOutOfCall(newIdx);
537 538
    } else {
        setActualCall(nullptr);
539
        ui->instantMessagingWidget->hide();
540 541
        if (imConnection_)
            disconnect(imConnection_);
542 543 544 545 546 547 548
        ui->stackedWidget->setCurrentWidget(ui->welcomePage);
    }
}

void
CallWidget::placeCall()
{
549
    if (ui->ringContactLineEdit->text().isEmpty())
550
        return;
551
    Call* c = CallModel::instance().dialingCall(PhoneDirectoryModel::instance().getNumber(ui->ringContactLineEdit->text()));
552
    c->performAction(Call::Action::ACCEPT);
553
    ui->ringContactLineEdit->clear();
554 555 556
}

void
557
CallWidget::settingsButton_clicked()
558
{
559
    ui->smartList->reset();
560 561 562 563
    emit NavigationRequested(ScreenEnum::ConfScreen);
}

void
564
CallWidget::contactButton_clicked(bool checked)
565 566 567 568 569
{
    ui->mainTabMenu->setCurrentIndex(checked ? 1 : 0);
}

void
570
CallWidget::historicButton_clicked(bool checked)
571 572 573
{
    ui->mainTabMenu->setCurrentIndex(checked ? 2 : 0);
}
574 575 576 577

void
CallWidget::on_ringContactLineEdit_returnPressed()
{
578 579 580 581
    auto cm = PhoneDirectoryModel::instance().getNumber(ui->ringContactLineEdit->text());
    time_t currentTime;
    ::time(&currentTime);
    cm->setLastUsed(currentTime);
582
    ui->ringContactLineEdit->clear();
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
}

void
CallWidget::on_btnCall_clicked()
{
    placeCall();
}

void
CallWidget::on_btnvideo_clicked()
{
    if (not highLightedIndex_.isValid())
        return;

    on_smartList_doubleClicked(highLightedIndex_);
}
599 600

void
601
CallWidget::showIMOutOfCall(const QModelIndex& nodeIdx)
602 603 604
{
    ui->contactMethodComboBox->clear();

Edric Milaret's avatar
Edric Milaret committed
605 606
    ui->imNameLabel->setText(QString(tr("Conversation with %1", "%1 is the contact name"))
                             .arg(nodeIdx.data(static_cast<int>(Ring::Role::Name)).toString()));
607
    auto cmVector = RecentModel::instance().getContactMethods(nodeIdx);
Edric Milaret's avatar
Edric Milaret committed
608
    ui->contactMethodComboBox->setEnabled(cmVector.size() > 1);
609
    foreach (const ContactMethod* cm, cmVector) {
Edric Milaret's avatar
Edric Milaret committed
610
        ui->contactMethodComboBox->addItem(cm->uri());
611
    }
612
    slidePage(ui->messagingPage, true);
613 614 615 616 617
}

void
CallWidget::on_sendButton_clicked()
{
Edric Milaret's avatar
Edric Milaret committed
618
    if (ui->messageEdit->text().trimmed().isEmpty())
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
        return;
    auto number = ui->contactMethodComboBox->currentText();
    if (auto cm = PhoneDirectoryModel::instance().getNumber(number)) {
        QMap<QString, QString> msg;
        msg["text/plain"] = ui->messageEdit->text();
        cm->sendOfflineTextMessage(msg);
        ui->messageEdit->clear();
    } else {
        qWarning() << "Contact Method not found for " << number;
    }
}

void
CallWidget::on_messageEdit_returnPressed()
{
    on_sendButton_clicked();
}

void
CallWidget::on_contactMethodComboBox_currentIndexChanged(const QString& number)
{
    auto cm = PhoneDirectoryModel::instance().getNumber(number);
    if (auto txtRecording = cm->textRecording()) {
        ui->listMessageView->setModel(txtRecording->instantMessagingModel());
643 644
        if (imConnection_)
            disconnect(imConnection_);
645
        imConnection_ = connect(txtRecording,
Edric Milaret's avatar
Edric Milaret committed
646 647 648
                                SIGNAL(messageInserted(QMap<QString,QString>,ContactMethod*,Media::Media::Direction)),
                                this,
                                SLOT(slotAccountMessageReceived(QMap<QString,QString>,ContactMethod*,Media::Media::Direction)));
649 650 651 652 653 654 655 656
        auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0;
        if (messagesPresent) {
            ui->listMessageView->scrollToBottom();
            txtRecording->setAllRead();
        }
        ui->listMessageView->setVisible(messagesPresent);
        ui->noMessagesLabel->setVisible(!messagesPresent);
        if (not messagesPresent) {
Edric Milaret's avatar
Edric Milaret committed
657 658 659 660 661 662
            imVisibleConnection_ = connect(txtRecording->instantMessagingModel(),
                                           &QAbstractItemModel::rowsInserted,
                                           [this, txtRecording]() {
                if (imVisibleConnection_)
                    disconnect(imVisibleConnection_);
                auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0;
663 664 665 666
                ui->listMessageView->setVisible(messagesPresent);
                ui->noMessagesLabel->setVisible(!messagesPresent);
            });
        }
667 668 669 670 671 672 673 674 675 676 677 678
    }
}

void
CallWidget::slotAccountMessageReceived(const QMap<QString,QString> message,
                                       ContactMethod* cm,
                                       Media::Media::Direction dir)
{
    Q_UNUSED(message)
    Q_UNUSED(dir)

    ui->listMessageView->scrollToBottom();
679
    cm->textRecording()->setAllRead();
680
}
681 682

void
683
CallWidget::on_ringContactLineEdit_textChanged(const QString& text)
684 685 686
{
    RecentModel::instance().peopleProxy()->setFilterWildcard(text);
}
Edric Milaret's avatar
Edric Milaret committed
687

Nicolas Jager's avatar
Nicolas Jager committed
688 689
void
CallWidget::on_imBackButton_clicked()
Edric Milaret's avatar
Edric Milaret committed
690
{
691 692
    RecentModel::instance().selectionModel()->clear();
    slidePage(ui->welcomePage);
Nicolas Jager's avatar
Nicolas Jager committed
693 694 695
}

void
696
CallWidget::slidePage(QWidget* widget, bool toRight)
Nicolas Jager's avatar
Nicolas Jager committed
697
{
698
    short dir = (toRight ? -1 : 1);
Nicolas Jager's avatar
Nicolas Jager committed
699
    ui->stackedWidget->setCurrentWidget(widget);
700 701 702 703 704 705
    pageAnim_->setTargetObject(widget);
    pageAnim_->setDuration(animDuration_);
    pageAnim_->setStartValue(QPoint(widget->width() * dir, widget->y()));
    pageAnim_->setEndValue(QPoint(widget->x(), widget->y()));
    pageAnim_->setEasingCurve(QEasingCurve::OutQuad);
    pageAnim_->start();
Nicolas Jager's avatar
Nicolas Jager committed
706 707 708
}

void
709
CallWidget::on_smartList_clicked(const QModelIndex& index)
Nicolas Jager's avatar
Nicolas Jager committed
710
{
711 712 713
    RecentModel::instance().selectionModel()->setCurrentIndex(
                RecentModel::instance().peopleProxy()->mapToSource(index),
                QItemSelectionModel::ClearAndSelect);
Edric Milaret's avatar
Edric Milaret committed
714
}
715 716 717 718 719 720 721

void
CallWidget::on_copyCMButton_clicked()
{
    auto text = ui->contactMethodComboBox->currentText();
    QApplication::clipboard()->setText(text);
}
Edric Milaret's avatar
Edric Milaret committed
722 723 724 725 726 727

void
CallWidget::on_shareButton_clicked()
{
   Utils::InvokeMailto("Contact me on Ring", QStringLiteral("My RingId is : ") + ui->ringIdLabel->text());
}