callwidget.cpp 24.6 KB
Newer Older
1
/***************************************************************************
2
 * Copyright (C) 2015-2016 by Savoir-faire Linux                           *
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>
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

31 32
#include "audio/settings.h"
#include "personmodel.h"
33
#include "person.h"
34
#include "fallbackpersoncollection.h"
35
#include "categorizedcontactmodel.h"
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"
54

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

63 64 65
    welcomePageAnim_ = new QPropertyAnimation(ui->welcomePage, "pos", this);
    messagingPageAnim_ = new QPropertyAnimation(ui->messagingPage, "pos", this);

66
    setActualCall(nullptr);
67 68
    videoRenderer_ = nullptr;

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

72 73 74 75
    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
76 77
    GlobalInstances::setPixmapManipulator(std::unique_ptr<Interfaces::PixbufManipulator>(new Interfaces::PixbufManipulator()));

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

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

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

93 94
        RecentModel::instance().peopleProxy()->setFilterRole(static_cast<int>(Ring::Role::Name));
        RecentModel::instance().peopleProxy()->setFilterCaseSensitivity(Qt::CaseInsensitive);
Edric Milaret's avatar
Edric Milaret committed
95
        ui->smartList->setModel(RecentModel::instance().peopleProxy());
96 97 98 99 100 101 102 103 104
        connect(ui->smartList->selectionModel(),
                SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
                this,
                SLOT(smartListSelectionChanged(QItemSelection,QItemSelection)));

        connect(ui->smartList, &QTreeView::entered, this, &CallWidget::on_entered);

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

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

Edric Milaret's avatar
Edric Milaret committed
109 110 111
        CategorizedContactModel::instance().setSortAlphabetical(false);
        CategorizedContactModel::instance().setUnreachableHidden(true);
        ui->contactView->setModel(&CategorizedContactModel::instance());
112 113
        contactDelegate_ = new ContactDelegate();
        ui->contactView->setItemDelegate(contactDelegate_);
114

Edric Milaret's avatar
Edric Milaret committed
115
        CategorizedHistoryModel::instance().
116
                addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
117

Edric Milaret's avatar
Edric Milaret committed
118 119
        ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance().model());
        CategorizedHistoryModel::SortedProxy::instance().model()->sort(0, Qt::DescendingOrder);
120
        ui->historyList->setHeaderHidden(true);
Edric Milaret's avatar
Edric Milaret committed
121 122
        historyDelegate_ = new HistoryDelegate();
        ui->historyList->setItemDelegate(historyDelegate_);
123

Edric Milaret's avatar
Edric Milaret committed
124 125
        connect(CategorizedHistoryModel::SortedProxy::instance().model(), &QSortFilterProxyModel::layoutChanged, [=]() {
            auto idx = CategorizedHistoryModel::SortedProxy::instance().model()->index(0,0);
126 127 128 129
            if (idx.isValid())
                ui->historyList->setExpanded(idx, true);
        });

130 131 132 133 134 135 136 137 138
        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*>();

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

157
        findRingAccount();
Edric Milaret's avatar
Edric Milaret committed
158 159
        setupOutOfCallIM();
        setupSmartListMenu();
160

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

163 164
    } catch (const std::exception& e) {
        qDebug() << "INIT ERROR" << e.what();
165 166 167 168 169 170
    }
}

CallWidget::~CallWidget()
{
    delete ui;
171
    delete menu_;
Edric Milaret's avatar
Edric Milaret committed
172
    delete contactDelegate_;
173
    delete imDelegate_;
174 175
    delete welcomePageAnim_;
    delete messagingPageAnim_;
176 177
}

Edric Milaret's avatar
Edric Milaret committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
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);
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226

    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
227 228 229 230 231 232 233 234 235 236 237 238
}

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;

239 240 241
        QVector<ContactMethod*> contactMethods = RecentModel::instance()
                .getContactMethods(RecentModel::instance().peopleProxy()->mapToSource(idx));
        if (contactMethods.isEmpty())
Edric Milaret's avatar
Edric Milaret committed
242
            return;
243 244 245 246 247 248 249

        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
250
            });
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
            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
278 279 280 281 282
        }
        menu.exec(globalPos);
    });
}

283
void
284 285 286 287 288 289
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
290
    auto a_count = AccountModel::instance().rowCount();
291 292
    auto found = false;
    for (int i = 0; i < a_count; ++i) {
Edric Milaret's avatar
Edric Milaret committed
293
        auto idx = AccountModel::instance().index(i, 0);
294 295 296
        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));
297
            ui->ringIdLabel->setText(username.toString());
298 299 300 301
            found = true;
            return;
        }
    }
302
    if (not found) {
303
        ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND"));
304 305 306 307 308 309
    }
}

void
CallWidget::findRingAccount()
{
310

Edric Milaret's avatar
Edric Milaret committed
311
    auto a_count = AccountModel::instance().rowCount();
312 313
    auto found = false;
    for (int i = 0; i < a_count; ++i) {
Edric Milaret's avatar
Edric Milaret committed
314
        auto idx = AccountModel::instance().index(i, 0);
315 316
        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
317
            auto account = AccountModel::instance().getAccountByModelIndex(idx);
318 319 320
            if (account->displayName().isEmpty())
                account->displayName() = account->alias();
            auto username = account->username();
321
            ui->ringIdLabel->setText(username);
322 323 324 325 326
            found = true;
            return;
        }
    }
    if (!found) {
327
        ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND"));
328 329 330
        WizardDialog *wizardDialog = new WizardDialog();
        wizardDialog->exec();
        delete wizardDialog;
331 332 333 334
    }
}

void
335
CallWidget::callIncoming(Call* call)
336
{
337 338 339 340
    if (!QApplication::focusWidget()) {
        GlobalSystemTray::instance()
                .showMessage("Ring",
                             QString(tr("Call incoming from %1")).arg(call->formattedName()));
341 342 343
        QApplication::alert(this, 5000);
    }

344
    if (!call->account()->isAutoAnswer()) {
345
        ui->callerIdLabel->setText(QString(tr("%1", "%1 is the name of the caller"))
Edric Milaret's avatar
Edric Milaret committed
346
                                   .arg(call->formattedName()));
347 348 349 350
        ui->callerPhoto->setPixmap(
                    QPixmap::fromImage(
                        GlobalInstances::pixmapManipulator()
                        .callPhoto(call, QSize(130,130)).value<QImage>()));
351
        ui->stackedWidget->setCurrentWidget(ui->callInvitePage);
352
    }
353
    setActualCall(call);
354 355 356 357 358 359
}

void
CallWidget::on_acceptButton_clicked()
{
    if (actualCall_ != nullptr)
360
        actualCall_->performAction(Call::Action::ACCEPT);
361
    ui->stackedWidget->setCurrentWidget(ui->videoPage);
362 363 364 365 366 367 368 369
}

void
CallWidget::on_refuseButton_clicked()
{
    if (actualCall_ == nullptr)
        return;
    actualCall_->performAction(Call::Action::REFUSE);
370
    setActualCall(nullptr);
371
    ui->stackedWidget->setCurrentWidget(ui->welcomePage);
372 373 374
}

void
375 376
CallWidget::addedCall(Call* call, Call* parent)
{
377 378
    Q_UNUSED(parent);
    if (call->direction() == Call::Direction::OUTGOING) {
379
        setActualCall(call);
380
        ui->stackedWidget->setCurrentWidget(ui->outboundCallPage);
381 382 383 384
    }
}

void
385 386
CallWidget::callStateChanged(Call* call, Call::State previousState)
{
387
    Q_UNUSED(previousState)
388 389
    if (call == nullptr
            || call != actualCall_)
390
        return;
391

392
    if (call->state() == Call::State::OVER) {
393
        setActualCall(nullptr);
394
        ui->instantMessagingWidget->setMediaText(nullptr);
395
        ui->stackedWidget->setCurrentWidget(ui->welcomePage);
396 397 398 399 400 401
        //TODO : Link this so that recentModel get selected correctly
        //        auto onHoldCall = callModel_->getActiveCalls().first();
        //        if (onHoldCall != nullptr && onHoldCall->state() == Call::State::HOLD) {
        //            setActualCall(onHoldCall);
        //            onHoldCall->performAction(Call::Action::HOLD);
        //        }
402
    } else if (call->state() == Call::State::CURRENT) {
403
        ui->instantMessagingWidget->setMediaText(actualCall_);
404
        ui->stackedWidget->setCurrentWidget(ui->videoPage);
405 406 407 408
    }
}

void
409 410
CallWidget::atExit()
{
411
}
412 413

void
414
CallWidget::on_contactView_doubleClicked(const QModelIndex& index)
415
{
416 417 418
    if (not index.isValid())
        return;

419
    ContactMethod* uri = nullptr;
420

421 422 423 424
    auto var = index.child(0,0).data(
                static_cast<int>(Person::Role::Object));
    if (var.isValid()) {
        Person* person = var.value<Person*>();
425 426 427 428 429 430 431 432 433 434
        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
435
            auto outCall = CallModel::instance().dialingCall(uri);
436
            outCall->performAction(Call::Action::ACCEPT);
437 438
            ui->mainTabMenu->setCurrentIndex(0);
            ui->smartList->setFocus();
439 440 441
        }
    }
}
442

443
void
444
CallWidget::on_historyList_doubleClicked(const QModelIndex& index)
445
{
446 447 448
    if (not index.isValid())
        return;

449 450
    auto number = index.data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
    if (number) {
Edric Milaret's avatar
Edric Milaret committed
451
        auto outCall = CallModel::instance().dialingCall(number);
452
        outCall->performAction(Call::Action::ACCEPT);
453 454
        ui->mainTabMenu->setCurrentIndex(0);
        ui->smartList->setFocus();
455 456
    }
}
457 458 459 460 461

void
CallWidget::setActualCall(Call* value)
{
    actualCall_ = value;
462 463
    CallModel::instance().selectCall(value);
    ui->videoWidget->pushRenderer(value);
464
}
465

466 467
void
CallWidget::on_cancelButton_clicked()
468 469 470 471
{
    if (actualCall_)
        actualCall_->performAction(Call::Action::REFUSE);
}
472 473

void
474
CallWidget::on_smartList_doubleClicked(const QModelIndex& index)
475
{
476 477 478
    ui->smartList->reset();
    ui->smartList->setCurrentIndex(index);

Edric Milaret's avatar
Edric Milaret committed
479 480
    auto realIndex = RecentModel::instance().peopleProxy()->mapToSource(index);
    if (RecentModel::instance().hasActiveCall(realIndex))
481 482 483 484 485 486 487 488 489 490
        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
491 492
    if (m && !RecentModel::instance().index(0, 0, realIndex).isValid()) {
        Call* c = CallModel::instance().dialingCall(m);
493 494 495 496 497
        c->performAction(Call::Action::ACCEPT);
    }
}

void
498
CallWidget::smartListSelectionChanged(const QItemSelection& newSel, const QItemSelection& oldSel) {
499 500 501

    Q_UNUSED(oldSel)

502 503 504 505 506
    if (newSel.indexes().empty())
    {
        ui->stackedWidget->setCurrentWidget(ui->welcomePage);
        return;
    }
507
    auto newIdx = newSel.indexes().first();
508
    if (not newIdx.isValid())
509 510
        return;

511 512 513
    auto nodeIdx = RecentModel::instance().peopleProxy()->mapToSource(newIdx);
    auto newIdxCall = RecentModel::instance().getActiveCall(nodeIdx);

Edric Milaret's avatar
Edric Milaret committed
514
    if (newIdxCall && newIdxCall != actualCall_) {
515
        setActualCall(newIdxCall);
516
        ui->stackedWidget->setCurrentWidget(ui->videoPage);
Edric Milaret's avatar
Edric Milaret committed
517 518
    } else if (newIdxCall == nullptr){
        setActualCall(nullptr);
519
        ui->instantMessagingWidget->hide();
520
        showIMOutOfCall();
521 522
    } else {
        setActualCall(nullptr);
523
        ui->instantMessagingWidget->hide();
524 525
        if (imConnection_)
            disconnect(imConnection_);
526 527 528 529 530 531 532
        ui->stackedWidget->setCurrentWidget(ui->welcomePage);
    }
}

void
CallWidget::placeCall()
{
533
    if (ui->ringContactLineEdit->text().isEmpty())
534
        return;
535
    Call* c = CallModel::instance().dialingCall(PhoneDirectoryModel::instance().getNumber(ui->ringContactLineEdit->text()));
536
    c->performAction(Call::Action::ACCEPT);
537
    ui->ringContactLineEdit->clear();
538 539 540
}

void
541
CallWidget::settingsButton_clicked()
542 543 544 545 546
{
    emit NavigationRequested(ScreenEnum::ConfScreen);
}

void
547
CallWidget::contactButton_clicked(bool checked)
548 549 550 551 552
{
    ui->mainTabMenu->setCurrentIndex(checked ? 1 : 0);
}

void
553
CallWidget::historicButton_clicked(bool checked)
554 555 556
{
    ui->mainTabMenu->setCurrentIndex(checked ? 2 : 0);
}
557 558 559 560

void
CallWidget::on_ringContactLineEdit_returnPressed()
{
561 562 563 564
    auto cm = PhoneDirectoryModel::instance().getNumber(ui->ringContactLineEdit->text());
    time_t currentTime;
    ::time(&currentTime);
    cm->setLastUsed(currentTime);
565
    ui->ringContactLineEdit->clear();
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
}

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

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

    on_smartList_doubleClicked(highLightedIndex_);
}
582 583

void
584
CallWidget::showIMOutOfCall()
585
{
586 587 588 589 590
    if (not highLightedIndex_.isValid())
        return;

    ui->smartList->selectionModel()->select(highLightedIndex_, QItemSelectionModel::ClearAndSelect);

591 592
    ui->contactMethodComboBox->clear();

593
    auto nodeIdx = RecentModel::instance().peopleProxy()->mapToSource(highLightedIndex_);
Edric Milaret's avatar
Edric Milaret committed
594 595
    ui->imNameLabel->setText(QString(tr("Conversation with %1", "%1 is the contact name"))
                             .arg(nodeIdx.data(static_cast<int>(Ring::Role::Name)).toString()));
596
    auto cmVector = RecentModel::instance().getContactMethods(nodeIdx);
Edric Milaret's avatar
Edric Milaret committed
597
    ui->contactMethodComboBox->setEnabled(cmVector.size() > 1);
598
    foreach (const ContactMethod* cm, cmVector) {
Edric Milaret's avatar
Edric Milaret committed
599
        ui->contactMethodComboBox->addItem(cm->uri());
600
    }
601
    slideToRight(messagingPageAnim_, ui->messagingPage);
602 603 604 605 606
}

void
CallWidget::on_sendButton_clicked()
{
Edric Milaret's avatar
Edric Milaret committed
607
    if (ui->messageEdit->text().trimmed().isEmpty())
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
        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());
632 633
        if (imConnection_)
            disconnect(imConnection_);
634
        imConnection_ = connect(txtRecording,
Edric Milaret's avatar
Edric Milaret committed
635 636 637
                                SIGNAL(messageInserted(QMap<QString,QString>,ContactMethod*,Media::Media::Direction)),
                                this,
                                SLOT(slotAccountMessageReceived(QMap<QString,QString>,ContactMethod*,Media::Media::Direction)));
638 639 640 641 642 643 644 645
        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
646 647 648 649 650 651
            imVisibleConnection_ = connect(txtRecording->instantMessagingModel(),
                                           &QAbstractItemModel::rowsInserted,
                                           [this, txtRecording]() {
                if (imVisibleConnection_)
                    disconnect(imVisibleConnection_);
                auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0;
652 653 654 655
                ui->listMessageView->setVisible(messagesPresent);
                ui->noMessagesLabel->setVisible(!messagesPresent);
            });
        }
656 657 658 659 660 661 662 663 664 665 666 667
    }
}

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

    ui->listMessageView->scrollToBottom();
668
    cm->textRecording()->setAllRead();
669
}
670 671

void
672
CallWidget::on_ringContactLineEdit_textChanged(const QString& text)
673 674 675
{
    RecentModel::instance().peopleProxy()->setFilterWildcard(text);
}
Edric Milaret's avatar
Edric Milaret committed
676

677 678
void
CallWidget::on_imBackButton_clicked()
Edric Milaret's avatar
Edric Milaret committed
679
{
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
    slideToLeft(welcomePageAnim_, ui->welcomePage);
}

void
CallWidget::slideToLeft(QPropertyAnimation* anim, QWidget* widget)
{
    ui->stackedWidget->setCurrentWidget(widget);
    anim->setDuration(animDuration_);
    anim->setStartValue(QPoint(widget->width(), widget->y()));
    anim->setEndValue(QPoint(widget->x(), widget->y()));
    anim->setEasingCurve(QEasingCurve::OutQuad);
    anim->start();
}

void
CallWidget::slideToRight(QPropertyAnimation* anim, QWidget* widget)
{
    ui->stackedWidget->setCurrentWidget(widget);
    anim->setDuration(animDuration_);
    anim->setStartValue(QPoint(-widget->width(), widget->y()));
    anim->setEndValue(QPoint(widget->x(), widget->y()));
    anim->setEasingCurve(QEasingCurve::OutQuad);
    anim->start();
Edric Milaret's avatar
Edric Milaret committed
703
}
704 705 706 707 708 709 710

void
CallWidget::on_copyCMButton_clicked()
{
    auto text = ui->contactMethodComboBox->currentText();
    QApplication::clipboard()->setText(text);
}