callwidget.cpp 24.8 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
    pageAnim_ = new QPropertyAnimation(ui->welcomePage, "pos", this);
64

65
    setActualCall(nullptr);
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()));

77
    try {
Edric Milaret's avatar
Edric Milaret committed
78
        callModel_ = &CallModel::instance();
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_);
96

Edric Milaret's avatar
Edric Milaret committed
97
        PersonModel::instance().
98
                addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
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);
            }
        });
152

153
        findRingAccount();
Edric Milaret's avatar
Edric Milaret committed
154 155
        setupOutOfCallIM();
        setupSmartListMenu();
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();
        });

174 175
    } catch (const std::exception& e) {
        qDebug() << "INIT ERROR" << e.what();
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_;
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);
    });
}

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();
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);
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);
332 333 334 335 336
            found = true;
            return;
        }
    }
    if (!found) {
337
        ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND"));
338 339 340
        WizardDialog *wizardDialog = new WizardDialog();
        wizardDialog->exec();
        delete wizardDialog;
341 342 343 344
    }
}

void
345
CallWidget::callIncoming(Call* call)
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);
361 362 363 364 365 366
}

void
CallWidget::on_acceptButton_clicked()
{
    if (actualCall_ != nullptr)
367
        actualCall_->performAction(Call::Action::ACCEPT);
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);
377 378 379
}

void
380 381
CallWidget::callStateChanged(Call* call, Call::State previousState)
{
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_);
393
    }
394
    callStateToView(call);
395 396 397
}

void
398 399
CallWidget::atExit()
{
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

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
{
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 472 473 474
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;
        }
    }
}

475 476 477 478
void
CallWidget::setActualCall(Call* value)
{
    actualCall_ = value;
479 480
    CallModel::instance().selectCall(value);
    ui->videoWidget->pushRenderer(value);
481 482

    callStateToView(value);
483
}
484

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

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

Edric Milaret's avatar
Edric Milaret committed
498 499
    auto realIndex = RecentModel::instance().peopleProxy()->mapToSource(index);
    if (RecentModel::instance().hasActiveCall(realIndex))
500 501 502 503 504 505 506 507 508 509
        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
510 511
    if (m && !RecentModel::instance().index(0, 0, realIndex).isValid()) {
        Call* c = CallModel::instance().dialingCall(m);
512
        c->performAction(Call::Action::ACCEPT);
513
        setActualCall(c);
514 515 516 517
    }
}

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

    Q_UNUSED(oldSel)

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

525
    auto newIdx = newSel.indexes().first();
526
    if (not newIdx.isValid())
527 528
        return;

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

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

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

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

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

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

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

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

    on_smartList_doubleClicked(highLightedIndex_);
}
598 599

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

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

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

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

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

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

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

void
695
CallWidget::slidePage(QWidget* widget, bool toRight)
696
{
697
    short dir = (toRight ? -1 : 1);
698
    ui->stackedWidget->setCurrentWidget(widget);
699 700 701 702 703 704
    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();
705 706 707
}

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

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