diff --git a/callwidget.cpp b/callwidget.cpp index 7051f26eb7da29de91a3408be4d1c2f922a8e60c..17b83abb3a899fdeff8ec9836273257447e72054 100644 --- a/callwidget.cpp +++ b/callwidget.cpp @@ -644,6 +644,7 @@ void CallWidget::slotShowCallView(const std::string& accountId, ui->callStackWidget->setCurrentWidget(ui->videoPage); ui->videoWidget->showChatviewIfToggled(); hideMiniSpinner(); + ui->videoWidget->pushRenderer(convInfo.callId); } void CallWidget::slotShowIncomingCallView(const std::string& accountId, diff --git a/contactdialog.ui b/contactdialog.ui deleted file mode 100644 index 4d4e80fe07ddf1e91f3c887aa23c6178f94ee6db..0000000000000000000000000000000000000000 --- a/contactdialog.ui +++ /dev/null @@ -1,94 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ContactDialog</class> - <widget class="QDialog" name="ContactDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>398</width> - <height>154</height> - </rect> - </property> - <property name="windowTitle"> - <string>Dialog</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QLabel" name="label"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>New Contact</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="nameLineEdit"> - <property name="placeholderText"> - <string>Enter a name...</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="numberLineEdit"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>ContactDialog</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel"> - <x>248</x> - <y>254</y> - </hint> - <hint type="destinationlabel"> - <x>157</x> - <y>274</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>ContactDialog</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel"> - <x>316</x> - <y>260</y> - </hint> - <hint type="destinationlabel"> - <x>286</x> - <y>274</y> - </hint> - </hints> - </connection> - </connections> -</ui> diff --git a/contactpicker.cpp b/contactpicker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70ccd7f57037e8fe7d374ec430fa0318db80ad90 --- /dev/null +++ b/contactpicker.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2015-2019 by Savoir-faire Linux * + * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* + * Author: Andreas Traczyk <andreas.traczyk@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 "contactpicker.h" +#include "ui_contactpicker.h" + +#include <QMouseEvent> + +#include "contactpickeritemdelegate.h" + +ContactPicker::ContactPicker(QWidget *parent) : + QDialog(parent), + ui(new Ui::ContactPicker), + type_(Type::CONFERENCE) +{ + ui->setupUi(this); + + setWindowFlags(Qt::CustomizeWindowHint); + setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint); + setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_TranslucentBackground, true); + + ui->smartList->setItemDelegate(new ContactPickerItemDelegate()); + + selectableProxyModel_ = new SelectableProxyModel(smartListModel_.get()); + ui->smartList->setModel(selectableProxyModel_); + +} + +ContactPicker::~ContactPicker() +{ + delete ui; +} + +void +ContactPicker::on_smartList_clicked(const QModelIndex &index) +{ + Q_UNUSED(index); + this->accept(); +} + +void +ContactPicker::accept() +{ + auto idx = ui->smartList->currentIndex(); + + if (idx.isValid()) { + // get current call id and peer uri + auto selectedConvUid = LRCInstance::getSelectedConvUid(); + auto convModel = LRCInstance::getCurrentConversationModel(); + auto conversation = Utils::getConversationFromUid(selectedConvUid, *convModel); + auto thisCallId = conversation->callId; + auto contactUri = idx.data(static_cast<int>(SmartListModel::Role::URI)).value<QString>().toStdString(); + + // let parent deal with this as this dialog will be destroyed + switch (type_) { + case Type::CONFERENCE: + emit contactWillJoinConference(thisCallId, contactUri); + break; + case Type::BLIND_TRANSFER: + case Type::ATTENDED_TRANSFER: + emit contactWillDoBlindTransfer(thisCallId, contactUri); + break; + default: + break; + } + } + + QDialog::accept(); +} + +void +ContactPicker::on_ringContactLineEdit_textChanged(const QString &arg1) +{ + selectableProxyModel_->setFilterRegExp(QRegExp(arg1, Qt::CaseInsensitive, QRegExp::FixedString)); +} + +void +ContactPicker::mousePressEvent(QMouseEvent *event) +{ + auto contactPickerWidgetRect = ui->contactPickerWidget->rect(); + if (!contactPickerWidgetRect.contains(event->pos())) { + //close(); + emit willClose(event); + } +} + +void +ContactPicker::setTitle(const std::string& title) +{ + ui->title->setText(QString::fromStdString(title)); +} + +void +ContactPicker::setType(const Type& type) +{ + type_ = type; + smartListModel_.reset(new SmartListModel(LRCInstance::getCurrAccId(), this, true)); + selectableProxyModel_->setSourceModel(smartListModel_.get()); + // adjust filter + switch (type_) { + case Type::CONFERENCE: + selectableProxyModel_->setPredicate( + [this](const QModelIndex& index, const QRegExp& regexp) { + bool match = regexp.indexIn(index.data(Qt::DisplayRole).toString()) != -1; + auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString(); + auto convModel = LRCInstance::getCurrentConversationModel(); + auto conversation = Utils::getConversationFromUid(convUid, *convModel); + if (conversation == convModel->allFilteredConversations().end()) { + return false; + } + auto callModel = LRCInstance::getCurrentCallModel(); + return match && + !(callModel->hasCall(conversation->callId) || callModel->hasCall(conversation->confId)) && + !index.parent().isValid(); + }); + break; + case Type::BLIND_TRANSFER: + case Type::ATTENDED_TRANSFER: + selectableProxyModel_->setPredicate( + [this](const QModelIndex& index, const QRegExp& regexp) { + return true; + }); + break; + default: + break; + } + selectableProxyModel_->invalidate(); +} diff --git a/contactpicker.h b/contactpicker.h new file mode 100644 index 0000000000000000000000000000000000000000..b9e9b4a10306ed75a1ea7f432422c59c2c255b85 --- /dev/null +++ b/contactpicker.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 2015-2019 by Savoir-faire Linux * + * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* + * Author: Andreas Traczyk <andreas.traczyk@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/>. * + **************************************************************************/ + +#pragma once + +#include <QDialog> +#include <QSortFilterProxyModel> + +#include "smartlistmodel.h" +#include "utils.h" +#include "lrcinstance.h" + +namespace Ui { +class ContactPicker; +} + +class SelectableProxyModel : public QSortFilterProxyModel +{ +public: + using FilterPredicate = std::function<bool(const QModelIndex&, const QRegExp&)>; + + explicit SelectableProxyModel(QAbstractItemModel* parent) : QSortFilterProxyModel(parent) { + setSourceModel(parent); + } + + void setPredicate(FilterPredicate filterPredicate) { + filterPredicate_ = filterPredicate; + } + + virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { + // Accept all contacts in conversation list filtered with account type, except those in a call + auto index = sourceModel()->index(source_row, 0, source_parent); + if (filterPredicate_) { + return filterPredicate_(index, filterRegExp()); + } + } + +private: + std::function<bool(const QModelIndex&, const QRegExp&)> filterPredicate_; + +}; + +class ContactPicker : public QDialog +{ + Q_OBJECT; + +public: + enum class Type { + CONFERENCE, + BLIND_TRANSFER, + ATTENDED_TRANSFER, + COUNT__ + }; + + explicit ContactPicker(QWidget *parent = 0); + ~ContactPicker(); + void setTitle(const std::string& title); + void setType(const Type& type); + +protected: + void mousePressEvent(QMouseEvent *event); + +signals: + void contactWillJoinConference(const std::string& callId, const std::string& contactUri); + void contactWillDoBlindTransfer(const std::string& callId, const std::string& contactUri); + void willClose(QMouseEvent *event); + +protected slots: + void accept(); + +private slots: + void on_smartList_clicked(const QModelIndex &index); + void on_ringContactLineEdit_textChanged(const QString &arg1); + +private: + Ui::ContactPicker *ui; + + std::unique_ptr<SmartListModel> smartListModel_; + SelectableProxyModel* selectableProxyModel_; + Type type_; + +}; diff --git a/contactpicker.ui b/contactpicker.ui new file mode 100644 index 0000000000000000000000000000000000000000..a943292a826e126fc8fef7d81b0354e4268ed542 --- /dev/null +++ b/contactpicker.ui @@ -0,0 +1,319 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ContactPicker</class> + <widget class="QDialog" name="ContactPicker"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>256</width> + <height>343</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string/> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QWidget" name="contactPickerWidget" native="true"> + <layout class="QGridLayout" name="gridLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>5</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>10</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="1" column="0"> + <widget class="QWidget" name="smartListOuterWidget" native="true"> + <property name="styleSheet"> + <string notr="true"/> + </property> + <layout class="QVBoxLayout" name="smartListOuterWidgetLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QWidget" name="searchBarLayoutWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>60</height> + </size> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="2" column="1"> + <spacer name="verticalSpacer_8"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>15</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="RingContactLineEdit" name="ringContactLineEdit"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>30</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>244</width> + <height>30</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>9</pointsize> + </font> + </property> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="toolTip"> + <string>Search contact text input</string> + </property> + <property name="maxLength"> + <number>100</number> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + <property name="placeholderText"> + <string>Search contacts</string> + </property> + <property name="clearButtonEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="1"> + <spacer name="verticalSpacer_7"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>5</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <widget class="SmartListView" name="smartList"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoScrollMargin"> + <number>16</number> + </property> + <property name="indentation"> + <number>0</number> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="itemsExpandable"> + <bool>false</bool> + </property> + <property name="expandsOnDoubleClick"> + <bool>false</bool> + </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + <attribute name="headerDefaultSectionSize"> + <number>0</number> + </attribute> + <attribute name="headerMinimumSectionSize"> + <number>0</number> + </attribute> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="topMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="title"> + <property name="font"> + <font> + <family>Microsoft Tai Le</family> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>Add contact to conference</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="spikeLabel"> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ressources.qrc">:/images/spike.png</pixmap> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>RingContactLineEdit</class> + <extends>QLineEdit</extends> + <header>ringcontactlineedit.h</header> + </customwidget> + <customwidget> + <class>SmartListView</class> + <extends>QTreeView</extends> + <header>smartlistview.h</header> + </customwidget> + </customwidgets> + <resources> + <include location="ressources.qrc"/> + </resources> + <connections/> +</ui> diff --git a/contactpickeritemdelegate.cpp b/contactpickeritemdelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..476ebf673d4702823904b9059d07cb4ee66d9122 --- /dev/null +++ b/contactpickeritemdelegate.cpp @@ -0,0 +1,191 @@ +/*************************************************************************** + * Copyright (C) 2019 by Savoir-faire Linux * + * Author: Andreas Traczyk <andreas.traczyk@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 "contactpickeritemdelegate.h" + +#include <QApplication> +#include <QPainter> +#include <QPixmap> + + // Client +#include "smartlistmodel.h" +#include "ringthemeutils.h" +#include "utils.h" +#include "lrcinstance.h" +#include "mainwindow.h" + +#include <ciso646> + +ContactPickerItemDelegate::ContactPickerItemDelegate(QObject* parent) + : QItemDelegate(parent) +{ +} + +void +ContactPickerItemDelegate::paint(QPainter* painter + , const QStyleOptionViewItem& option + , const QModelIndex& index +) const +{ + QStyleOptionViewItem opt(option); + painter->setRenderHint(QPainter::Antialiasing, true); + + // Not having focus removes dotted lines around the item + if (opt.state & QStyle::State_HasFocus) + opt.state ^= QStyle::State_HasFocus; + + bool selected = false; + if (option.state & QStyle::State_Selected) { + selected = true; + opt.state ^= QStyle::State_Selected; + } else { + highlightMap_[index.row()] = option.state & QStyle::State_MouseOver; + } + + QColor presenceBorderColor = Qt::white; + auto rowHighlight = highlightMap_.find(index.row()); + if (selected) { + painter->fillRect(option.rect, RingTheme::smartlistSelection_); + presenceBorderColor = RingTheme::smartlistSelection_; + } else if (rowHighlight != highlightMap_.end() && (*rowHighlight).second) { + painter->fillRect(option.rect, RingTheme::smartlistHighlight_); + presenceBorderColor = RingTheme::smartlistHighlight_; + } + + QRect &rect = opt.rect; + + // Avatar drawing + opt.decorationSize = QSize(sizeImage_, sizeImage_); + opt.decorationPosition = QStyleOptionViewItem::Left; + opt.decorationAlignment = Qt::AlignCenter; + + QRect rectAvatar(dx_ + rect.left(), rect.top() + dy_, sizeImage_, sizeImage_); + drawDecoration(painter, opt, rectAvatar, + QPixmap::fromImage(index.data(Qt::DecorationRole).value<QImage>()) + .scaled(sizeImage_, sizeImage_, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + QFont font(painter->font()); + + // Presence indicator + if (index.data(static_cast<int>(SmartListModel::Role::Presence)).value<bool>()) { + qreal radius = sizeImage_ / 6; + QPainterPath outerCircle, innerCircle; + QPointF center(rectAvatar.right() - radius + 2, (rectAvatar.bottom() - radius) + 1 + 2); + qreal outerCRadius = radius; + qreal innerCRadius = outerCRadius * 0.75; + outerCircle.addEllipse(center, outerCRadius, outerCRadius); + innerCircle.addEllipse(center, innerCRadius, innerCRadius); + painter->fillPath(outerCircle, presenceBorderColor); + painter->fillPath(innerCircle, RingTheme::presenceGreen_); + } + + using namespace lrc::api; + auto type = Utils::toEnum<profile::Type>( + index.data(static_cast<int>(SmartListModel::Role::ContactType)).value<int>() + ); + switch (type) { + case profile::Type::RING: + case profile::Type::TEMPORARY: + paintRingContactItem(painter, option, rect, index); + break; + case profile::Type::SIP: + break; + default: + paintRingContactItem(painter, option, rect, index); + break; + } +} + +QSize +ContactPickerItemDelegate::sizeHint(const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + Q_UNUSED(option); + Q_UNUSED(index); + return QSize(0, cellHeight_); +} + +void +ContactPickerItemDelegate::paintRingContactItem(QPainter* painter, + const QStyleOptionViewItem& option, + const QRect& rect, + const QModelIndex& index) const +{ + Q_UNUSED(option); + QFont font(painter->font()); + QPen pen(painter->pen()); + painter->setPen(pen); + + auto scalingRatio = MainWindow::instance().getCurrentScalingRatio(); + if (scalingRatio > 1.0) { + font.setPointSize(fontSize_ - 2); + } else { + font.setPointSize(fontSize_); + } + + auto leftMargin = dx_ + sizeImage_ + dx_; + auto rightMargin = dx_; + auto topMargin = 4; + auto bottomMargin = 8; + + QRect rectName1(rect.left() + leftMargin, + rect.top() + topMargin, + rect.width() - leftMargin * 2, + rect.height() / 2 - 2); + + QRect rectName2(rectName1.left(), + rectName1.top() + rectName1.height(), + rectName1.width(), + rectName1.height() - bottomMargin); + + QFontMetrics fontMetrics(font); + + // The name is displayed at the avatar's right + QString nameStr = index.data(static_cast<int>(SmartListModel::Role::DisplayName)).value<QString>(); + if (!nameStr.isNull()) { + font.setItalic(false); + font.setBold(false); + pen.setColor(RingTheme::lightBlack_); + painter->setPen(pen); + painter->setFont(font); + QString elidedNameStr = fontMetrics.elidedText(nameStr, Qt::ElideRight, rectName1.width()); + painter->drawText(rectName1, Qt::AlignVCenter | Qt::AlignLeft, elidedNameStr); + } + + // Display the ID under the name + QString idStr = index.data(static_cast<int>(SmartListModel::Role::DisplayID)).value<QString>(); + if (idStr != nameStr && !idStr.isNull()) { + font.setItalic(false); + font.setBold(false); + pen.setColor(RingTheme::grey_); + painter->setPen(pen); + painter->setFont(font); + idStr = fontMetrics.elidedText(idStr, Qt::ElideRight, rectName2.width()); + painter->drawText(rectName2, Qt::AlignVCenter | Qt::AlignLeft, idStr); + } +} + +void +ContactPickerItemDelegate::paintSIPContactItem(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + Q_UNUSED(painter); + Q_UNUSED(option); + Q_UNUSED(index); +} diff --git a/contactpickeritemdelegate.h b/contactpickeritemdelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..6cdc22522b86569841ba88674719803aa10ccb2b --- /dev/null +++ b/contactpickeritemdelegate.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2019 by Savoir-faire Linux * + * Author: Andreas Traczyk <andreas.traczyk@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/>. * + **************************************************************************/ + +#pragma once + +#include <QObject> +#include <QItemDelegate> + +class QPainter; + +class ContactPickerItemDelegate : public QItemDelegate +{ + Q_OBJECT +public: + explicit ContactPickerItemDelegate(QObject* parent = 0); + +protected: + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + +private: + void paintRingContactItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const; + void paintSIPContactItem(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + + constexpr static int sizeImage_ = 48; + constexpr static int cellHeight_ = 60; + constexpr static int dy_ = 6; + constexpr static int dx_ = 12; + constexpr static int fontSize_ = 11; + + mutable std::map<int, bool> highlightMap_; +}; diff --git a/images/icons/ic_call_transfer_white_24px.png b/images/icons/ic_call_transfer_white_24px.png index ed68542c24cf6e16df683c78feaa1e39af1939ac..a43dbb4be9d54a6be42b89d03488487b86ed2613 100644 Binary files a/images/icons/ic_call_transfer_white_24px.png and b/images/icons/ic_call_transfer_white_24px.png differ diff --git a/images/spike.png b/images/spike.png new file mode 100644 index 0000000000000000000000000000000000000000..1f0392703b91ddcc49f5fd47707ee5f82eb51021 Binary files /dev/null and b/images/spike.png differ diff --git a/images/spikeMask.png b/images/spikeMask.png deleted file mode 100644 index c0e42b65822d8b2548ffefcfd8538a4810c5ff96..0000000000000000000000000000000000000000 Binary files a/images/spikeMask.png and /dev/null differ diff --git a/jami-qt.pro b/jami-qt.pro index 4d7ea6aaf4c8b1ed0568c28c5bccb7ef7a66e2f5..2ef752fdcba60c95bc2781d14c7fe09572a93aa4 100644 --- a/jami-qt.pro +++ b/jami-qt.pro @@ -136,5 +136,6 @@ FORMS += ./aboutdialog.ui \ ./videooverlay.ui \ ./videoview.ui \ ./downloadbar.ui \ - ./updateconfirmdialog.ui + ./updateconfirmdialog.ui \ + ./contactpicker.ui RESOURCES += ressources.qrc diff --git a/ressources.qrc b/ressources.qrc index fe80f96e751daf2b3bbb7afba04b16b35beede75..9ca1fcb9cff94304430510f3e5c31fa3c6cdc44a 100644 --- a/ressources.qrc +++ b/ressources.qrc @@ -1,86 +1,87 @@ <RCC> - <qresource prefix="/"> - <file>images/icons/outline-info-24px.svg</file> - <file>images/icons/baseline-camera_alt-24px.svg</file> - <file>images/icons/baseline-refresh-24px.svg</file> - <file>images/jami_rolling_spinner.gif</file> - <file>images/icons/baseline-close-24px.svg</file> - <file>images/icons/baseline-done-24px.svg</file> - <file>images/icons/baseline-error_outline-24px.svg</file> - <file>stylesheet.css</file> - <file>images/ajax-loader.gif</file> - <file>images/default_avatar_overlay.svg</file> - <file>images/FontAwesome.otf</file> - <file>images/logo-jami-standard-coul.png</file> - <file>images/qrcode.png</file> - <file>images/jami.ico</file> - <file>images/jami.png</file> - <file>images/waiting.gif</file> - <file>images/icons/ic_add_black_18dp_2x.png</file> - <file>images/icons/ic_arrow_back_24px.svg</file> - <file>images/icons/ic_arrow_back_white_24dp.png</file> - <file>images/icons/ic_arrow_drop_down_black_9dp_2x.png</file> - <file>images/icons/ic_arrow_drop_down_black_18dp_2x.png</file> - <file>images/icons/ic_arrow_drop_up_black_9dp_2x.png</file> - <file>images/icons/ic_arrow_drop_up_black_18dp_2x.png</file> - <file>images/icons/ic_arrow_forward_white_48dp_2x.png</file> - <file>images/icons/ic_arrow_tab_next_black_9dp_2x.png</file> - <file>images/icons/ic_arrow_tab_previous_black_9dp_2x.png</file> - <file>images/icons/ic_block_24px.svg</file> - <file>images/icons/ic_call_transfer_white_24px.png</file> - <file>images/icons/ic_chat_black_24dp_2x.png</file> - <file>images/icons/ic_chat_white_24dp.png</file> - <file>images/icons/ic_check_white_18dp_2x.png</file> - <file>images/icons/ic_clear_24px.svg</file> - <file>images/icons/ic_close_white_24dp.png</file> - <file>images/icons/ic_content_copy_white_24dp.png</file> - <file>images/icons/ic_delete_black_18dp_2x.png</file> - <file>images/icons/ic_done_white_24dp.png</file> - <file>images/icons/ic_folder_black_18dp_2x.png</file> - <file>images/icons/ic_group_add_white_24dp.png</file> - <file>images/icons/ic_high_quality_white_24dp.png</file> - <file>images/icons/ic_mic_off_white_24dp.png</file> - <file>images/icons/ic_pause_white_24dp.png</file> - <file>images/icons/ic_pause_white_100px.png</file> - <file>images/icons/ic_person_add_black_24dp_2x.png</file> - <file>images/icons/ic_person_add_white_24dp.png</file> - <file>images/icons/ic_phone_24px.svg</file> - <file>images/icons/ic_photo_camera_white_24dp_2x.png</file> - <file>images/icons/ic_search_black_18dp_2x.png</file> - <file>images/icons/ic_send_24px.svg</file> - <file>images/icons/ic_send_white_24dp.png</file> - <file>images/icons/ic_settings_white_48dp_2x.png</file> - <file>images/icons/ic_share_black_48dp_2x.png</file> - <file>images/icons/ic_video_call_24px.svg</file> - <file>images/icons/ic_videocam_off_white_24dp.png</file> - <file>images/icons/ic_videocam_white.png</file> - <file>images/icons/ic_voicemail_white_24dp_2x.png</file> - <file>images/icons/round-add-24px.svg</file> - <file>images/icons/round-arrow_drop_down-24px.svg</file> - <file>images/icons/round-arrow_drop_up-24px.svg</file> - <file>images/icons/round-arrow_right-24px.svg</file> - <file>images/icons/round-close-24px.svg</file> - <file>images/icons/round-edit-24px.svg</file> - <file>images/icons/round-folder-24px.svg</file> - <file>images/icons/round-remove_circle-24px.svg</file> - <file>images/icons/round-settings-24px.svg</file> - <file>images/icons/round-undo-24px.svg</file> - <file>web/chatview.css</file> - <file>web/chatview.html</file> - <file>web/chatview.js</file> - <file>web/linkify.js</file> - <file>web/linkify-html.js</file> - <file>web/linkify-string.js</file> - <file>web/qwebchannel.js</file> - <file>images/icons/round-check_circle-24px.svg</file> - <file>images/icons/round-error-24px.svg</file> - <file>images/icons/round-save_alt-24px.svg</file> - <file>images/jami_eclipse_spinner.gif</file> - <file>images/icons/ic_hide_password.png</file> - <file>images/icons/ic_show_password.png</file> - <file>images/icons/baseline-desktop_windows-24px.svg</file> - <file>images/icons/baseline-people-24px.svg</file> - <file>images/icons/round-add_a_photo-24px.svg</file> - <file>images/icons/ic_mic_white_24dp.png</file> - </qresource> + <qresource prefix="/"> + <file>images/icons/outline-info-24px.svg</file> + <file>images/icons/baseline-camera_alt-24px.svg</file> + <file>images/icons/baseline-refresh-24px.svg</file> + <file>images/jami_rolling_spinner.gif</file> + <file>images/icons/baseline-close-24px.svg</file> + <file>images/icons/baseline-done-24px.svg</file> + <file>images/icons/baseline-error_outline-24px.svg</file> + <file>stylesheet.css</file> + <file>images/ajax-loader.gif</file> + <file>images/default_avatar_overlay.svg</file> + <file>images/FontAwesome.otf</file> + <file>images/logo-jami-standard-coul.png</file> + <file>images/qrcode.png</file> + <file>images/jami.ico</file> + <file>images/jami.png</file> + <file>images/spike.png</file> + <file>images/waiting.gif</file> + <file>images/icons/ic_add_black_18dp_2x.png</file> + <file>images/icons/ic_arrow_back_24px.svg</file> + <file>images/icons/ic_arrow_back_white_24dp.png</file> + <file>images/icons/ic_arrow_drop_down_black_9dp_2x.png</file> + <file>images/icons/ic_arrow_drop_down_black_18dp_2x.png</file> + <file>images/icons/ic_arrow_drop_up_black_9dp_2x.png</file> + <file>images/icons/ic_arrow_drop_up_black_18dp_2x.png</file> + <file>images/icons/ic_arrow_forward_white_48dp_2x.png</file> + <file>images/icons/ic_arrow_tab_next_black_9dp_2x.png</file> + <file>images/icons/ic_arrow_tab_previous_black_9dp_2x.png</file> + <file>images/icons/ic_block_24px.svg</file> + <file>images/icons/ic_call_transfer_white_24px.png</file> + <file>images/icons/ic_chat_black_24dp_2x.png</file> + <file>images/icons/ic_chat_white_24dp.png</file> + <file>images/icons/ic_check_white_18dp_2x.png</file> + <file>images/icons/ic_clear_24px.svg</file> + <file>images/icons/ic_close_white_24dp.png</file> + <file>images/icons/ic_content_copy_white_24dp.png</file> + <file>images/icons/ic_delete_black_18dp_2x.png</file> + <file>images/icons/ic_done_white_24dp.png</file> + <file>images/icons/ic_folder_black_18dp_2x.png</file> + <file>images/icons/ic_group_add_white_24dp.png</file> + <file>images/icons/ic_high_quality_white_24dp.png</file> + <file>images/icons/ic_mic_off_white_24dp.png</file> + <file>images/icons/ic_pause_white_24dp.png</file> + <file>images/icons/ic_pause_white_100px.png</file> + <file>images/icons/ic_person_add_black_24dp_2x.png</file> + <file>images/icons/ic_person_add_white_24dp.png</file> + <file>images/icons/ic_phone_24px.svg</file> + <file>images/icons/ic_photo_camera_white_24dp_2x.png</file> + <file>images/icons/ic_search_black_18dp_2x.png</file> + <file>images/icons/ic_send_24px.svg</file> + <file>images/icons/ic_send_white_24dp.png</file> + <file>images/icons/ic_settings_white_48dp_2x.png</file> + <file>images/icons/ic_share_black_48dp_2x.png</file> + <file>images/icons/ic_video_call_24px.svg</file> + <file>images/icons/ic_videocam_off_white_24dp.png</file> + <file>images/icons/ic_videocam_white.png</file> + <file>images/icons/ic_voicemail_white_24dp_2x.png</file> + <file>images/icons/round-add-24px.svg</file> + <file>images/icons/round-arrow_drop_down-24px.svg</file> + <file>images/icons/round-arrow_drop_up-24px.svg</file> + <file>images/icons/round-arrow_right-24px.svg</file> + <file>images/icons/round-close-24px.svg</file> + <file>images/icons/round-edit-24px.svg</file> + <file>images/icons/round-folder-24px.svg</file> + <file>images/icons/round-remove_circle-24px.svg</file> + <file>images/icons/round-settings-24px.svg</file> + <file>images/icons/round-undo-24px.svg</file> + <file>web/chatview.css</file> + <file>web/chatview.html</file> + <file>web/chatview.js</file> + <file>web/linkify.js</file> + <file>web/linkify-html.js</file> + <file>web/linkify-string.js</file> + <file>web/qwebchannel.js</file> + <file>images/icons/round-check_circle-24px.svg</file> + <file>images/icons/round-error-24px.svg</file> + <file>images/icons/round-save_alt-24px.svg</file> + <file>images/jami_eclipse_spinner.gif</file> + <file>images/icons/ic_hide_password.png</file> + <file>images/icons/ic_show_password.png</file> + <file>images/icons/baseline-desktop_windows-24px.svg</file> + <file>images/icons/baseline-people-24px.svg</file> + <file>images/icons/round-add_a_photo-24px.svg</file> + <file>images/icons/ic_mic_white_24dp.png</file> + </qresource> </RCC> diff --git a/ring-client-windows.vcxproj b/ring-client-windows.vcxproj index 21fbdf4f80a5841666e9c8b40cd49eb1abb15daa..3036e4e6d3a1a32ab1405bf8d4977c2850b9677c 100644 --- a/ring-client-windows.vcxproj +++ b/ring-client-windows.vcxproj @@ -230,6 +230,8 @@ <ClCompile Include="banneditemwidget.cpp" /> <ClCompile Include="bannedlistmodel.cpp" /> <ClCompile Include="animationhelpers.cpp" /> + <ClCompile Include="contactpicker.cpp" /> + <ClCompile Include="contactpickeritemdelegate.cpp" /> <ClCompile Include="currentaccountcombobox.cpp" /> <ClCompile Include="aboutdialog.cpp" /> <ClCompile Include="updatedownloaddialog.cpp" /> @@ -430,6 +432,14 @@ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)winsparkle\include;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> <IncludePath Condition="'$(Configuration)|$(Platform)'=='ReleaseCompile|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)winsparkle\include;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> </QtMoc> + <QtMoc Include="contactpicker.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)winsparkle\include;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='ReleaseCompile|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)winsparkle\include;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + </QtMoc> + <QtMoc Include="contactpickeritemdelegate.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)winsparkle\include;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='ReleaseCompile|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)winsparkle\include;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + </QtMoc> <ClInclude Include="pixbufmanipulator.h" /> <QtMoc Include="ringbutton.h"> </QtMoc> @@ -607,6 +617,7 @@ <SubType>Designer</SubType> </QtUic> <QtUic Include="updatedownloaddialog.ui" /> + <QtUic Include="contactpicker.ui" /> <QtUic Include="deleteaccountdialog.ui"> <SubType>Designer</SubType> </QtUic> @@ -701,4 +712,4 @@ <UserProperties UicDir=".\GeneratedFiles" RccDir=".\GeneratedFiles" Qt5Version_x0020_x64="$(DefaultQtVersion)" /> </VisualStudio> </ProjectExtensions> -</Project> \ No newline at end of file +</Project> diff --git a/ring-client-windows.vcxproj.filters b/ring-client-windows.vcxproj.filters index f46f7a864bf46f8abf127cfd8154a36ff9f0d80c..57f452773912e475142278c628f8de27be1d8474 100644 --- a/ring-client-windows.vcxproj.filters +++ b/ring-client-windows.vcxproj.filters @@ -207,6 +207,12 @@ <ClCompile Include="downloadmanager.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="contactpicker.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="contactpickeritemdelegate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <QtMoc Include="aboutdialog.h"> @@ -356,6 +362,12 @@ <QtMoc Include="runguard.h"> <Filter>Header Files</Filter> </QtMoc> + <QtMoc Include="contactpicker.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="contactpickeritemdelegate.h"> + <Filter>Header Files</Filter> + </QtMoc> </ItemGroup> <ItemGroup> <CustomBuild Include="debug\moc_predefs.h.cbt"> @@ -638,6 +650,9 @@ <QtUic Include="updatedownloaddialog.ui"> <Filter>Form Files</Filter> </QtUic> + <QtUic Include="contactpicker.ui"> + <Filter>Form Files</Filter> + </QtUic> </ItemGroup> <ItemGroup> <None Include="images\FontAwesome.otf"> diff --git a/smartlistmodel.cpp b/smartlistmodel.cpp index db26c0686e6ecfa126e8fc9560aef530bf517434..ef898db5eb437d96b0cd8fffbb5b4b772c2d379e 100644 --- a/smartlistmodel.cpp +++ b/smartlistmodel.cpp @@ -32,9 +32,10 @@ #include "utils.h" #include "lrcinstance.h" -SmartListModel::SmartListModel(const std::string& accId, QObject *parent) +SmartListModel::SmartListModel(const std::string& accId, QObject *parent, bool contactList) : QAbstractItemModel(parent), - accId_(accId) + accId_(accId), + contactList_(contactList) { } @@ -42,6 +43,10 @@ int SmartListModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { auto& accInfo = LRCInstance::accountModel().getAccountInfo(accId_); + if (contactList_) { + auto filterType = accInfo.profileInfo.type; + return accInfo.conversationModel->getFilteredConversations(filterType).size(); + } return accInfo.conversationModel->allFilteredConversations().size(); } return 0; // A valid QModelIndex returns 0 as no entry has sub-elements @@ -60,7 +65,15 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const } auto& accInfo = LRCInstance::accountModel().getAccountInfo(accId_); - const auto& item = accInfo.conversationModel->filteredConversation(index.row()); + + lrc::api::conversation::Info item; + if (contactList_) { + auto filterType = accInfo.profileInfo.type; + item = accInfo.conversationModel->getFilteredConversations(filterType).at(index.row()); + } else { + item = accInfo.conversationModel->filteredConversation(index.row()); + } + if (item.participants.size() > 0) { try { switch (role) { diff --git a/smartlistmodel.h b/smartlistmodel.h index 08e36a119085e0ba29b68a03ccfbdf7a95e7238a..6320af3173ce64763732087e29c41899556897ff 100644 --- a/smartlistmodel.h +++ b/smartlistmodel.h @@ -35,7 +35,6 @@ public: using ConversationInfo = lrc::api::conversation::Info; using ContactInfo = lrc::api::contact::Info; - enum Role { DisplayName = Qt::UserRole + 1, DisplayID, @@ -51,7 +50,7 @@ public: ContextMenuOpen }; - explicit SmartListModel(const std::string& accId, QObject *parent = 0); + explicit SmartListModel(const std::string& accId, QObject *parent = 0, bool contactList = false); // QAbstractItemModel int rowCount(const QModelIndex &parent = QModelIndex()) const override; @@ -68,4 +67,5 @@ public: private: std::string accId_; + bool contactList_; }; diff --git a/stylesheet.css b/stylesheet.css index 12ca44d9013117d8e8a57a73bb7cacc151173309..f80075cf8b62bfcda538acf597080847714d6a64 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -186,14 +186,14 @@ QPushButton#qualityButton, QPushButton#recButton { QPushButton#holdButton:hover, QPushButton#chatButton:hover, QPushButton#noMicButton:hover, QPushButton#noVideoButton:hover, QPushButton#transferButton:hover, QPushButton#addPersonButton:hover, QPushButton#joinButton:hover, QPushButton#qualityButton:hover, QPushButton#addToContactButton:hover, -QPushButton#recButton:hover{ +QPushButton#recButton:hover { background-color: rgba(0, 192, 213, 0.6); } QPushButton#holdButton:pressed, QPushButton#chatButton:pressed, QPushButton#noMicButton:pressed, QPushButton#noVideoButton:pressed, QPushButton#transferButton:pressed, QPushButton#addPersonButton:pressed, QPushButton#joinButton:pressed, QPushButton#qualityButton:pressed, QPushButton#addToContactButton:pressed, -QPushButton#recButton:pressed{ +QPushButton#recButton:pressed { background-color: rgba(0, 192, 213, 0.8); } @@ -722,4 +722,10 @@ SettingsWidget QListView { background-color: transparent; } -/* } SettingsWidget */ \ No newline at end of file +/* } SettingsWidget */ + +QWidget#contactPickerWidget { + border-radius: 10px; + border:solid 1px transparent; + background-color: white; +} diff --git a/videooverlay.cpp b/videooverlay.cpp index 656522a71c71e89dcfd74b150d6e3f7d2e28b3f5..c04965f934685093011935f5b4e916a869be7598 100644 --- a/videooverlay.cpp +++ b/videooverlay.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * + * Copyright (C) 2015-2019 by Savoir-faire Linux * * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> * * * @@ -21,25 +21,28 @@ #include "ui_videooverlay.h" #include <QTime> +#include <QMouseEvent> #include "lrcinstance.h" +#include "contactpicker.h" #include "utils.h" VideoOverlay::VideoOverlay(QWidget* parent) : QWidget(parent), ui(new Ui::VideoOverlay), - oneSecondTimer_(new QTimer(this)) + oneSecondTimer_(new QTimer(this)), + contactPicker_(new ContactPicker(this)) { ui->setupUi(this); + setAttribute(Qt::WA_NoSystemBackground); + ui->bottomButtons->setMouseTracking(true); ui->chatButton->setCheckable(true); ui->onHoldLabel->setVisible(false); - setAttribute(Qt::WA_NoSystemBackground); - ui->recButton->setVisible(false); } @@ -90,9 +93,14 @@ VideoOverlay::setVideoMuteVisibility(bool visible) bool VideoOverlay::shouldShowOverlay() { + if (!LRCInstance::getCurrentCallModel()->hasCall(callId_)) { + return false; + } auto callInfo = LRCInstance::getCurrentCallModel()->getCall(callId_); - auto callPaused = callInfo.status == lrc::api::call::Status::PAUSED; - return ui->bottomButtons->underMouse() || ui->topInfoBar->underMouse() || callPaused; + return ui->bottomButtons->underMouse() || + ui->topInfoBar->underMouse() || + (callInfo.status == lrc::api::call::Status::PAUSED) || + contactPicker_->isActiveWindow(); } void @@ -130,50 +138,40 @@ VideoOverlay::on_chatButton_toggled(bool checked) void VideoOverlay::on_holdButton_clicked() { - auto selectedConvUid = LRCInstance::getSelectedConvUid(); - auto conversation = Utils::getConversationFromUid(selectedConvUid, - *LRCInstance::getCurrentConversationModel()); - auto& callId = conversation->callId; auto callModel = LRCInstance::getCurrentCallModel(); - if (callModel->hasCall(callId)) { - auto onHold = callModel->getCall(callId).status == lrc::api::call::Status::PAUSED; + if (callModel->hasCall(callId_)) { + callModel->togglePause(callId_); + auto onHold = callModel->getCall(callId_).status == lrc::api::call::Status::PAUSED; ui->holdButton->setChecked(!onHold); ui->onHoldLabel->setVisible(!onHold); - callModel->togglePause(callId); } } void VideoOverlay::on_noMicButton_toggled(bool checked) { - bool btn_status = false; + Q_UNUSED(checked); auto callModel = LRCInstance::getCurrentCallModel(); if (callModel->hasCall(callId_)) { callModel->toggleMedia(callId_, lrc::api::NewCallModel::Media::AUDIO); - btn_status = callModel->getCall(callId_).audioMuted; } } void VideoOverlay::on_noVideoButton_toggled(bool checked) { - bool btn_status = false; + Q_UNUSED(checked); auto callModel = LRCInstance::getCurrentCallModel(); if (callModel->hasCall(callId_)) { callModel->toggleMedia(callId_, lrc::api::NewCallModel::Media::VIDEO); - btn_status = callModel->getCall(callId_).videoMuted; } } void VideoOverlay::on_recButton_clicked() { - auto selectedConvUid = LRCInstance::getSelectedConvUid(); - auto conversation = Utils::getConversationFromUid(selectedConvUid, - *LRCInstance::getCurrentConversationModel()); - auto& callId = conversation->callId; auto callModel = LRCInstance::getCurrentCallModel(); - if (callModel->hasCall(callId)) { - callModel->toggleAudioRecord(callId); + if (callModel->hasCall(callId_)) { + callModel->toggleAudioRecord(callId_); } } diff --git a/videooverlay.h b/videooverlay.h index c59475d2aeea229683ee97b45dbf426c33b3298f..28cef61a37fd0a4b014ff706e99b9c53c6886b3c 100644 --- a/videooverlay.h +++ b/videooverlay.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * + * Copyright (C) 2015-2019 by Savoir-faire Linux * * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* * * * This program is free software; you can redistribute it and/or modify * @@ -22,6 +22,8 @@ #include <QMenu> #include <QTimer> +class ContactPicker; + namespace Ui { class VideoOverlay; } @@ -56,6 +58,7 @@ private slots: private: Ui::VideoOverlay* ui; + ContactPicker* contactPicker_; bool dialogVisible_ = false; QTimer* oneSecondTimer_; std::string callId_; diff --git a/videooverlay.ui b/videooverlay.ui index 984bbad03b9318e2164b1cb639d1dda50e3dc5ba..34aaed7b57b00452ffbf29d3cd99458bb85bd815 100644 --- a/videooverlay.ui +++ b/videooverlay.ui @@ -106,6 +106,32 @@ </property> </widget> </item> + <item> + <widget class="QPushButton" name="transferCallButton"> + <property name="minimumSize"> + <size> + <width>36</width> + <height>36</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>36</width> + <height>36</height> + </size> + </property> + <property name="toolTip"> + <string>Transfer the call</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>images/icons/ic_call_transfer_white_24px.png</normaloff>images/icons/ic_call_transfer_white_24px.png</iconset> + </property> + </widget> + </item> <item> <widget class="QPushButton" name="chatButton"> <property name="minimumSize"> diff --git a/videoview.cpp b/videoview.cpp index 38d500176c14a38880d7f7bf61fdf2006d66761e..ad2aa533242d0ebab1f80ce2366c2a72bb30e511 100644 --- a/videoview.cpp +++ b/videoview.cpp @@ -351,6 +351,10 @@ VideoView::pushRenderer(const std::string& callId) { auto call = callModel->getCall(callId); + if (call.isAudioOnly) { + return; + } + this->overlay_->callStarted(callId); this->overlay_->setVideoMuteVisibility(!LRCInstance::getCurrentCallModel()->getCall(callId).isAudioOnly);