From b8b13ba87f2d395464ff9fc38d72ac378e044cad Mon Sep 17 00:00:00 2001 From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> Date: Tue, 21 Aug 2018 16:30:16 -0400 Subject: [PATCH] refactor: implement new lrc api - use new lrc models for - smartlist - conversation view - account selector Change-Id: I0a009d4e9be6f84100f49ba176d853e05364c351 --- RingWinClient.pro | 43 +- accountitemdelegate.cpp | 141 ++ smartlistdelegate.h => accountitemdelegate.h | 21 +- accountlistmodel.cpp | 105 ++ accountlistmodel.h | 51 + callutilsdialog.cpp | 10 +- callutilsdialog.h | 4 +- callwidget.cpp | 1261 +++++++++-------- callwidget.h | 126 +- callwidget.ui | 301 ++-- combar.ui | 95 -- configurationwidget.cpp | 3 - contactmethodpicker.cpp | 57 - contactmethodpicker.h | 49 - contactmethodpicker.ui | 39 - contactrequestitemdelegate.cpp | 103 -- contactrequestlistwidget.cpp | 128 -- contactrequestlistwidget.h | 44 - conversationitemdelegate.cpp | 307 ++++ ...emdelegate.h => conversationitemdelegate.h | 30 +- conversationsfilterwidget.cpp | 66 + ...estwidget.h => conversationsfilterwidget.h | 49 +- currentaccountwidget.cpp | 106 +- currentaccountwidget.h | 10 +- currentaccountwidget.ui | 63 +- deletecontactdialog.cpp | 63 - deletecontactdialog.ui | 181 --- images/icons/ic_block-24px.svg | 1 + images/icons/ic_clear-24px.svg | 1 + imdelegate.cpp | 156 +- imdelegate.h | 13 +- instantmessagingwidget.cpp | 24 +- ...contactdialog.h => invitebuttonswidget.cpp | 53 +- combar.h => invitebuttonswidget.h | 20 +- invitebuttonswidget.ui | 175 +++ lrcinstance.h | 42 +- main.cpp | 1 - mainwindow.cpp | 16 +- messagemodel.cpp | 123 ++ messagemodel.h | 61 + photoboothwidget.cpp | 6 - pixbufmanipulator.cpp | 102 +- pixbufmanipulator.h | 4 +- quickactcontactrequestwidget.cpp | 56 - ressources.qrc | 2 + ring-client-windows.pro | 287 ---- ring-client-windows.sln | 15 +- ring-client-windows.vcxproj | 183 +-- ring-client-windows.vcxproj.filters | 129 +- ringthemeutils.h | 4 +- settingskey.h | 3 +- smartlist.cpp | 108 -- smartlistdelegate.cpp | 219 --- smartlistmodel.cpp | 145 ++ smartlistmodel.h | 70 + smartlistselectorbuttonnotifier.cpp | 93 ++ ...r.cpp => smartlistselectorbuttonnotifier.h | 33 +- smartlistview.cpp | 156 ++ smartlist.h => smartlistview.h | 23 +- stylesheet.css | 49 +- utils.cpp | 174 ++- utils.h | 59 +- videooverlay.cpp | 142 +- videooverlay.h | 4 +- videooverlay.ui | 1057 +++++++------- videoview.cpp | 62 +- videoview.h | 3 +- wizarddialog.cpp | 156 +- wizarddialog.h | 11 +- 69 files changed, 3851 insertions(+), 3646 deletions(-) create mode 100644 accountitemdelegate.cpp rename smartlistdelegate.h => accountitemdelegate.h (78%) create mode 100644 accountlistmodel.cpp create mode 100644 accountlistmodel.h delete mode 100644 combar.ui delete mode 100644 contactmethodpicker.cpp delete mode 100644 contactmethodpicker.h delete mode 100644 contactmethodpicker.ui delete mode 100644 contactrequestitemdelegate.cpp delete mode 100644 contactrequestlistwidget.cpp delete mode 100644 contactrequestlistwidget.h create mode 100644 conversationitemdelegate.cpp rename contactrequestitemdelegate.h => conversationitemdelegate.h (61%) create mode 100644 conversationsfilterwidget.cpp rename quickactcontactrequestwidget.h => conversationsfilterwidget.h (62%) delete mode 100644 deletecontactdialog.cpp delete mode 100644 deletecontactdialog.ui create mode 100644 images/icons/ic_block-24px.svg create mode 100644 images/icons/ic_clear-24px.svg rename deletecontactdialog.h => invitebuttonswidget.cpp (59%) rename combar.h => invitebuttonswidget.h (73%) create mode 100644 invitebuttonswidget.ui create mode 100644 messagemodel.cpp create mode 100644 messagemodel.h delete mode 100644 quickactcontactrequestwidget.cpp delete mode 100644 ring-client-windows.pro delete mode 100644 smartlist.cpp delete mode 100644 smartlistdelegate.cpp create mode 100644 smartlistmodel.cpp create mode 100644 smartlistmodel.h create mode 100644 smartlistselectorbuttonnotifier.cpp rename combar.cpp => smartlistselectorbuttonnotifier.h (66%) create mode 100644 smartlistview.cpp rename smartlist.h => smartlistview.h (75%) diff --git a/RingWinClient.pro b/RingWinClient.pro index 06c6805..af7e37b 100644 --- a/RingWinClient.pro +++ b/RingWinClient.pro @@ -41,7 +41,7 @@ isEmpty(QMAKE_LRELEASE) { } SOURCES += main.cpp\ - mainwindow.cpp \ + mainwindow.cpp \ callwidget.cpp \ configurationwidget.cpp \ navwidget.cpp \ @@ -59,13 +59,11 @@ SOURCES += main.cpp\ videooverlay.cpp \ imdelegate.cpp \ contactpicker.cpp \ - contactmethodpicker.cpp \ globalsystemtray.cpp \ - smartlistdelegate.cpp \ + conversationitemdelegate.cpp \ + conversationsfilterwidget.cpp \ callutilsdialog.cpp \ - combar.cpp \ idlabel.cpp \ - smartlist.cpp \ ringcontactlineedit.cpp \ pixbufmanipulator.cpp \ qualitydialog.cpp \ @@ -74,13 +72,16 @@ SOURCES += main.cpp\ sendcontactrequestwidget.cpp \ currentaccountwidget.cpp \ contactrequestwidget.cpp \ - contactrequestitemdelegate.cpp \ - quickactcontactrequestwidget.cpp \ - contactrequestlistwidget.cpp \ + smartlistselectorbuttonnotifier.cpp \ deleteaccountdialog.cpp \ bannedcontactswidget.cpp \ photoboothwidget.cpp \ - deletecontactdialog.cpp + smartlistmodel.cpp \ + smartlistview.cpp \ + accountitemdelegate.cpp \ + accountlistmodel.cpp \ + messagemodel.cpp \ + invitebuttonswidget.cpp HEADERS += mainwindow.h \ callwidget.h \ @@ -100,14 +101,12 @@ HEADERS += mainwindow.h \ videooverlay.h \ imdelegate.h \ contactpicker.h \ - contactmethodpicker.h \ settingskey.h \ globalsystemtray.h \ - smartlistdelegate.h \ + conversationitemdelegate.h \ + conversationsfilterwidget.h \ callutilsdialog.h \ - combar.h \ idlabel.h \ - smartlist.h \ ringcontactlineedit.h \ pixbufmanipulator.h \ qualitydialog.h \ @@ -117,14 +116,17 @@ HEADERS += mainwindow.h \ sendcontactrequestwidget.h \ currentaccountwidget.h \ contactrequestwidget.h \ - contactrequestitemdelegate.h \ - quickactcontactrequestwidget.h \ - contactrequestlistwidget.h \ + smartlistselectorbuttonnotifier.h \ deleteaccountdialog.h \ bannedcontactswidget.h \ photoboothwidget.h \ - deletecontactdialog.h \ - lrcinstance.h + lrcinstance.h \ + smartlistmodel.h \ + smartlistview.h \ + accountitemdelegate.h \ + accountlistmodel.h \ + messagemodel.h \ + invitebuttonswidget.h contains(DEFINES, URI_PROTOCOL) { HEADERS += shmclient.h @@ -141,20 +143,17 @@ FORMS += mainwindow.ui \ videoview.ui \ videooverlay.ui \ contactpicker.ui \ - contactmethodpicker.ui \ callutilsdialog.ui \ - combar.ui \ qualitydialog.ui \ ringbutton.ui \ photoboothdialog.ui \ sendcontactrequestwidget.ui \ currentaccountwidget.ui \ contactrequestwidget.ui \ - quickactcontactrequestwidget.ui \ deleteaccountdialog.ui \ bannedcontactswidget.ui \ photoboothwidget.ui \ - deletecontactdialog.ui + invitebuttonswidget.ui win32: LIBS += -lole32 -luuid -lshlwapi -lgdi32 LIBS += -lqrencode diff --git a/accountitemdelegate.cpp b/accountitemdelegate.cpp new file mode 100644 index 0000000..346d750 --- /dev/null +++ b/accountitemdelegate.cpp @@ -0,0 +1,141 @@ +/*************************************************************************** + * Copyright (C) 2018 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 "accountitemdelegate.h" + +#include <QApplication> +#include <QTextDocument> +#include <QPixmap> + +#include "utils.h" +#include "accountlistmodel.h" +#include "ringthemeutils.h" + +#undef REGISTERED + +AccountItemDelegate::AccountItemDelegate(QObject *parent) + : QItemDelegate(parent) +{ +} + +void +AccountItemDelegate::paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QStyleOptionViewItem opt(option); + painter->setRenderHint(QPainter::Antialiasing); + + // Not having focus removes dotted lines around the item + if (opt.state & QStyle::State_HasFocus) { + opt.state.setFlag(QStyle::State_HasFocus, false); + } + + // First, we draw the control itself + QStyle* style = opt.widget ? opt.widget->style() : QApplication::style(); + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); + + bool selected = false; + if (option.state & QStyle::State_Selected) { + selected = true; + opt.state ^= QStyle::State_Selected; + painter->fillRect(option.rect, RingTheme::smartlistSelection_); + } + else if (option.state & QStyle::State_MouseOver) { + painter->fillRect(option.rect, RingTheme::smartlistHighlight_); + } + + QRect &rect = opt.rect; + + // Avatar drawing + opt.decorationSize = QSize(avatarSize_, avatarSize_); + opt.decorationPosition = QStyleOptionViewItem::Left; + opt.decorationAlignment = Qt::AlignCenter; + + QRect rectAvatar(dy_ + rect.left(), rect.top() + dy_, avatarSize_, avatarSize_); + drawDecoration(painter, opt, rectAvatar, + QPixmap::fromImage(index.data(AccountListModel::Role::Picture).value<QImage>()) + .scaled(avatarSize_, avatarSize_, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + QFont font(painter->font()); + + // Presence indicator + QPainterPath outerCircle, innerCircle; + QPointF center(rectAvatar.right() - avatarSize_ / 6, (rectAvatar.bottom() - avatarSize_ / 6) + 1); + qreal outerCRadius = avatarSize_ / 6, innerCRadius = outerCRadius * 0.75; + outerCircle.addEllipse(center, outerCRadius, outerCRadius); + innerCircle.addEllipse(center, innerCRadius, innerCRadius); + auto status = index.data(static_cast<int>(AccountListModel::Role::Status)).value<int>(); + auto isPresent = Utils::toEnum<lrc::api::account::Status>(status) == lrc::api::account::Status::REGISTERED; + if (isPresent) { + painter->fillPath(outerCircle, Qt::white); + painter->fillPath(innerCircle, RingTheme::presenceGreen_); + } + + font.setPointSize(fontSize_); + QPen pen(painter->pen()); + + painter->setPen(pen); + + QRect rectTexts(dx_ + rect.left() + dx_ + avatarSize_, + rect.top(), + rect.width(), + rect.height() / 2); + + // The name is displayed at the avatar's right + QVariant name = index.data(static_cast<int>(AccountListModel::Role::Alias)); + if (name.isValid()) + { + font.setItalic(false); + font.setBold(true); + pen.setColor(RingTheme::lightBlack_); + painter->setPen(pen); + painter->setFont(font); + QFontMetrics fontMetrics(font); + QString nameStr = fontMetrics.elidedText(name.value<QString>(), Qt::ElideRight, + rectTexts.width() - avatarSize_ - dx_); + painter->drawText(rectTexts, Qt::AlignVCenter | Qt::AlignLeft, nameStr); + } + + // Display the ID under the name + QString idStr = index.data(static_cast<int>(AccountListModel::Role::Username)).value<QString>(); + if (idStr != name.toString()) { + font.setItalic(false); + font.setBold(false); + pen.setColor(RingTheme::grey_); + painter->setPen(pen); + painter->setFont(font); + QFontMetrics fontMetrics(font); + if (!idStr.isNull()) { + idStr = fontMetrics.elidedText(idStr, Qt::ElideRight, + rectTexts.width() - avatarSize_ - dx_ * 2); + painter->drawText(QRect(dx_ + rect.left() + dx_ + avatarSize_, + rect.top() + dy_ * 3, + rect.width(), + rect.height() / 2), + Qt::AlignBottom | Qt::AlignLeft, idStr); + } + } +} + +QSize AccountItemDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const +{ + QSize size = QItemDelegate::sizeHint(option, index); + size.setHeight(cellHeight_); + return size; +} diff --git a/smartlistdelegate.h b/accountitemdelegate.h similarity index 78% rename from smartlistdelegate.h rename to accountitemdelegate.h index 2b5e413..c3a798c 100644 --- a/smartlistdelegate.h +++ b/accountitemdelegate.h @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * - * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* + * Copyright (C) 2018 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 * @@ -15,29 +15,26 @@ * 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 <QPainter> #include <QItemDelegate> -class QPainter; - -class SmartListDelegate : public QItemDelegate +class AccountItemDelegate : public QItemDelegate { Q_OBJECT public: - explicit SmartListDelegate(QObject* parent = 0); + explicit AccountItemDelegate(QObject *parent = nullptr); protected: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; private: - constexpr static int sizeImage_ = 48; - constexpr static int cellHeight_ = 60; + constexpr static int fontSize_ = 10; + const QFont font_ = QFont("Arial", fontSize_); constexpr static int dy_ = 6; constexpr static int dx_ = 12; - constexpr static int fontSize_ = 10; - constexpr static int effectiveComBarSize_ = 48; + constexpr static int avatarSize_ = 36; + constexpr static int cellHeight_ = 48; }; diff --git a/accountlistmodel.cpp b/accountlistmodel.cpp new file mode 100644 index 0000000..fb7b2da --- /dev/null +++ b/accountlistmodel.cpp @@ -0,0 +1,105 @@ +/*************************************************************************** +* Copyright (C) 2018 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 "accountlistmodel.h" + +// Qt +#include <QDateTime> + +// LRC +#include "globalinstances.h" + +// Client +#include "pixbufmanipulator.h" +#include "lrcinstance.h" +#include "utils.h" + +AccountListModel::AccountListModel(QObject *parent) + : QAbstractItemModel(parent) +{ +} + +int AccountListModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return LRCInstance::accountModel().getAccountList().size(); // count + } + return 0; // A valid QModelIndex returns 0 as no entry has sub-elements +} + +int AccountListModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 1; +} + +QVariant AccountListModel::data(const QModelIndex &index, int role) const +{ + auto accountList = LRCInstance::accountModel().getAccountList(); + if (!index.isValid() || accountList.size() == 0) { + return QVariant(); + } + + auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountList.at(index.row())); + + switch (role) { + case Role::Alias: + case Qt::DisplayRole: + return QVariant(QString::fromStdString(accountInfo.profileInfo.alias)); + case Role::Username: + return QVariant(QString::fromStdString(accountInfo.profileInfo.uri)); + case Role::Type: + return QVariant(Utils::toUnderlyingValue<lrc::api::profile::Type>(accountInfo.profileInfo.type)); + case Role::Status: + return QVariant(Utils::toUnderlyingValue<lrc::api::account::Status>(accountInfo.status)); + case Role::Picture: + case Qt::DecorationRole: + return PixbufManipulator::accountPhoto(accountInfo); + case Role::ID: + return QVariant(QString::fromStdString(accountInfo.id)); + } + return QVariant(); +} + +QModelIndex AccountListModel::index(int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(parent); + if (column != 0) { + return QModelIndex(); + } + + if (row >= 0 && row < rowCount()) { + return createIndex(row, column); + } + return QModelIndex(); +} + +QModelIndex AccountListModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child); + return QModelIndex(); +} + +Qt::ItemFlags AccountListModel::flags(const QModelIndex &index) const +{ + auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable; + if (!index.isValid()) { + return QAbstractItemModel::flags(index); + } + return flags; +} diff --git a/accountlistmodel.h b/accountlistmodel.h new file mode 100644 index 0000000..127cb88 --- /dev/null +++ b/accountlistmodel.h @@ -0,0 +1,51 @@ +/*************************************************************************** +* Copyright (C) 2018 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 + +// Qt include +#include <QAbstractItemModel> + +// LRC +#include "api/account.h" +#include "api/conversation.h" +#include "api/contact.h" + +class AccountListModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + enum Role { + Alias = Qt::UserRole + 1, + Username, + Picture, + Type, + Status, + ID + }; + + explicit AccountListModel(QObject *parent = 0); + + // QAbstractItemModel + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + Qt::ItemFlags flags(const QModelIndex &index) const; +}; diff --git a/callutilsdialog.cpp b/callutilsdialog.cpp index db2453b..5e41620 100644 --- a/callutilsdialog.cpp +++ b/callutilsdialog.cpp @@ -34,7 +34,7 @@ CallUtilsDialog::CallUtilsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CallUtilsDialog), confMode_(false), - smartListDelegate_(nullptr), + conversationItemDelegate_(nullptr), notCurrentProxyModel_(nullptr), spikeMask_(new QPixmap(":/images/spikeMask.png")) { @@ -62,7 +62,7 @@ CallUtilsDialog::~CallUtilsDialog() delete effect_; delete spikeMask_; delete fadeAnim_; - delete smartListDelegate_; + delete conversationItemDelegate_; delete notCurrentProxyModel_; delete ui; } @@ -77,10 +77,10 @@ CallUtilsDialog::showEvent(QShowEvent* event) notCurrentProxyModel_ = new NotCurrentProxyModel(&RecentModel::instance()); } ui->contactView->setModel(notCurrentProxyModel_); - if (not smartListDelegate_) { - smartListDelegate_ = new SmartListDelegate(); + if (not conversationItemDelegate_) { + conversationItemDelegate_ = new ConversationItemDelegate(); } - ui->contactView->setItemDelegate(smartListDelegate_); + ui->contactView->setItemDelegate(conversationItemDelegate_); emit(isVisible(true)); diff --git a/callutilsdialog.h b/callutilsdialog.h index 0ab4491..e4b9130 100644 --- a/callutilsdialog.h +++ b/callutilsdialog.h @@ -24,7 +24,7 @@ #include "callmodel.h" #include "recentmodel.h" -#include "smartlistdelegate.h" +#include "conversationitemdelegate.h" #include <ciso646> @@ -79,7 +79,7 @@ private slots: private: Ui::CallUtilsDialog* ui; bool confMode_; - SmartListDelegate* smartListDelegate_; + ConversationItemDelegate* conversationItemDelegate_; NotCurrentProxyModel* notCurrentProxyModel_; QPixmap* spikeMask_; QPropertyAnimation* fadeAnim_; diff --git a/callwidget.cpp b/callwidget.cpp index e15cf7d..e41a38e 100644 --- a/callwidget.cpp +++ b/callwidget.cpp @@ -1,8 +1,9 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * + * Copyright (C) 2015-2018 by Savoir-faire Linux * * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * * Author: Olivier Soldano <olivier.soldano@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 * @@ -33,41 +34,22 @@ #undef ERROR #undef interface -//LRC -#include "audio/settings.h" -#include "accountmodel.h" -#include "personmodel.h" -#include "person.h" -#include "fallbackpersoncollection.h" -#include "categorizedcontactmodel.h" -#include "localhistorycollection.h" -#include "media/text.h" -#include "media/recording.h" -#include "media/recordingmodel.h" -#include "recentmodel.h" -#include "contactmethod.h" +// lrc #include "globalinstances.h" -#include <availableaccountmodel.h> -#include "pendingcontactrequestmodel.h" #include "profilemodel.h" -#include "profile.h" -#include "peerprofilecollection.h" #include "localprofilecollection.h" -#include "callmodel.h" -//Client +// client #include "wizarddialog.h" #include "windowscontactbackend.h" #include "contactpicker.h" -#include "contactmethodpicker.h" #include "globalsystemtray.h" -#include "smartlistdelegate.h" +#include "conversationitemdelegate.h" #include "imdelegate.h" #include "pixbufmanipulator.h" #include "settingskey.h" -#include "contactrequestitemdelegate.h" -#include "deletecontactdialog.h" - +#include "lrcinstance.h" +#include "messagemodel.h" CallWidget::CallWidget(QWidget* parent) : NavWidget(parent), @@ -77,15 +59,9 @@ CallWidget::CallWidget(QWidget* parent) : { ui->setupUi(this); - pageAnim_ = new QPropertyAnimation(ui->welcomePage, "pos", this); - - setActualCall(nullptr); - videoRenderer_ = nullptr; + using namespace lrc::api; - connect(ui->settingsButton, &QPushButton::clicked, this, &CallWidget::settingsButtonClicked); - - connect(ui->videoWidget, SIGNAL(setChatVisibility(bool)), - ui->instantMessagingWidget, SLOT(setVisible(bool))); + QApplication::setEffectEnabled(Qt::UI_AnimateCombo, false); QPixmap logo(":/images/logo-ring-standard-coul.png"); ui->ringLogo->setPixmap(logo.scaledToHeight(100, Qt::SmoothTransformation)); @@ -93,106 +69,92 @@ CallWidget::CallWidget(QWidget* parent) : ui->qrLabel->hide(); - try { - callModel_ = &CallModel::instance(); - - connect(callModel_, SIGNAL(incomingCall(Call*)), - this, SLOT(callIncoming(Call*))); - connect(callModel_, SIGNAL(callStateChanged(Call*, Call::State)), - this, SLOT(callStateChanged(Call*, Call::State))); - - RecentModel::instance().peopleProxy()->setFilterRole(static_cast<int>(Ring::Role::Name)); - RecentModel::instance().peopleProxy()->setFilterCaseSensitivity(Qt::CaseInsensitive); - ui->smartList->setModel(RecentModel::instance().peopleProxy()); + videoRenderer_ = nullptr; - PersonModel::instance().addCollection<PeerProfileCollection>(LoadOptions::FORCE_ENABLED); - ProfileModel::instance().addCollection<LocalProfileCollection>(LoadOptions::FORCE_ENABLED); + // this line is not welcome here, and must be removed + ProfileModel::instance().addCollection<LocalProfileCollection>(LoadOptions::FORCE_ENABLED); - PersonModel::instance(). - addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED); + // select last used account if stored in registry + auto accountList = LRCInstance::accountModel().getAccountList(); + if (!accountList.empty()) { + std::string accountIdToStartWith; + QSettings settings; + if (settings.contains(SettingsKey::selectedAccount)) { + accountIdToStartWith = settings + .value(SettingsKey::selectedAccount, true) + .value<QString>() + .toStdString(); + if (Utils::indexInVector(accountList, accountIdToStartWith) == -1) { + accountIdToStartWith = accountList.at(0); + } + } + else { + accountIdToStartWith = accountList.at(0); + } + setSelectedAccount(accountIdToStartWith); + // get account index and set the currentAccountWidget selector + auto index = Utils::indexInVector(accountList, accountIdToStartWith); + if (index != -1) { + ui->currentAccountWidget->changeSelectedIndex(index); + } + } - connect(ui->smartList, &QTreeView::entered, this, &CallWidget::on_entered); + // conversation list + conversationItemDelegate_ = new ConversationItemDelegate(); + ui->smartList->setContextMenuPolicy(Qt::CustomContextMenu); - smartListDelegate_ = new SmartListDelegate(); - ui->smartList->setSmartListItemDelegate(smartListDelegate_); + // setup searchingfor mini spinner + miniSpinner_ = new QMovie(":/images/waiting.gif"); + ui->spinnerLabel->setMovie(miniSpinner_); + ui->spinnerLabel->hide(); - ui->contactRequestList->setItemDelegate(new ContactRequestItemDelegate()); + // set to welcome view + ui->stackedWidget->setCurrentWidget(ui->welcomePage); + setupOutOfCallIM(); - ui->smartList->setContextMenuPolicy(Qt::CustomContextMenu); + // connections + connect(ui->settingsButton, &QPushButton::clicked, + this, &CallWidget::settingsButtonClicked); - connect(ui->smartList, &SmartList::btnVideoClicked, this, &CallWidget::btnComBarVideoClicked); + connect(ui->videoWidget, SIGNAL(setChatVisibility(bool)), + ui->instantMessagingWidget, SLOT(setVisible(bool))); - connect(RecentModel::instance().selectionModel(), - SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, - SLOT(smartListCurrentChanged(QModelIndex,QModelIndex))); + connect(ui->videoWidget, &VideoView::videoSettingsClicked, + this, &CallWidget::settingsButtonClicked); - //set most recent call to view - connect(&RecentModel::instance(), &QAbstractItemModel::dataChanged, [=](const QModelIndex &topLeft, const QModelIndex &bottomRight,const QVector<int> &vec){ - Q_UNUSED(bottomRight) - Q_UNUSED(vec) + connect(ui->buttonConversations, &QPushButton::clicked, + this, &CallWidget::conversationsButtonClicked); - if (topLeft.isValid() && RecentModel::instance().hasActiveCall(topLeft)){ - ui->smartList->selectionModel()->setCurrentIndex(topLeft,QItemSelectionModel::ClearAndSelect); - } - }); + connect(ui->buttonInvites, &QPushButton::clicked, + this, &CallWidget::invitationsButtonClicked); - connect(RecentModel::instance().selectionModel(), &QItemSelectionModel::selectionChanged, [=](const QItemSelection &selected, const QItemSelection &deselected) { - // lambda used to focus on the correct smartList element when switching automatically between two calls - 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 { - RecentModel::instance().selectionModel()->clearCurrentIndex(); - ui->smartList->clearSelection(); - ui->smartList->selectionModel()->clearCurrentIndex(); - } - }); - - connect(&NameDirectory::instance(), SIGNAL(registeredNameFound(Account*,NameDirectory::LookupStatus,const QString&,const QString&)), - this, SLOT(contactLineEdit_registeredNameFound(Account*,NameDirectory::LookupStatus,const QString&,const QString&))); - - connect(&AccountModel::instance(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), - ui->currentAccountWidget, SLOT(update())); - - connect(ui->searchBtn, SIGNAL(clicked(bool)), this, SLOT(searchBtnClicked())); - - connect(ui->sendContactRequestWidget, &SendContactRequestWidget::sendCRclicked, [=]{Utils::slidePage(ui->stackedWidget, ui->messagingPage);}); - - connect(ui->contactRequestWidget, &ContactRequestWidget::choiceMade, [this]() { - if (getSelectedAccount()->pendingContactRequestModel()->rowCount() == 0) - ui->mainTabMenu->setCurrentWidget(ui->mainTabMenuPage1); - else - ui->contactRequestList->selectionModel()->clear(); - }); + connect(ui->currentAccountWidget, &CurrentAccountWidget::currentAccountChanged, + this, &CallWidget::currentAccountChanged); - connect(AvailableAccountModel::instance().selectionModel(), &QItemSelectionModel::currentChanged, - this, &CallWidget::selectedAccountChanged); + // TODO(new lrc) + connect(&ProfileModel::instance(), &ProfileModel::dataChanged, + ui->currentAccountWidget, &CurrentAccountWidget::setPhoto); - // It needs to be called manually once to initialize the ui with the account selected at start. - // The second argument (previous) is set to an invalid QModelIndex as it is the first selection. - selectedAccountChanged(AvailableAccountModel::instance().selectionModel()->currentIndex(), QModelIndex()); + connect(ui->smartList, &QListView::customContextMenuRequested, + this, &CallWidget::slotCustomContextMenuRequested); - // This connect() is used to initialise and track changes of profile's picture - connect(&ProfileModel::instance(), &ProfileModel::dataChanged, - ui->currentAccountWidget, &CurrentAccountWidget::setPhoto); + connect(ui->smartList, &SmartListView::btnAcceptInviteClicked, + this, &CallWidget::slotAcceptInviteClicked); - connect(ui->videoWidget, &VideoView::videoSettingsClicked, this, &CallWidget::settingsButtonClicked); + connect(ui->smartList, &SmartListView::btnBlockInviteClicked, + this, &CallWidget::slotBlockInviteClicked); - connect(ui->smartList, &QListView::customContextMenuRequested, [=](const QPoint& pos){ setupSmartListMenu(pos);}); + connect(ui->smartList, &SmartListView::btnIgnoreInviteClicked, + this, &CallWidget::slotIgnoreInviteClicked); - // setup searchingfor mini spinner - miniSpinner_ = new QMovie(":/images/waiting.gif"); - ui->spinnerLabel->setMovie(miniSpinner_); - ui->spinnerLabel->hide(); + connect(&LRCInstance::behaviorController(), &BehaviorController::showCallView, + this, &CallWidget::slotShowCallView); - } catch (const std::exception& e) { - qDebug() << "INIT ERROR" << e.what(); - } + connect(&LRCInstance::behaviorController(), &BehaviorController::showIncomingCallView, + this, &CallWidget::slotShowIncomingCallView); - setupOutOfCallIM(); + connect(&LRCInstance::behaviorController(), &BehaviorController::showChatView, + this, &CallWidget::slotShowChatView); } CallWidget::~CallWidget() @@ -200,9 +162,7 @@ CallWidget::~CallWidget() delete ui; delete menu_; delete imDelegate_; - delete pageAnim_; - delete smartListDelegate_; - delete shareMenu_; + delete conversationItemDelegate_; } void @@ -221,131 +181,108 @@ CallWidget::setupOutOfCallIM() QApplication::clipboard()->setText(text.value<QString>()); } }); - - QSettings settings; - - auto displayDate = new QAction(tr("Display date"), this); - displayDate->setCheckable(true); - displayDate->setChecked(settings.value(SettingsKey::imShowDate).toBool()); - ui->listMessageView->addAction(displayDate); - - auto displayAuthor = new QAction(tr("Display author"), this); - displayAuthor->setCheckable(true); - displayAuthor->setChecked(settings.value(SettingsKey::imShowAuthor).toBool()); - ui->listMessageView->addAction(displayAuthor); - - auto lamdba = [=](){ - QSettings settings; - settings.setValue(SettingsKey::imShowAuthor, displayAuthor->isChecked()); - settings.setValue(SettingsKey::imShowDate, displayDate->isChecked()); - emit imDelegate_->sizeHintChanged(QModelIndex()); - }; - - connect(displayAuthor, &QAction::triggered, lamdba); - connect(displayDate, &QAction::triggered, lamdba); - - connect(&::media::RecordingModel::instance(), - SIGNAL(newTextMessage(::media::TextRecording*, ContactMethod*)), - this, - SLOT(onIncomingMessage(::media::TextRecording*, ContactMethod*))); } void -CallWidget::onIncomingMessage(::media::TextRecording* t, ContactMethod* cm) +CallWidget::onIncomingMessage(const std::string& convUid, + uint64_t interactionId, + const lrc::api::interaction::Info& interaction) { - Q_UNUSED(cm) - + Q_UNUSED(interactionId); 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); + Utils::showSystemNotification(this, + QString(tr("Message incoming from %1")) + .arg(QString::fromStdString(interaction.body))); } + updateConversationView(convUid); + ui->conversationsFilterWidget->update(); } void -CallWidget::triggerDeleteContactDialog(ContactMethod *cm, Account *ac) +CallWidget::setupSmartListContextMenu(const QPoint& pos) { - auto dlg = new DeleteContactDialog(cm, ac); - dlg->exec(); -} - -void -CallWidget::setupSmartListMenu(const QPoint& pos) -{ - auto idx = ui->smartList->currentIndex(); - - if (not idx.isValid()) + QPoint globalPos = ui->smartList->mapToGlobal(pos); + auto index = ui->smartList->indexAt(pos); + if (not index.isValid()) { return; + } - QPoint globalPos = ui->smartList->mapToGlobal(pos); - QMenu menu; - QVector<ContactMethod*> contactMethods = RecentModel::instance() - .getContactMethods(RecentModel::instance().peopleProxy()->mapToSource(idx)); + auto convModel = LRCInstance::getCurrentConversationModel(); + auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)) + .value<QString>() + .toStdString(); + auto conversation = Utils::getConversationFromUid(convUid, *convModel); + auto contactUid = (*conversation).participants.at(0); + auto contact = LRCInstance::getCurrentAccountInfo().contactModel.get()->getContact(contactUid); - if (contactMethods.isEmpty()) + if (!Utils::isContactValid(contactUid, *convModel)) { return; + } - auto contactMethod = contactMethods.first(); + QMenu menu; - if (contactMethods.size() == 1){ - auto copyAction = new QAction(tr("Copy number"), this); - menu.addAction(copyAction); - connect(copyAction, &QAction::triggered, [contactMethod]() { - QApplication::clipboard()->setText(contactMethod->uri()); + // video call + auto videoCallAction = new QAction(tr("Start video call"), this); + menu.addAction(videoCallAction); + connect(videoCallAction, &QAction::triggered, + [this, convUid, conversation, convModel]() { + convModel->placeCall(convUid); + ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid))); + if (convUid != selectedConvUid()) { + selectConversation(*conversation, *convModel); + } }); - - auto copyNameAction = new QAction(tr("Copy name"), this); - menu.addAction(copyNameAction); - connect(copyNameAction, &QAction::triggered, [contactMethod]() { - QApplication::clipboard()->setText(contactMethod->primaryName()); + // audio call + auto audioCallAction = new QAction(tr("Start audio call"), this); + menu.addAction(audioCallAction); + connect(audioCallAction, &QAction::triggered, + [this, convUid, conversation, convModel]() { + convModel->placeAudioOnlyCall(convUid); + ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid))); + if (convUid != selectedConvUid()) { + selectConversation(*conversation, *convModel); + } }); - } else { - auto callMenu = menu.addMenu(tr("Call Number")); - auto copyMenu = menu.addMenu(tr("Copy Number")); - for (auto cM : contactMethods) { - auto uri = cM->bestId(); - auto copyAction = new QAction(tr("Copy %1").arg(uri), this); - copyMenu->addAction(copyAction); - connect(copyAction, &QAction::triggered, [uri]() { - QApplication::clipboard()->setText(uri); + + if (contact.profileInfo.type == lrc::api::profile::Type::RING) { + // separator + menu.addSeparator(); + + // clear conversation + auto clearConversationAction = new QAction(tr("Clear conversation"), this); + menu.addAction(clearConversationAction); + connect(clearConversationAction, &QAction::triggered, + [convUid]() { + LRCInstance::getCurrentConversationModel()->clearHistory(convUid); }); - 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); + // block contact + auto blockContactAction = new QAction(tr("Block contact"), this); + menu.addAction(blockContactAction); + connect(blockContactAction, &QAction::triggered, + [convUid]() { + LRCInstance::getCurrentConversationModel()->removeConversation(convUid, true); }); - } - } - auto ac = getSelectedAccount(); - if (ac && !ac->hasContact(contactMethod)) { - auto addExisting = new QAction(tr("Add to contacts"), this); - menu.addAction(addExisting); - connect(addExisting, &QAction::triggered, [this, contactMethod, ac]() { - /* uncomment and capture globalPos in lambda to reactivate popup - ContactPicker contactPicker(contactMethod); - contactPicker.move(globalPos.x(), globalPos.y() - (contactPicker.height()/2)); - contactPicker.exec(); - */ - ac->addContact(contactMethod); - }); - } else if (ac) { - auto removeExisting = new QAction(tr("Remove from contacts"), this); - menu.addAction(removeExisting); - connect(removeExisting, &QAction::triggered, [this, contactMethod, ac]() { - triggerDeleteContactDialog(contactMethod, ac); - }); + // separator + menu.addSeparator(); + + // copy number(infohash) + auto copyNumberAction = new QAction(tr("Copy number"), this); + menu.addAction(copyNumberAction); + connect(copyNumberAction, &QAction::triggered, + [contact]() { + QApplication::clipboard()->setText( + QString::fromStdString(contact.profileInfo.uri) + ); + }); } - + smartListModel_->isContextMenuOpen_ = true; menu.exec(globalPos); + smartListModel_->isContextMenuOpen_ = false; } -void CallWidget::setupQRCode(QString ringID) +void +CallWidget::setupQRCode(QString ringID) { auto rcode = QRcode_encodeString(ringID.toStdString().c_str(), 0, //Let the version be decided by libqrencode @@ -379,24 +316,22 @@ void CallWidget::setupQRCode(QString ringID) } painter.end(); QRcode_free(rcode); - ui->qrLabel->setPixmap(QPixmap::fromImage(result.scaled(QSize(qrSize_, qrSize_), Qt::KeepAspectRatio))); + ui->qrLabel->setPixmap(QPixmap::fromImage(result.scaled(QSize(qrSize_, qrSize_), + Qt::KeepAspectRatio))); } bool CallWidget::findRingAccount() { bool ringAccountFound = false; - auto a_count = AccountModel::instance().rowCount(); - for (int i = 0; i < a_count; ++i) { - auto idx = AccountModel::instance().index(i, 0); - auto protocol = idx.data(static_cast<int>(Account::Role::Proto)); - if (static_cast<Account::Protocol>(protocol.toUInt()) == Account::Protocol::RING) { + auto accountList = LRCInstance::accountModel().getAccountList(); + for (int i = 0; i < accountList.size(); ++i) { + auto accountId = accountList.at(i); + auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountId); + if (accountInfo.profileInfo.type == lrc::api::profile::Type::RING) { ringAccountFound = true; - auto account = AccountModel::instance().getAccountByModelIndex(idx); - if (account->displayName().isEmpty()) - account->displayName() = account->alias(); - if (account->needsMigration()) { - WizardDialog dlg(WizardDialog::MIGRATION, account); + if (accountInfo.status == lrc::api::account::Status::ERROR_NEED_MIGRATION) { + WizardDialog dlg(WizardDialog::MIGRATION); dlg.exec(); } } @@ -416,215 +351,128 @@ CallWidget::findRingAccount() } void -CallWidget::callChangedSlot() -{ - if (not actualCall_) - return; - - ui->callerIdLabel->setText(QString("%1") - .arg(actualCall_->formattedName())); - ui->callerPhoto->setPixmap( - QPixmap::fromImage( - GlobalInstances::pixmapManipulator() - .callPhoto(actualCall_, QSize(128, 128)).value<QImage>())); - ui->callerBestIdLabel->setText(actualCall_->peerContactMethod()->bestId()); - - if(actualCall_->state() == Call::State::OVER || actualCall_->state() == Call::State::FAILURE){ - ui->outboundCallLabel->setText(actualCall_->toHumanStateName(Call::State::INITIALIZATION)); - } else { - ui->outboundCallLabel->setText(actualCall_->toHumanStateName()); - } -} - -void -CallWidget::callIncoming(Call* call) +CallWidget::on_smartList_clicked(const QModelIndex& index) { - if (!QApplication::focusWidget()) { - GlobalSystemTray::instance() - .showMessage("Ring", - QString(tr("Call incoming from %1")).arg(call->formattedName())); - QApplication::alert(this, 5000); - } - - setActualCall(call); + Q_UNUSED(index); } void CallWidget::on_acceptButton_clicked() { - if (actualCall_ != nullptr) - actualCall_->performAction(Call::Action::ACCEPT); + auto convModel = LRCInstance::getCurrentConversationModel(); + auto callModel = LRCInstance::getCurrentCallModel(); + auto conversation = Utils::getConversationFromUid(selectedConvUid(), *convModel); + callModel->accept(conversation->callId); } void CallWidget::on_refuseButton_clicked() { - if (actualCall_ == nullptr) - return; - actualCall_->performAction(Call::Action::REFUSE); - ui->stackedWidget->setCurrentWidget(ui->welcomePage); - setActualCall(nullptr); + auto convModel = LRCInstance::getCurrentConversationModel(); + auto conversation = Utils::getConversationFromUid(selectedConvUid(), *convModel); + LRCInstance::getCurrentCallModel()->hangUp(conversation->callId); + showConversationView(); } void -CallWidget::callStateChanged(Call* call, Call::State previousState) +CallWidget::on_cancelButton_clicked() { - Q_UNUSED(previousState) - if (call == nullptr - || call != actualCall_) - return; - - callStateToView(call); - - if (call->state() == Call::State::OVER) { - setActualCall(nullptr); - ui->smartList->clearSelection(); - RecentModel::instance().selectionModel()->clear(); - } + auto convModel = LRCInstance::getCurrentConversationModel(); + auto conversation = Utils::getConversationFromUid(selectedConvUid(), *convModel); + LRCInstance::getCurrentCallModel()->hangUp(conversation->callId); + showConversationView(); } void -CallWidget::atExit() +CallWidget::showConversationView() { + ui->stackedWidget->setCurrentWidget(ui->messagingPage); + ui->imMessageEdit->clear(); + ui->imMessageEdit->setFocus(); + disconnect(imClickedConnection_); + imClickedConnection_ = connect(ui->listMessageView, &QListView::clicked, [this](const QModelIndex& index) { + auto urlList = index.data(static_cast<int>(media::TextRecording::Role::LinkList)).value<QList<QUrl>>(); + if (urlList.size() == 1) { + QDesktopServices::openUrl(urlList.at(0)); + } else if (urlList.size()) { + //TODO Handle multiple url in one message + } + }); } void -CallWidget::callStateToView(Call* value) +CallWidget::selectSmartlistItem(const std::string & convUid) { - 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: - case Call::State::CONFERENCE: - case Call::State::HOLD: - ui->stackedWidget->setCurrentWidget(ui->videoPage); - hideMiniSpinner(); - break; - case Call::State::OVER: - ui->stackedWidget->setCurrentWidget(ui->welcomePage); - break; - case Call::State::FAILURE: - case Call::State::ERROR: - on_cancelButton_clicked(); - hideMiniSpinner(); - break; - case Call::State::INITIALIZATION: - case Call::State::CONNECTED: - case Call::State::RINGING: - miniSpinner_->start(); - ui->spinnerLabel->show(); - ui->stackedWidget->setCurrentWidget(ui->outboundCallPage); - break; - default: - qWarning() << "Call state not handled doing nothing : " - << value->toHumanStateName(); - break; + if (convUid.empty()) { + return; + } + ui->smartList->selectionModel()->setCurrentIndex(QModelIndex(), QItemSelectionModel::Deselect); + auto convModel = LRCInstance::getCurrentConversationModel(); + auto conversation = Utils::getConversationFromUid(convUid, *convModel); + if (conversation == convModel->allFilteredConversations().end()) { + return; + } + auto contactURI = QString::fromStdString((*conversation).participants[0]); + if (contactURI.isEmpty() || + convModel->owner.contactModel->getContact(contactURI.toStdString()).profileInfo.type == lrc::api::profile::Type::TEMPORARY) { + return; + } + for (int row = 0; row < smartListModel_->rowCount(); row++) { + QModelIndex index = smartListModel_->index(row); + auto indexContactURI = index.data(SmartListModel::Role::URI).value<QString>(); + if (indexContactURI == contactURI) { + ui->smartList->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); + return; } } } void -CallWidget::setActualCall(Call* value) +CallWidget::on_smartList_doubleClicked(const QModelIndex& index) { - actualCall_ = value; - CallModel::instance().selectCall(value); - ui->videoWidget->pushRenderer(value); - ui->instantMessagingWidget->setMediaText(actualCall_); - callStateToView(value); - if (actualCall_) { - callChangedConnection_ = connect(actualCall_, - SIGNAL(changed()), - this, - SLOT(callChangedSlot())); - } else - disconnect(callChangedConnection_); + if (!index.isValid()) + return; + LRCInstance::getCurrentConversationModel()->placeCall(selectedConvUid()); + + ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(selectedConvUid()))); } -void -CallWidget::on_cancelButton_clicked() +QImage +CallWidget::imageForConv(const std::string& convUid) { - if (actualCall_){ - actualCall_->performAction(Call::Action::REFUSE); - ui->stackedWidget->setCurrentWidget(ui->welcomePage); - } + return Utils::conversationPhoto(convUid, LRCInstance::getCurrentAccountInfo()); } -void -CallWidget::on_smartList_clicked(const QModelIndex& index) +const std::string& +CallWidget::selectedAccountId() { - RecentModel::instance().selectionModel()->setCurrentIndex( - RecentModel::instance().peopleProxy()->mapToSource(index), - QItemSelectionModel::ClearAndSelect); + return LRCInstance::getSelectedAccountId(); } -void -CallWidget::on_smartList_doubleClicked(const QModelIndex& index) +const std::string& +CallWidget::selectedConvUid() { - if (!index.isValid()) - return; - - auto realIndex = RecentModel::instance().peopleProxy()->mapToSource(index); - if (RecentModel::instance().hasActiveCall(realIndex)) - 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(); - } - } - - if (m && !RecentModel::instance().index(0, 0, realIndex).isValid()) { - - QPixmap map = QPixmap::fromImage( - GlobalInstances::pixmapManipulator().callPhoto(m, QSize(130,130)).value<QImage>()); - ui->callingPhoto->setPixmap(map); - - Call* c = CallModel::instance().dialingCall(m); - c->performAction(Call::Action::ACCEPT); - setActualCall(c); - } + return LRCInstance::getSelectedConvUid(); } void -CallWidget::smartListCurrentChanged(const QModelIndex ¤tIdx, const QModelIndex &previousIdx) +CallWidget::smartListSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { - Q_UNUSED(previousIdx); - if (not currentIdx.isValid()) { - auto widget = ui->stackedWidget->currentWidget(); - if (widget == ui->messagingPage || widget == ui->videoPage) - Utils::slidePage(ui->stackedWidget, ui->welcomePage); - if(actualCall_) - setActualCall(nullptr); + Q_UNUSED(deselected); + QModelIndexList indices = selected.indexes(); + + if (indices.isEmpty()) { return; } - //catch call of current index - auto currentIdxCall = RecentModel::instance().getActiveCall(currentIdx); + auto selectedIndex = indices.at(0); - if (currentIdxCall) { - if (currentIdxCall != actualCall_) //if it is different from actual call, switch between the two - setActualCall(currentIdxCall); - } else { // if there is no call attached to this smartlist index (contact tab) - setActualCall(nullptr); - showIMOutOfCall(currentIdx); // change page to contact request of messaging page with correct behaviour - } - /* - else { // if non defined behaviour disconnect instant messaging and return to welcome page - setActualCall(nullptr); - if (imConnection_) - disconnect(imConnection_); - ui->stackedWidget->setCurrentWidget(ui->welcomePage); + if (not selectedIndex.isValid()) { + return; } - */ + + selectConversation(selectedIndex); } void @@ -638,7 +486,7 @@ CallWidget::contactReqListCurrentChanged(const QModelIndex ¤tIdx, const QM } else { ui->contactRequestWidget->setCurrentContactRequest(QModelIndex()); if (ui->stackedWidget->currentWidget() == ui->contactRequestPage) - Utils::slidePage(ui->stackedWidget, ui->welcomePage); + Utils::setStackWidget(ui->stackedWidget, ui->welcomePage); } } @@ -657,144 +505,219 @@ CallWidget::placeCall() } void -CallWidget::settingsButtonClicked() +CallWidget::conversationsButtonClicked() { - emit NavigationRequested(ScreenEnum::ConfScreen); + setConversationFilter(lrc::api::profile::Type::RING); } void -CallWidget::searchContactLineEditEntry(const URI &uri) +CallWidget::invitationsButtonClicked() { - auto cm = PhoneDirectoryModel::instance().getNumber(uri, getSelectedAccount()); - // if its a new CM, bring it to the top - if (cm->lastUsed() == 0) - cm->setLastUsed(QDateTime::currentDateTime().toTime_t()); - - // select cm - RecentModel::instance().selectionModel()->setCurrentIndex(RecentModel::instance().getIndex(cm), - QItemSelectionModel::ClearAndSelect); - ui->ringContactLineEdit->clear(); - cm->setAccount(AvailableAccountModel::instance().currentDefaultAccount(cm)); + setConversationFilter(lrc::api::profile::Type::PENDING); } -bool -CallWidget::uriNeedNameLookup(const URI uri_passed) +void +CallWidget::settingsButtonClicked() { - if (uri_passed.protocolHint() == URI::ProtocolHint::RING_USERNAME ) { - return TRUE; - } else if ( - uri_passed.protocolHint() != URI::ProtocolHint::RING && // not a RingID - uri_passed.schemeType() == URI::SchemeType::NONE // scheme type not specified - ){ - // if no scheme type has been specified, determine ring vs sip by the current selected account - auto idx = AvailableAccountModel::instance().selectionModel()->currentIndex(); - if (idx.isValid()) { - auto account = idx.data((int)Ring::Role::Object).value<Account *>(); - if (account && account->protocol() == Account::Protocol::RING) - return TRUE; - } - } - - return FALSE; + emit NavigationRequested(ScreenEnum::ConfScreen); } void CallWidget::processContactLineEdit() { auto contactLineText = ui->ringContactLineEdit->text(); - URI uri_passed = URI(contactLineText); - Account* ac = getSelectedAccount(); - - if (!contactLineText.isNull() && !contactLineText.isEmpty()){ - if (uriNeedNameLookup(uri_passed)){ - NameDirectory::instance().lookupName(ac, QString(), uri_passed); - } else { - searchContactLineEditEntry(uri_passed); - } - } + setConversationFilter(contactLineText); } void CallWidget::on_ringContactLineEdit_returnPressed() { - processContactLineEdit(); + // select current temporary item and show conversation + auto convModel = LRCInstance::getCurrentConversationModel(); + auto conversations = convModel->allFilteredConversations(); + auto contactIsValid = Utils::isContactValid(conversations.at(0).participants.at(0), *convModel); + if (!conversations.empty() && contactIsValid) { + selectConversation(smartListModel_->index(0)); + } } -void -CallWidget::searchBtnClicked() +void CallWidget::slotAcceptInviteClicked(const QModelIndex & index) { - processContactLineEdit(); + auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>(); + LRCInstance::getCurrentConversationModel()->makePermanent(convUid.toStdString()); } -void -CallWidget::btnComBarVideoClicked() +void CallWidget::slotBlockInviteClicked(const QModelIndex & index) { - if (not highLightedIndex_.isValid()) - return; - - on_smartList_doubleClicked(highLightedIndex_); + auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>(); + LRCInstance::getCurrentConversationModel()->removeConversation(convUid.toStdString(), true); } -void -CallWidget::selectedAccountChanged(const QModelIndex ¤t, const QModelIndex &previous) +void CallWidget::slotIgnoreInviteClicked(const QModelIndex & index) { - Q_UNUSED(previous) + auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>(); + LRCInstance::getCurrentConversationModel()->removeConversation(convUid.toStdString()); +} - if (current.isValid()) { - if (ui->selectBar->isHidden()){ - ui->selectBar->show(); - } - auto ac = current.data(static_cast<int>(Account::Role::Object)).value<Account*>(); +void CallWidget::slotCustomContextMenuRequested(const QPoint& pos) +{ + setupSmartListContextMenu(pos); +} - // First, we get back to the welcome view (except if in call) +void CallWidget::slotShowCallView(const std::string& accountId, + const lrc::api::conversation::Info& convInfo) +{ + Q_UNUSED(accountId); + Q_UNUSED(convInfo); + qDebug() << "BehaviorController::showCallView"; + ui->stackedWidget->setCurrentWidget(ui->videoPage); + hideMiniSpinner(); +} - if (ui->stackedWidget->currentWidget() != ui->videoPage && - ui->stackedWidget->currentWidget() != ui->welcomePage) { - Utils::slidePage(ui->stackedWidget, ui->welcomePage); +void CallWidget::slotShowIncomingCallView(const std::string& accountId, + const lrc::api::conversation::Info& convInfo) { + Q_UNUSED(accountId); + qDebug() << "BehaviorController::showIncomingCallView"; + auto callModel = LRCInstance::getCurrentCallModel(); + auto call = callModel->getCall(convInfo.callId); + if (call.isOutgoing) { + miniSpinner_->start(); + ui->spinnerLabel->show(); + ui->stackedWidget->setCurrentWidget(ui->outboundCallPage); + } + else { + selectSmartlistItem(convInfo.uid); + auto selectedAccountId = LRCInstance::getCurrentAccountInfo().id; + auto accountProperties = LRCInstance::accountModel().getAccountConfig(selectedAccountId); + if (!accountProperties.autoAnswer) { + ui->stackedWidget->setCurrentWidget(ui->callInvitePage); } - - // We setup the ringIdLabel and the QRCode - auto protocol = ac->protocol(); - if (protocol == Account::Protocol::RING) { - ui->ringIdLabel->setText((ac->registeredName().isEmpty())?ac->username():ac->registeredName()); - setupQRCode(ac->username()); - } else { - ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND")); + else { + ui->stackedWidget->setCurrentWidget(ui->videoPage); + } + if (!QApplication::focusWidget()) { + auto formattedName = Utils::bestNameForConversation(convInfo, *LRCInstance::getCurrentConversationModel()); + Utils::showSystemNotification(this, + QString(tr("Call incoming from %1")).arg(QString::fromStdString(formattedName))); } + } - // Then, we update the pending CR list with those from the newly selected account - if (disconnect(crListSelectionConnection_)) { - ui->contactRequestList->selectionModel()->clear(); - // The selection model must be deleted by the application (see QT doc). - QItemSelectionModel* sMod = ui->contactRequestList->selectionModel(); - delete sMod; - RecentModel::instance().selectionModel()->clear(); + if (!callModel->hasCall(convInfo.callId)) { + return; + } + + ui->videoWidget->pushRenderer(convInfo.callId); + // TODO:(new lrc) in call chat + //ui->instantMessagingWidget->setMediaText(actualCall_); + + disconnect(selectedCallChanged_); + selectedCallChanged_ = connect( + callModel, + &lrc::api::NewCallModel::callStatusChanged, + [this, callModel](const std::string& callUid) { + auto call = callModel->getCall(callUid); + qDebug() << "NewCallModel::callStatusChanged: " << static_cast<int>(call.status); } + ); - ui->contactRequestList->setItemModel(ac->pendingContactRequestModel()); + ui->callerPhoto->setPixmap(QPixmap::fromImage(imageForConv(selectedConvUid()))); +} - // We modify the currentAccountWidget to reflect the new selected account - // if the event wasn't triggered by this widget - ui->currentAccountWidget->changeSelectedIndex(current.row()); +void CallWidget::slotShowChatView(const std::string& accountId, + const lrc::api::conversation::Info& convInfo) { + Q_UNUSED(accountId); + Q_UNUSED(convInfo); + qDebug() << "BehaviorController::showChatView"; + showConversationView(); +} - if (actualCall_){ - // keep call on foreground - callStateToView(actualCall_); - } - } else { +void +CallWidget::currentAccountChanged(const QModelIndex ¤t) +{ + if (!current.isValid()) { ui->selectBar->hide(); ui->ringIdLabel->setText(""); + return; + } + if (ui->selectBar->isHidden()){ + ui->selectBar->show(); + } + + auto accountId = current.data(static_cast<int>(AccountListModel::Role::ID)).value<QString>().toStdString(); + + setSelectedAccount(accountId); +} + +void +CallWidget::setSelectedAccount(const std::string& accountId) +{ + LRCInstance::setSelectedAccountId(accountId); + + // First, we get back to the welcome view (except if in call) + if (ui->stackedWidget->currentWidget() != ui->videoPage && + ui->stackedWidget->currentWidget() != ui->welcomePage) { + Utils::setStackWidget(ui->stackedWidget, ui->welcomePage); + } + + // We setup the ringIdLabel and the QRCode + auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountId); + auto id = accountInfo.registeredName.empty() ? accountInfo.profileInfo.uri : accountInfo.registeredName; + auto isRingAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING; + if (isRingAccount) { + ui->ringIdLabel->setText(QString::fromStdString(id)); + setupQRCode(QString::fromStdString(accountInfo.profileInfo.uri)); + } + + updateSmartList(); + currentTypeFilter_ = accountInfo.profileInfo.type; + LRCInstance::getCurrentConversationModel()->setFilter(accountInfo.profileInfo.type); + updateConversationsFilterWidget(); + connectConversationModel(); +} + +void CallWidget::setConversationFilter(lrc::api::profile::Type filter) +{ + if (currentTypeFilter_ == filter) { + return; + } + currentTypeFilter_ = filter; + LRCInstance::getCurrentConversationModel()->setFilter(currentTypeFilter_); +} + +void CallWidget::updateConversationsFilterWidget() +{ + auto invites = LRCInstance::getCurrentAccountInfo().contactModel->pendingRequestCount(); + if (invites == 0 && currentTypeFilter_ == lrc::api::profile::Type::PENDING) { + currentTypeFilter_ = lrc::api::profile::Type::RING; + LRCInstance::getCurrentConversationModel()->setFilter(currentTypeFilter_); } + ui->conversationsFilterWidget->setVisible(invites); + ui->verticalSpacer_3->changeSize(0, 10 * (1 - static_cast<bool>(invites))); +} + +void CallWidget::setConversationFilter(const QString & filter) +{ + LRCInstance::getCurrentConversationModel()->setFilter(filter.toStdString()); } void CallWidget::showIMOutOfCall(const QModelIndex& nodeIdx) { - ui->contactMethodComboBox->clear(); - QString name = nodeIdx.data(static_cast<int>(Ring::Role::Name)).toString(); - QString number = nodeIdx.data(static_cast<int>(Ring::Role::Number)).toString(); + QString displayName = nodeIdx.data(static_cast<int>(SmartListModel::Role::DisplayName)).toString(); + QString displayId = nodeIdx.data(static_cast<int>(SmartListModel::Role::DisplayID)).toString(); + QString contactURI = nodeIdx.data(static_cast<int>(SmartListModel::Role::URI)).toString(); + + bool isContact = false; + auto selectedAccountId = LRCInstance::getSelectedAccountId(); + auto& accountInfo = LRCInstance::accountModel().getAccountInfo(selectedAccountId); + bool isRINGAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING; + try { + accountInfo.contactModel->getContact(contactURI.toStdString()); + isContact = true; + } + catch (...) {} - if (getSelectedAccount()->isIp2ip()){ + if (!isRINGAccount){ ui->imMessageEdit->setPlaceholderText("No messaging possible out of call (SIP) "); ui->imMessageEdit->setEnabled(false); ui->sendIMButton->hide(); @@ -805,58 +728,38 @@ CallWidget::showIMOutOfCall(const QModelIndex& nodeIdx) } ui->imNameLabel->setText(QString(tr("%1", "%1 is the contact username")) - .arg(name)); + .arg(displayName)); - if ( !getSelectedAccount()->isIp2ip() && name != number ){ + if (isRINGAccount && displayName != displayId){ ui->imIdLabel->show(); ui->imIdLabel->setText(QString(tr("%1", "%1 is the contact unique identifier")) - .arg(number)); + .arg(displayId)); } else { ui->imIdLabel->hide(); } - auto cmVector = RecentModel::instance().getContactMethods(nodeIdx); - ui->contactMethodComboBox->setVisible(cmVector.size() > 1); - foreach (const ContactMethod* cm, cmVector) { - ui->contactMethodComboBox->addItem(cm->bestId()); - } + bool shouldShowSendContactRequestBtn = !isContact && isRINGAccount; + ui->sendContactRequestPageButton->setVisible(shouldShowSendContactRequestBtn); - ui->sendContactRequestPageButton->setVisible(shouldDisplayInviteButton(*cmVector[0])); + showConversationView(); - ui->stackedWidget->setCurrentWidget(ui->messagingPage); - ui->imMessageEdit->clear(); - ui->imMessageEdit->setFocus(); - disconnect(imClickedConnection_); - imClickedConnection_ = connect(ui->listMessageView, &QListView::clicked, [this](const QModelIndex& index) { - auto urlList = index.data(static_cast<int>(media::TextRecording::Role::LinkList)).value<QList<QUrl>>(); - if (urlList.size() == 1) - QDesktopServices::openUrl(urlList.at(0)); - else if (urlList.size()) { - //TODO Handle multiple url in one message - } - }); + auto currentConversation = Utils::getConversationFromUid(selectedConvUid(), + *LRCInstance::getCurrentConversationModel()); + messageModel_.reset(new MessageModel(*currentConversation, accountInfo, this->parent())); + ui->listMessageView->setModel(messageModel_.get()); + ui->listMessageView->scrollToBottom(); } void CallWidget::on_sendIMButton_clicked() { - if (ui->imMessageEdit->text().trimmed().isEmpty()) - return; - - auto idx = RecentModel::instance().selectionModel()->currentIndex(); - auto cmVec = RecentModel::instance().getContactMethods(idx); - if (cmVec.size() > 0) { - auto cm = cmVec[0]; - if(!cm) { - qWarning() << "Contact Method not found"; - return; - } - QMap<QString, QString> msg; - msg["text/plain"] = ui->imMessageEdit->text(); - cm->sendOfflineTextMessage(msg); - ui->imMessageEdit->clear(); - } else { - qWarning() << "No contact method found for messaging"; + auto msg = ui->imMessageEdit->text(); + if (msg.trimmed().isEmpty()) return; + ui->imMessageEdit->clear(); + try { + LRCInstance::getCurrentConversationModel()->sendMessage(selectedConvUid(), msg.toStdString()); + } catch (...) { + qDebug() << "exception when sending message"; } } @@ -866,48 +769,6 @@ CallWidget::on_imMessageEdit_returnPressed() on_sendIMButton_clicked(); } -void CallWidget::on_contactMethodComboBox_currentIndexChanged(int index) -{ - auto idx = RecentModel::instance().selectionModel()->currentIndex(); - auto cmVec = RecentModel::instance().getContactMethods(idx); - ContactMethod* cm {}; - - if (index < cmVec.size() && index >= 0 ){ - cm = cmVec[index]; - } - - if (cm){ - ui->sendContactRequestPageButton->setVisible(shouldDisplayInviteButton(*cm)); - if (auto txtRecording = cm->textRecording()) { - ui->listMessageView->setModel(txtRecording->instantMessagingModel()); - if (imConnection_) - disconnect(imConnection_); - imConnection_ = connect(txtRecording, - SIGNAL(messageInserted(QMap<QString,QString>,ContactMethod*,media::Media::Direction)), - this, - SLOT(slotAccountMessageReceived(QMap<QString,QString>,ContactMethod*,media::Media::Direction))); - auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0; - if (messagesPresent) { - ui->listMessageView->scrollToBottom(); - txtRecording->setAllRead(); - } - ui->listMessageView->setVisible(messagesPresent); - ui->noMessagesLabel->setVisible(!messagesPresent); - if (not messagesPresent) { - imVisibleConnection_ = connect(txtRecording->instantMessagingModel(), - &QAbstractItemModel::rowsInserted, - [this, txtRecording]() { - if (imVisibleConnection_) - disconnect(imVisibleConnection_); - auto messagesPresent = txtRecording->instantMessagingModel()->rowCount() > 0; - ui->listMessageView->setVisible(messagesPresent); - ui->noMessagesLabel->setVisible(!messagesPresent); - }); - } - } - } -} - void CallWidget::slotAccountMessageReceived(const QMap<QString,QString> message, ContactMethod* cm, @@ -923,17 +784,19 @@ CallWidget::slotAccountMessageReceived(const QMap<QString,QString> message, void CallWidget::on_ringContactLineEdit_textChanged(const QString& text) { - RecentModel::instance().peopleProxy()->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive, QRegExp::FixedString)); + Q_UNUSED(text); + processContactLineEdit(); } void CallWidget::backToWelcomePage() { - RecentModel::instance().selectionModel()->clear(); - disconnect(imConnection_); + deselectConversation(); + ui->stackedWidget->setCurrentWidget(ui->welcomePage); } -void CallWidget::hideMiniSpinner() +void +CallWidget::hideMiniSpinner() { if(ui->spinnerLabel->isVisible()){ miniSpinner_->stop(); @@ -960,97 +823,237 @@ CallWidget::on_shareButton_clicked() } void -CallWidget::contactLineEdit_registeredNameFound(Account* account,NameDirectory::LookupStatus status, - const QString& address,const QString& name) +CallWidget::on_sendContactRequestPageButton_clicked() { - URI uri = URI(ui->ringContactLineEdit->text()); - QString username_to_lookup = uri.userinfo(); + LRCInstance::getCurrentConversationModel()->makePermanent(selectedConvUid()); +} - if (username_to_lookup.compare(name) != 0){ - return; +void +CallWidget::on_sendCRBackButton_clicked() +{ + ui->stackedWidget->setCurrentWidget(ui->messagingPage); +} + +void +CallWidget::on_pendingCRBackButton_clicked() +{ + ui->stackedWidget->setCurrentWidget(ui->welcomePage); +} + +bool +CallWidget::connectConversationModel() +{ + auto currentConversationModel = LRCInstance::getCurrentAccountInfo().conversationModel.get(); + + if (ui->smartList->selectionModel()) { + ui->smartList->selectionModel()->setCurrentIndex(QModelIndex(), QItemSelectionModel::Deselect); } - switch (status) - { - case NameDirectory::LookupStatus::SUCCESS: - { - uri = URI("ring:" + address); - qDebug() << "contactLineEdit username to search: " << username_to_lookup; - qDebug() << uri; - searchContactLineEditEntry(uri); - auto cm = PhoneDirectoryModel::instance().getNumber(uri); - cm->setAccount(account); - break; + QObject::disconnect(modelSortedConnection_); + QObject::disconnect(modelUpdatedConnection_); + QObject::disconnect(filterChangedConnection_); + QObject::disconnect(newConversationConnection_); + QObject::disconnect(conversationRemovedConnection_); + QObject::disconnect(conversationClearedConnection); + QObject::disconnect(interactionStatusUpdatedConnection_); + QObject::disconnect(newInteractionConnection_); + + modelSortedConnection_ = QObject::connect( + currentConversationModel, &lrc::api::ConversationModel::modelSorted, + [this]() { + updateConversationsFilterWidget(); + selectSmartlistItem(selectedConvUid()); + ui->smartList->update(); } - case NameDirectory::LookupStatus::INVALID_NAME: - { - qDebug() << "Invalid Ring username"; - break; + ); + modelUpdatedConnection_ = QObject::connect( + currentConversationModel, &lrc::api::ConversationModel::conversationUpdated, + [this](const std::string& convUid) { + Q_UNUSED(convUid); + ui->smartList->update(); } - case NameDirectory::LookupStatus::ERROR: - case NameDirectory::LookupStatus::NOT_FOUND: - default: - { - qDebug() << "Could not resolve Ring username"; - break; + ); + filterChangedConnection_ = QObject::connect( + currentConversationModel, &lrc::api::ConversationModel::filterChanged, + [this]() { + updateSmartList(); + updateConversationsFilterWidget(); + ui->smartList->update(); } - } + ); + newConversationConnection_ = QObject::connect( + currentConversationModel, &lrc::api::ConversationModel::newConversation, + [this](const std::string& convUid) { + updateSmartList(); + updateConversationForNewContact(convUid); + ui->conversationsFilterWidget->update(); + } + ); + conversationRemovedConnection_ = QObject::connect( + currentConversationModel, &lrc::api::ConversationModel::conversationRemoved, + [this]() { + backToWelcomePage(); + } + ); + conversationClearedConnection = QObject::connect( + currentConversationModel, &lrc::api::ConversationModel::conversationCleared, + [this](const std::string& convUid) { + updateConversationView(convUid); + // if currently selected, + // switch to welcome screen (deselecting current smartlist item ) + if (convUid != selectedConvUid()) { + return; + } + backToWelcomePage(); + } + ); + interactionStatusUpdatedConnection_ = QObject::connect( + currentConversationModel, &lrc::api::ConversationModel::interactionStatusUpdated, + [this](const std::string& convUid) { + if (convUid != selectedConvUid()) { + return; + } + updateConversationView(convUid); + } + ); + newInteractionConnection_ = QObject::connect( + currentConversationModel, &lrc::api::ConversationModel::newInteraction, + [this](const std::string& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction) { + onIncomingMessage(convUid, interactionId, interaction); + } + ); + currentConversationModel->setFilter(""); + // clear search field + ui->ringContactLineEdit->setText(""); + return true; } void -CallWidget::on_sendContactRequestPageButton_clicked() +CallWidget::updateConversationView(const std::string& convUid) { - ui->sendContactRequestWidget->sendCR(RecentModel::instance().selectionModel()->currentIndex()); - // temporarly changed comportment waiting for message in payload implementation - /*ui->sendContactRequestWidget->setup(RecentModel::instance().selectionModel()->currentIndex()); - slidePage(ui->sendContactRequestPage);*/ + if (convUid != selectedConvUid()) { + return; + } + + auto& currentAccountInfo = LRCInstance::getCurrentAccountInfo(); + auto currentConversationModel = currentAccountInfo.conversationModel.get(); + currentConversationModel->clearUnreadInteractions(convUid); + ui->conversationsFilterWidget->update(); + auto currentConversation = Utils::getConversationFromUid(convUid, + *currentConversationModel); + if (currentConversation == currentConversationModel->allFilteredConversations().end()) { + return; + } + messageModel_.reset(new MessageModel(*currentConversation, currentAccountInfo, this->parent())); + ui->listMessageView->setModel(messageModel_.get()); + ui->listMessageView->scrollToBottom(); } void -CallWidget::on_sendCRBackButton_clicked() +CallWidget::selectConversation(const QModelIndex& index) { - ui->stackedWidget->setCurrentWidget(ui->messagingPage); + auto currentConversationModel = LRCInstance::getCurrentConversationModel(); + + if (currentConversationModel == nullptr || !index.isValid()) { + return; + } + + const auto item = currentConversationModel->filteredConversation(index.row()); + + if (selectConversation(item, *currentConversationModel)) { + auto convUid = selectedConvUid(); + if (!lastConvUid_.compare(convUid)) { + return; + } + lastConvUid_.assign(convUid); + auto currentConversationModel = LRCInstance::getCurrentConversationModel(); + auto callModel = LRCInstance::getCurrentCallModel(); + auto conversation = Utils::getConversationFromUid(convUid, *currentConversationModel); + const auto item = currentConversationModel->filteredConversation(index.row()); + if (callModel->hasCall(conversation->callId)) { + ui->stackedWidget->setCurrentWidget(ui->videoPage); + } + else { + showIMOutOfCall(index); + } + } } -void -CallWidget::on_pendingCRBackButton_clicked() +bool +CallWidget::selectConversation( const lrc::api::conversation::Info& item, + lrc::api::ConversationModel& convModel) { - ui->contactRequestList->selectionModel()->clear(); - ui->stackedWidget->setCurrentWidget(ui->welcomePage); + if (selectedConvUid() == item.uid) { + return false; + } else if (item.participants.size() > 0) { + convModel.selectConversation(item.uid); + LRCInstance::setSelectedConvId(item.uid); + convModel.clearUnreadInteractions(item.uid); + ui->conversationsFilterWidget->update(); + return true; + } } -Account* -CallWidget::getSelectedAccount() +void +CallWidget::deselectConversation() { - auto idx = AvailableAccountModel::instance().selectionModel()->currentIndex(); - if (idx.isValid()) { - auto ac = idx.data(static_cast<int>(Ring::Role::Object)).value<Account*>(); - return ac; + auto currentConversationModel = LRCInstance::getCurrentConversationModel(); + + if (currentConversationModel == nullptr) { + return; } - return nullptr; + + currentConversationModel->selectConversation(""); + LRCInstance::setSelectedConvId(""); + + ui->smartList->selectionModel()->clear(); + disconnect(imConnection_); } -bool -CallWidget::shouldDisplayInviteButton(ContactMethod &cm) +void +CallWidget::updateConversationForNewContact(const std::string& convUid) { - // Displaying the button for a SIP ContactMethod is a nonsense - if (cm.protocolHint() == URI::ProtocolHint::RING) { - // If we know that the other accepted us - if (cm.isConfirmed()) - return false; - - // If not sure, we still check if the contact method is linked to a - // Ring account or if the selected account is a RING one. - if(auto linkedAccount = cm.account()) - return linkedAccount->protocol() == Account::Protocol::RING; - else if (auto acc = getSelectedAccount()) - return acc->protocol() == Account::Protocol::RING; + auto convModel = LRCInstance::getCurrentConversationModel(); + if (convModel == nullptr) { + return; + } + ui->ringContactLineEdit->setText(""); + auto selectedUid = selectedConvUid(); + auto it = Utils::getConversationFromUid(convUid, *convModel); + if (it != convModel->allFilteredConversations().end()) { + try { + auto contact = convModel->owner.contactModel->getContact(it->participants[0]); + if (!contact.profileInfo.uri.empty() && contact.profileInfo.uri.compare(selectedUid) == 0) { + LRCInstance::setSelectedConvId(convUid); + convModel->selectConversation(convUid); + } + } catch (...) { + return; + } } - return false; } -void CallWidget::on_contactRequestList_clicked(const QModelIndex &index) +void +CallWidget::updateSmartList() { - RecentModel::instance().selectionModel()->clear(); - contactReqListCurrentChanged(index, QModelIndex()); + auto& currentAccountInfo = LRCInstance::getCurrentAccountInfo(); + smartListModel_.reset(new SmartListModel(currentAccountInfo, this->parent())); + ui->smartList->setModel(smartListModel_.get()); + ui->smartList->setItemDelegate(new ConversationItemDelegate()); + + // smartlist selection + QObject::disconnect(smartlistSelectionConnection_); + smartlistSelectionConnection_ = connect(ui->smartList->selectionModel(), + SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, + SLOT(smartListSelectionChanged(QItemSelection, QItemSelection))); } + +void +CallWidget::update() +{ + ui->currentAccountWidget->update(); + updateSmartList(); + updateConversationsFilterWidget(); + connectConversationModel(); +} \ No newline at end of file diff --git a/callwidget.h b/callwidget.h index f77d82e..9fb6178 100644 --- a/callwidget.h +++ b/callwidget.h @@ -1,8 +1,9 @@ /************************************************************************** -* Copyright (C) 2015-2017 by Savoir-faire Linux * +* Copyright (C) 2015-2018 by Savoir-faire Linux * * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * * Author: Olivier Soldano <olivier.soldano@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 * @@ -29,7 +30,9 @@ #include "navwidget.h" #include "instantmessagingwidget.h" +#include "smartlistmodel.h" +// old LRC #include "callmodel.h" #include "video/renderer.h" #include "video/previewmanager.h" @@ -37,7 +40,16 @@ #include "categorizedhistorymodel.h" #include "media/textrecording.h" -class SmartListDelegate; +// new LRC +#include "globalinstances.h" +#include "api/newaccountmodel.h" +#include "api/conversationmodel.h" +#include "api/account.h" +#include "api/contact.h" +#include "api/contactmodel.h" +#include "api/newcallmodel.h" + +class ConversationItemDelegate; class ImDelegate; class QPropertyAnimation; @@ -52,18 +64,22 @@ class CallWidget : public NavWidget public: explicit CallWidget(QWidget* parent = 0); ~CallWidget(); - void atExit(); bool findRingAccount(); public slots: - void settingsButtonClicked(); - void showIMOutOfCall(const QModelIndex& nodeIdx); - void btnComBarVideoClicked(); + void on_ringContactLineEdit_returnPressed(); -//UI SLOTS public slots: - void on_ringContactLineEdit_returnPressed(); - inline void on_entered(const QModelIndex& i){if (i.isValid()) highLightedIndex_ = i;} + void settingsButtonClicked(); + void showIMOutOfCall(const QModelIndex& nodeIdx); + void slotAcceptInviteClicked(const QModelIndex& index); + void slotBlockInviteClicked(const QModelIndex& index); + void slotIgnoreInviteClicked(const QModelIndex& index); + void slotCustomContextMenuRequested(const QPoint & pos); + void slotShowCallView(const std::string & accountId, const lrc::api::conversation::Info & convInfo); + void slotShowIncomingCallView(const std::string & accountId, const lrc::api::conversation::Info & convInfo); + void slotShowChatView(const std::string & accountId, const lrc::api::conversation::Info & convInfo); + void update(); private slots: void on_acceptButton_clicked(); @@ -82,55 +98,75 @@ private slots: void on_pendingCRBackButton_clicked(); private slots: - void callIncoming(Call* call); - void callStateChanged(Call* call, Call::State previousState); - void smartListCurrentChanged(const QModelIndex ¤tIdx, const QModelIndex &previousIdx); + void smartListSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void contactReqListCurrentChanged(const QModelIndex ¤tIdx, const QModelIndex &previousIdx); void slotAccountMessageReceived(const QMap<QString,QString> message,ContactMethod* cm, media::Media::Direction dir); - void onIncomingMessage(::media::TextRecording* t, ContactMethod* cm); - void callChangedSlot(); - void contactLineEdit_registeredNameFound(Account *account, NameDirectory::LookupStatus status, const QString& address, const QString& name); - void searchBtnClicked(); - void selectedAccountChanged(const QModelIndex ¤t, const QModelIndex &previous); - void on_contactMethodComboBox_currentIndexChanged(int index); - void on_contactRequestList_clicked(const QModelIndex &index); + void onIncomingMessage(const std::string & convUid, uint64_t interactionId, const lrc::api::interaction::Info & interaction); + void currentAccountChanged(const QModelIndex ¤t); private: - Ui::CallWidget* ui; - Call* actualCall_; - Video::Renderer* videoRenderer_; - CallModel* callModel_; - int outputVolume_; - int inputVolume_; + void placeCall(); + void conversationsButtonClicked(); + void invitationsButtonClicked(); + void setupOutOfCallIM(); + void setupSmartListContextMenu(const QPoint &pos); + void setupQRCode(QString ringID); + void backToWelcomePage(); + void triggerDeleteContactDialog(ContactMethod *cm, Account *ac); + + // lrc + void selectConversation(const QModelIndex& index); + bool selectConversation(const lrc::api::conversation::Info& item, + lrc::api::ConversationModel& convModel); + void deselectConversation(); + bool connectConversationModel(); + void updateConversationView(const std::string& convUid); + void showConversationView(); + void selectSmartlistItem(const std::string& convUid); + QImage imageForConv(const std::string & convUid); + void processContactLineEdit(); + void hideMiniSpinner(); + void updateConversationForNewContact(const std::string& convUid); + void updateSmartList(); + void setSelectedAccount(const std::string & accountId); + void setConversationFilter(const QString& filter); + void setConversationFilter(lrc::api::profile::Type filter); + void updateConversationsFilterWidget(); + const std::string& selectedAccountId(); + const std::string& selectedConvUid(); + QMenu* menu_; - SmartListDelegate* smartListDelegate_; - QPersistentModelIndex highLightedIndex_; + ConversationItemDelegate* conversationItemDelegate_; ImDelegate* imDelegate_; + QMetaObject::Connection imConnection_; QMetaObject::Connection imVisibleConnection_; QMetaObject::Connection callChangedConnection_; QMetaObject::Connection imClickedConnection_; QMetaObject::Connection crListSelectionConnection_; - QPropertyAnimation* pageAnim_; - QMenu* shareMenu_; + + Ui::CallWidget* ui; QMovie* miniSpinner_; constexpr static int qrSize_ = 200; -private: - void setActualCall(Call* value); - void placeCall(); - void setupOutOfCallIM(); - void setupSmartListMenu(const QPoint &pos); - void slidePage(QWidget* widget, bool toRight = false); - void callStateToView(Call* value); - void setupQRCode(QString ringID); - void searchContactLineEditEntry(const URI &uri); - bool uriNeedNameLookup(const URI uri_passed); - void processContactLineEdit(); - static Account* getSelectedAccount(); - static bool shouldDisplayInviteButton(ContactMethod& cm); - void backToWelcomePage(); - void hideMiniSpinner(); - void triggerDeleteContactDialog(ContactMethod *cm, Account *ac); + // lrc + Video::Renderer* videoRenderer_; + std::string lastConvUid_ {}; + lrc::api::profile::Type currentTypeFilter_{}; + + std::unique_ptr<SmartListModel> smartListModel_; + std::unique_ptr<MessageModel> messageModel_; + QMetaObject::Connection modelSortedConnection_; + QMetaObject::Connection modelUpdatedConnection_; + QMetaObject::Connection filterChangedConnection_; + QMetaObject::Connection newConversationConnection_; + QMetaObject::Connection conversationRemovedConnection_; + QMetaObject::Connection newInteractionConnection_; + QMetaObject::Connection interactionStatusUpdatedConnection_; + QMetaObject::Connection conversationClearedConnection; + QMetaObject::Connection selectedCallChanged_; + QMetaObject::Connection smartlistSelectionConnection_; + + }; diff --git a/callwidget.ui b/callwidget.ui index 7b7031a..1efddad 100644 --- a/callwidget.ui +++ b/callwidget.ui @@ -112,7 +112,7 @@ <number>0</number> </property> <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_2" stretch="3,1,18"> + <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0"> <property name="spacing"> <number>0</number> </property> @@ -122,7 +122,7 @@ <item> <widget class="CurrentAccountWidget" name="currentAccountWidget" native="true"> <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -130,23 +130,32 @@ <property name="minimumSize"> <size> <width>0</width> - <height>100</height> + <height>60</height> </size> </property> </widget> </item> <item> <widget class="QWidget" name="selectBar" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="maximumSize"> <size> - <width>324</width> - <height>16777215</height> + <width>16777214</width> + <height>30</height> </size> </property> - <layout class="QHBoxLayout" name="horizontalLayout_4"> + <layout class="QHBoxLayout" name="selectBar_layout" stretch="0,0,0"> <property name="spacing"> <number>0</number> </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> <property name="leftMargin"> <number>0</number> </property> @@ -169,7 +178,7 @@ </property> <property name="sizeHint" stdset="0"> <size> - <width>16</width> + <width>10</width> <height>38</height> </size> </property> @@ -181,14 +190,14 @@ <bool>true</bool> </property> <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> - <width>244</width> + <width>266</width> <height>30</height> </size> </property> @@ -203,6 +212,9 @@ <pointsize>9</pointsize> </font> </property> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> <property name="toolTip"> <string>Search contact text input</string> </property> @@ -221,7 +233,7 @@ </widget> </item> <item> - <spacer name="horizontalSpacer_3"> + <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> @@ -231,35 +243,36 @@ <property name="sizeHint" stdset="0"> <size> <width>10</width> - <height>20</height> + <height>38</height> </size> </property> </spacer> </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="smartListWidget" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,0,0"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>1</number> + </property> + <property name="topMargin"> + <number>1</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>1</number> + </property> <item> - <widget class="QPushButton" name="searchBtn"> - <property name="minimumSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - <property name="toolTip"> - <string>search button</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_search_black_18dp_2x.png</normaloff>:/images/icons/ic_search_black_18dp_2x.png</iconset> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_2"> + <spacer name="verticalSpacer_3"> <property name="orientation"> - <enum>Qt::Horizontal</enum> + <enum>Qt::Vertical</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Fixed</enum> @@ -267,159 +280,76 @@ <property name="sizeHint" stdset="0"> <size> <width>20</width> - <height>20</height> + <height>10</height> </size> </property> </spacer> </item> - </layout> - </widget> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout_5" stretch="0"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QTabWidget" name="mainTabMenu"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="toolTip"> - <string/> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <widget class="QWidget" name="mainTabMenuPage1"> - <attribute name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_chat_black_24dp_2x.png</normaloff>:/images/icons/ic_chat_black_24dp_2x.png</iconset> - </attribute> - <attribute name="title"> - <string/> - </attribute> - <attribute name="toolTip"> - <string>Conversations</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <widget class="ConversationsFilterWidget" name="conversationsFilterWidget" native="true"> + <layout class="QHBoxLayout" name="conversationFilterLayout"> <property name="spacing"> - <number>0</number> + <number>10</number> </property> <property name="leftMargin"> - <number>0</number> + <number>10</number> </property> <property name="topMargin"> - <number>0</number> + <number>10</number> </property> <property name="rightMargin"> - <number>0</number> + <number>10</number> </property> <property name="bottomMargin"> - <number>0</number> + <number>10</number> </property> <item> - <widget class="SmartList" name="smartList"> - <property name="minimumSize"> - <size> - <width>324</width> - <height>0</height> - </size> - </property> - <property name="mouseTracking"> - <bool>true</bool> - </property> - <property name="indentation"> - <number>0</number> + <widget class="QPushButton" name="buttonConversations"> + <property name="toolTip"> + <string>Show conversations</string> </property> - <property name="headerHidden"> - <bool>true</bool> + <property name="text"> + <string>Conversations</string> </property> - <attribute name="headerMinimumSectionSize"> - <number>0</number> - </attribute> </widget> </item> - </layout> - </widget> - <widget class="QWidget" name="mainTabMenuPage2"> - <attribute name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_person_add_black_24dp_2x.png</normaloff>:/images/icons/ic_person_add_black_24dp_2x.png</iconset> - </attribute> - <attribute name="title"> - <string/> - </attribute> - <attribute name="toolTip"> - <string>Contact requests</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_7"> - <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="ContactRequestListWidget" name="contactRequestList"> - <property name="styleSheet"> - <string notr="true"/> + <widget class="QPushButton" name="buttonInvites"> + <property name="toolTip"> + <string>Show invites</string> </property> - <property name="rootIsDecorated"> - <bool>false</bool> + <property name="text"> + <string>Invites</string> </property> - <attribute name="headerVisible"> - <bool>false</bool> - </attribute> - <attribute name="headerMinimumSectionSize"> - <number>0</number> - </attribute> </widget> </item> </layout> </widget> - </widget> - </item> - </layout> + </item> + <item> + <widget class="SmartListView" name="smartList"> + <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> + </widget> + </item> + </layout> + </widget> </item> </layout> </item> @@ -490,7 +420,7 @@ <string/> </property> <property name="currentIndex"> - <number>0</number> + <number>2</number> </property> <widget class="QWidget" name="welcomePage"> <layout class="QVBoxLayout" name="verticalLayout_15"> @@ -677,8 +607,10 @@ <string notr="true">color: #aeaeae</string> </property> <property name="text"> - <string>This is your RingID. -Copy and share it with your friends!</string> + <string> + This is your RingID. + Copy and share it with your friends! + </string> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> @@ -1033,7 +965,7 @@ Copy and share it with your friends!</string> <verstretch>0</verstretch> </sizepolicy> </property> - <layout class="QVBoxLayout" name="verticalLayout_12" stretch="1,25,25,1"> + <layout class="QVBoxLayout" name="verticalLayout_12" stretch="1,25,1"> <property name="leftMargin"> <number>5</number> </property> @@ -1177,19 +1109,6 @@ Copy and share it with your friends!</string> </property> </spacer> </item> - <item> - <widget class="QComboBox" name="contactMethodComboBox"> - <property name="minimumSize"> - <size> - <width>160</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Peer contact method selector</string> - </property> - </widget> - </item> <item> <widget class="QPushButton" name="sendContactRequestPageButton"> <property name="sizePolicy"> @@ -1221,23 +1140,6 @@ Copy and share it with your friends!</string> </item> </layout> </item> - <item alignment="Qt::AlignHCenter|Qt::AlignVCenter"> - <widget class="QLabel" name="noMessagesLabel"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>Start the conversation !</string> - </property> - </widget> - </item> <item> <widget class="QListView" name="listMessageView"> <property name="sizePolicy"> @@ -1918,9 +1820,9 @@ Copy and share it with your friends!</string> <header>idlabel.h</header> </customwidget> <customwidget> - <class>SmartList</class> + <class>SmartListView</class> <extends>QTreeView</extends> - <header>smartlist.h</header> + <header>smartlistview.h</header> </customwidget> <customwidget> <class>SendContactRequestWidget</class> @@ -1941,9 +1843,10 @@ Copy and share it with your friends!</string> <container>1</container> </customwidget> <customwidget> - <class>ContactRequestListWidget</class> - <extends>QTreeView</extends> - <header>contactrequestlistwidget.h</header> + <class>ConversationsFilterWidget</class> + <extends>QWidget</extends> + <header>conversationsfilterwidget.h</header> + <container>1</container> </customwidget> </customwidgets> <resources> diff --git a/combar.ui b/combar.ui deleted file mode 100644 index 8b9e661..0000000 --- a/combar.ui +++ /dev/null @@ -1,95 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ComBar</class> - <widget class="QWidget" name="ComBar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>578</width> - <height>112</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="windowTitle"> - <string/> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <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>5</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="btnComBarVideo"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - <property name="toolTip"> - <string>Call button</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_videocam_white.png</normaloff>:/images/icons/ic_videocam_white.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>18</width> - <height>18</height> - </size> - </property> - </widget> - </item> - </layout> - </widget> - <resources> - <include location="ressources.qrc"/> - </resources> - <connections/> -</ui> diff --git a/configurationwidget.cpp b/configurationwidget.cpp index 67e9388..81f9b55 100644 --- a/configurationwidget.cpp +++ b/configurationwidget.cpp @@ -77,9 +77,6 @@ ConfigurationWidget::ConfigurationWidget(QWidget *parent) : } accountModel_->save(); accountDetails_->save(); - }); - - connect(ui->exitSettingsButton, &QPushButton::clicked, this, [=]() { emit NavigationRequested(ScreenEnum::CallScreen); }); diff --git a/contactmethodpicker.cpp b/contactmethodpicker.cpp deleted file mode 100644 index 9d7d11a..0000000 --- a/contactmethodpicker.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015-2017 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 * - * 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 "contactmethodpicker.h" -#include "ui_contactmethodpicker.h" - -#include "contactmethod.h" - -ContactMethodPicker::ContactMethodPicker(const Person::ContactMethods& cM, QWidget *parent) : - QDialog(parent), - ui(new Ui::ContactMethodPicker), - contactMethods_(cM) -{ - ui->setupUi(this); - - this->setWindowFlags(Qt::CustomizeWindowHint); - this->setWindowFlags(Qt::FramelessWindowHint | Qt::Popup); - - for (auto contactMethod : cM) { - auto item = new QListWidgetItem(); - item->setText(contactMethod->uri()); - ui->contactMethodListWidget->addItem(item); - } -} - -ContactMethodPicker::~ContactMethodPicker() -{ - delete ui; -} - -void -ContactMethodPicker::on_contactMethodListWidget_clicked(const QModelIndex &index) -{ - index_ = index.row(); - accept(); -} - -ContactMethod* -ContactMethodPicker::getSelected() const -{ - return contactMethods_.at(index_); -} diff --git a/contactmethodpicker.h b/contactmethodpicker.h deleted file mode 100644 index 489ab98..0000000 --- a/contactmethodpicker.h +++ /dev/null @@ -1,49 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015-2017 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 * - * 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 "person.h" -#include "personmodel.h" - -namespace Ui { -class ContactMethodPicker; -} - -class ContactMethodPicker final : public QDialog -{ - Q_OBJECT - -public: - explicit ContactMethodPicker(const Person::ContactMethods &cM, QWidget *parent = 0); - ~ContactMethodPicker(); - - ContactMethod* getSelected() const; - -//UI SLOTS -private slots: - void on_contactMethodListWidget_clicked(const QModelIndex &index); - -private: - Ui::ContactMethodPicker *ui; - const Person::ContactMethods& contactMethods_; - int index_; -}; - diff --git a/contactmethodpicker.ui b/contactmethodpicker.ui deleted file mode 100644 index 338d2df..0000000 --- a/contactmethodpicker.ui +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ContactMethodPicker</class> - <widget class="QDialog" name="ContactMethodPicker"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>93</width> - <height>93</height> - </rect> - </property> - <property name="windowTitle"> - <string/> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <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="QListWidget" name="contactMethodListWidget"/> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/contactrequestitemdelegate.cpp b/contactrequestitemdelegate.cpp deleted file mode 100644 index 6e6d9f6..0000000 --- a/contactrequestitemdelegate.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2017 by Savoir-faire Linux * - * Author: Anthony Léonard <anthony.leonard@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 "contactrequestitemdelegate.h" -#include "ringthemeutils.h" - -#include "accountmodel.h" -#include "pendingcontactrequestmodel.h" -#include "contactrequest.h" -#include "globalinstances.h" -#include "pixmapmanipulatordefault.h" - -#include <QPainter> -#include <QApplication> - -#include <ciso646> - -ContactRequestItemDelegate::ContactRequestItemDelegate(QObject* parent) : - QItemDelegate(parent) -{} - -void -ContactRequestItemDelegate::paint(QPainter* painter - , const QStyleOptionViewItem& option - , const QModelIndex& index - ) const -{ - painter->setRenderHint(QPainter::Antialiasing); - - QStyleOptionViewItem opt(option); - - // Not having focus removes dotted lines around the item - if (opt.state & QStyle::State_HasFocus) - opt.state ^= QStyle::State_HasFocus; - - // First, we draw the control itself - QStyle* style = opt.widget ? opt.widget->style() : QApplication::style(); - style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); - - bool selected = false; - if (option.state & QStyle::State_Selected) { - selected = true; - opt.state ^= QStyle::State_Selected; - painter->fillRect(option.rect, RingTheme::smartlistSelection_); - } - else if (option.state & QStyle::State_MouseOver) { - painter->fillRect(option.rect, RingTheme::smartlistHighlight_); - } - - // Then, we print the text - QFont font(painter->font()); - font.setPointSize(10); - font.setBold(true); - painter->setFont(font); - - QFontMetrics fontMetrics(font); - - QRect rectText(opt.rect); - rectText.setLeft(opt.rect.left() + dxText_); - rectText.setTop(opt.rect.top() + dyText_); - rectText.setBottom(rectText.top() + fontMetrics.height()); - - QString text(index.data().toString()); - text = fontMetrics.elidedText(text, Qt::ElideRight, rectText.width()); - - QPen pen(painter->pen()); - - pen.setColor(RingTheme::lightBlack_); - painter->setPen(pen); - - painter->drawText(rectText,text); - - // Draw the picture from the vCard - QRect rectPic(opt.rect.left() + dxImage_, opt.rect.top() + dyImage_, sizeImage_, sizeImage_); - auto cr = index.data(static_cast<int>(Ring::Role::Object)).value<ContactRequest*>(); - auto photo = GlobalInstances::pixmapManipulator().contactPhoto(cr->peer(), QSize(sizeImage_, sizeImage_), false); - drawDecoration(painter, opt, rectPic, QPixmap::fromImage(photo.value<QImage>())); -} - -QSize -ContactRequestItemDelegate::sizeHint(const QStyleOptionViewItem& option - , const QModelIndex& index - ) const -{ - QSize size = QItemDelegate::sizeHint(option, index); - size.setHeight(cellHeight_); - return size; -} diff --git a/contactrequestlistwidget.cpp b/contactrequestlistwidget.cpp deleted file mode 100644 index 1e74d39..0000000 --- a/contactrequestlistwidget.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/************************************************************************** -* Copyright (C) 2015-2017 by Savoir-faire Linux * -* Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * -* Author: Olivier Soldano <olivier.soldano@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 "contactrequestlistwidget.h" - -//LRC -#include "contactrequest.h" -#include "pendingcontactrequestmodel.h" -#include "itemdataroles.h" - -//CLIENT -#include "quickactcontactrequestwidget.h" -#include <QScrollBar> -#include <QAbstractItemView> -#include <QEvent> - -#include <ciso646> - -ContactRequestListWidget::ContactRequestListWidget(QWidget *parent) : - QTreeView(parent) -{ - // for hover detection - setMouseTracking(true); - - //connects the entered signal to the creation and display of hovering widget - connect(this, &QAbstractItemView::entered, [this](const QModelIndex & index) { - //get current hovered row quick action widget - auto widget = indexWidget(index); - //build and add hovering quick action widget to row and display, if already built just display - if (!widget) { - QuickActContactRequestWidget* quickBtns = new QuickActContactRequestWidget(); - setIndexWidget(index, quickBtns); - connect(quickBtns, &QuickActContactRequestWidget::quickValidCRBtnClicked, - this, - [=](){ model()->data(index, static_cast<int>(Ring::Role::Object)).value<ContactRequest*>()->accept(); }); - - connect(quickBtns, &QuickActContactRequestWidget::quickMuteCRBtnClicked, - this, - [=](){ model()->data(index, static_cast<int>(Ring::Role::Object)).value<ContactRequest*>()->discard(); }); - - connect(quickBtns, &QuickActContactRequestWidget::quickBanCRBtnClicked, - this, - [=](){ model()->data(index, static_cast<int>(Ring::Role::Object)).value<ContactRequest*>()->block(); }); - } - else if (index.isValid()){ - indexWidget(index)->setVisible(true); - } - - //hide previously shown hover widget (if any) - if(hoveredCRIndex_.isValid() and indexWidget(hoveredCRIndex_)) - indexWidget(hoveredCRIndex_)->setVisible(false); - - //update current hovered index - hoveredCRIndex_ = index; - }); -} - -ContactRequestListWidget::~ContactRequestListWidget() -{ -} - -void -ContactRequestListWidget::setItemModel(QAbstractItemModel *model) -{ - setModel(model); - - // Hide unused columns - for(int column = 1; column < model->columnCount(); column++){ - hideColumn(column); - } -} - - -void -ContactRequestListWidget::enterEvent(QEvent* event) -{ - Q_UNUSED(event); - verticalScrollBar()->show(); -} - -void -ContactRequestListWidget::leaveEvent(QEvent* event) -{ - Q_UNUSED(event); - - hoveredCRIndex_ = QModelIndex(); - verticalScrollBar()->hide(); -} - -bool -ContactRequestListWidget::eventFilter(QObject* watched, QEvent* event) -{ - if (qobject_cast<QScrollBar*>(watched) && event->type() == QEvent::Enter) { - hoveredCRIndex_ = QModelIndex(); - return true; - } - - return QObject::eventFilter(watched, event); -} - - -void -ContactRequestListWidget::drawRow(QPainter* painter, - const QStyleOptionViewItem& option, const QModelIndex& index) const -{ - if(index == hoveredCRIndex_ && indexWidget(hoveredCRIndex_)) - indexWidget(index)->setVisible(true); - else if(indexWidget(index)) - indexWidget(index)->setVisible(false); - - QTreeView::drawRow(painter, option, index); -} diff --git a/contactrequestlistwidget.h b/contactrequestlistwidget.h deleted file mode 100644 index 4dc61e3..0000000 --- a/contactrequestlistwidget.h +++ /dev/null @@ -1,44 +0,0 @@ -/************************************************************************** -* Copyright (C) 2015-2017 by Savoir-faire Linux * -* Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * -* Author: Olivier Soldano <olivier.soldano@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/>. * -**************************************************************************/ - -#ifndef CONTACTREQUESTLISTWIDGET_H -#define CONTACTREQUESTLISTWIDGET_H - -#include <QTreeView> - -class ContactRequestListWidget : public QTreeView -{ - Q_OBJECT - -public: - explicit ContactRequestListWidget(QWidget *parent = 0); - ~ContactRequestListWidget(); - void setItemModel(QAbstractItemModel *model); - -private: - QModelIndex hoveredCRIndex_; - -protected: - void enterEvent(QEvent *event); - void leaveEvent(QEvent *event); - bool eventFilter(QObject *watched, QEvent *event); - void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; -}; - -#endif // CONTACTREQUESTLISTWIDGET_H diff --git a/conversationitemdelegate.cpp b/conversationitemdelegate.cpp new file mode 100644 index 0000000..f260519 --- /dev/null +++ b/conversationitemdelegate.cpp @@ -0,0 +1,307 @@ +/*************************************************************************** + * Copyright (C) 2015-2017 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 "conversationitemdelegate.h" + +#include <QApplication> +#include <QPainter> +#include <QPixmap> +#include <QDebug> + +// Client +#include "smartlistmodel.h" +#include "ringthemeutils.h" +#include "utils.h" + +#include <ciso646> + +ConversationItemDelegate::ConversationItemDelegate(QObject* parent) : + QItemDelegate(parent) +{ +} + +void +ConversationItemDelegate::paint(QPainter* painter + , const QStyleOptionViewItem& option + , const QModelIndex& index + ) const +{ + QStyleOptionViewItem opt(option); + painter->setRenderHint(QPainter::Antialiasing); + + // Not having focus removes dotted lines around the item + if (opt.state & QStyle::State_HasFocus) + opt.state ^= QStyle::State_HasFocus; + + // First, we draw the control itself + QStyle* style = opt.widget ? opt.widget->style() : QApplication::style(); + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); + + auto isContextMenuOpen = index.data(static_cast<int>(SmartListModel::Role::ContextMenuOpen)).value<bool>(); + bool selected = false; + if (option.state & QStyle::State_Selected) { + selected = true; + opt.state ^= QStyle::State_Selected; + } else if (!isContextMenuOpen) { + if (option.state & QStyle::State_MouseOver) { + highlightMap_[index.row()] = true; + } else { + highlightMap_[index.row()] = false; + } + } + + // One does not simply keep the highlighted state drawn when the context + // menu is open� + auto rowHighlight = highlightMap_.find(index.row()); + if (selected) { + painter->fillRect(option.rect, RingTheme::smartlistSelection_); + } else if (rowHighlight != highlightMap_.end() && (*rowHighlight).second) { + painter->fillRect(option.rect, 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()); + + // If there's unread messages, a message count is displayed + if (auto messageCount = index.data(static_cast<int>(SmartListModel::Role::UnreadMessagesCount)).toInt()) { + QString messageCountText = (messageCount > 9) ? "9+" : QString::number(messageCount); + qreal fontSize = messageCountText.count() > 1 ? 7 : 8; + font.setPointSize(fontSize); + + // ellipse + QPainterPath ellipse; + qreal ellipseHeight = sizeImage_ / 6; + qreal ellipseWidth = ellipseHeight; + QPointF ellipseCenter(rectAvatar.right() - ellipseWidth, rectAvatar.top() + ellipseHeight + 1); + QRect ellipseRect(ellipseCenter.x() - ellipseWidth, ellipseCenter.y() - ellipseHeight, + ellipseWidth * 2, ellipseHeight * 2); + ellipse.addRoundedRect(ellipseRect, ellipseWidth, ellipseHeight); + painter->fillPath(ellipse, RingTheme::notificationRed_); + + // text + painter->setPen(Qt::white); + painter->setOpacity(1); + painter->setFont(font); + ellipseRect.setTop(ellipseRect.top() - 2); + painter->drawText(ellipseRect, Qt::AlignCenter, messageCountText); + } + + // 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, (rectAvatar.bottom() - radius) + 1); + qreal outerCRadius = radius; + qreal innerCRadius = outerCRadius * 0.75; + outerCircle.addEllipse(center, outerCRadius, outerCRadius); + innerCircle.addEllipse(center, innerCRadius, innerCRadius); + painter->fillPath(outerCircle, Qt::white); + 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: + paintRingConversationItem(painter, option, rect, index); + break; + case profile::Type::PENDING: + paintRingInviteConversationItem(painter, option, rect, index); + break; + case profile::Type::SIP: + break; + default: + paintRingConversationItem(painter, option, rect, index); + break; + } +} + +QSize +ConversationItemDelegate::sizeHint(const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + return QSize(0, cellHeight_); +} + +void +ConversationItemDelegate::paintRingConversationItem(QPainter* painter, + const QStyleOptionViewItem& option, + const QRect& rect, + const QModelIndex& index) const +{ + QFont font(painter->font()); + font.setPointSize(fontSize_); + QPen pen(painter->pen()); + painter->setPen(pen); + + auto leftMargin = dx_ + sizeImage_ + dx_ / 2; + auto rightMargin = dx_; + auto topMargin = 0; + auto bottomMargin = 12; + + QRect rectName1(rect.left() + leftMargin, + rect.top() + topMargin, + rect.width() - leftMargin - infoTextWidth_, + rect.height() / 2); + + QRect rectName2(rectName1.left(), + rectName1.top() + rectName1.height(), + rectName1.width(), + rectName1.height() - bottomMargin); + + QRect rectInfo1(rectName1.left() + rectName1.width(), + rect.top() + topMargin, + infoTextWidth_ - rightMargin, + rect.height() / 2); + + QRect rectInfo2(rectInfo1.left(), + rectInfo1.top() + rectInfo1.height(), + rectInfo1.width(), + rectInfo1.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(true); + 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); + } + + // top-right: last interaction date/time + QString lastUsedStr = index.data(static_cast<int>(SmartListModel::Role::LastInteractionDate)).value<QString>(); + if (!lastUsedStr.isNull()) { + font.setItalic(false); + font.setBold(false); + pen.setColor(RingTheme::grey_); + painter->setPen(pen); + painter->setFont(font); + lastUsedStr = fontMetrics.elidedText(lastUsedStr, Qt::ElideRight, rectInfo1.width()); + painter->drawText(rectInfo1, Qt::AlignVCenter | Qt::AlignRight, lastUsedStr); + } + + // bottom-right: last interaction snippet + QString interactionStr = index.data(static_cast<int>(SmartListModel::Role::LastInteraction)).value<QString>(); + if (!interactionStr.isNull()) { + // remove phone glyphs + interactionStr.replace(QChar(0xd83d), ""); + interactionStr.replace(QChar(0xdd7d), ""); + interactionStr.replace(QChar(0xdcde), ""); + + font.setItalic(false); + font.setBold(false); + pen.setColor(RingTheme::grey_); + painter->setPen(pen); + painter->setFont(font); + interactionStr = fontMetrics.elidedText(interactionStr, Qt::ElideRight, rectInfo2.width()); + painter->drawText(rectInfo2, Qt::AlignVCenter | Qt::AlignRight, interactionStr); + } +} + +void +ConversationItemDelegate::paintRingInviteConversationItem(QPainter* painter, + const QStyleOptionViewItem& option, + const QRect& rect, + const QModelIndex& index) const +{ + QFont font(painter->font()); + font.setPointSize(fontSize_); + QPen pen(painter->pen()); + painter->setPen(pen); + + auto leftMargin = dx_ + sizeImage_ + dx_ / 2; + auto rightMargin = dx_; + if (option.state & QStyle::State_MouseOver) { + rightMargin = infoTextWidth_ - dx_ * 2; + } + auto topMargin = 0; + auto bottomMargin = 12; + + QRect rectName1(rect.left() + leftMargin, + rect.top() + topMargin, + rect.width() - leftMargin - rightMargin, + rect.height() / 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(true); + 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 +ConversationItemDelegate::paintSIPConversationItem(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const +{ +} diff --git a/contactrequestitemdelegate.h b/conversationitemdelegate.h similarity index 61% rename from contactrequestitemdelegate.h rename to conversationitemdelegate.h index 2d059e3..249d77b 100644 --- a/contactrequestitemdelegate.h +++ b/conversationitemdelegate.h @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2017 by Savoir-faire Linux * - * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * + * Copyright (C) 2015-2017 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 * * it under the terms of the GNU General Public License as published by * @@ -14,30 +14,36 @@ * * * 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 ContactRequestItemDelegate : public QItemDelegate +class QPainter; + +class ConversationItemDelegate : public QItemDelegate { + Q_OBJECT public: - ContactRequestItemDelegate(QObject* parent = 0); + explicit ConversationItemDelegate(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: - constexpr static int cellHeight_ = 60; - constexpr static int sizeImage_ = 48; - constexpr static int dxImage_ = 16; - constexpr static int dyImage_ = 6; + void paintRingConversationItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const; + void paintRingInviteConversationItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const; + void paintSIPConversationItem(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; - constexpr static int dxText_ = dxImage_ + sizeImage_ + 12; - constexpr static int dyText_ = 13; + constexpr static int sizeImage_ = 48; + constexpr static int cellHeight_ = 60; + constexpr static int dy_ = 6; + constexpr static int dx_ = 12; + constexpr static int fontSize_ = 10; + constexpr static int infoTextWidth_ = 144; - constexpr static int separatorYPadding_ = 20; + mutable std::map<int, bool> highlightMap_; }; diff --git a/conversationsfilterwidget.cpp b/conversationsfilterwidget.cpp new file mode 100644 index 0000000..07abdf5 --- /dev/null +++ b/conversationsfilterwidget.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2018 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 "conversationsfilterwidget.h" + +#include "ringthemeutils.h" + +#include <QPainter> + +static inline const QRect +getNotifierRect(const QRect& buttonRect) +{ + qreal radius = 8; + QPointF ellipseCenter(buttonRect.right() - radius * 2, buttonRect.top()); + return QRect(ellipseCenter.x() - radius, ellipseCenter.y() - radius, radius * 2, radius * 2); +} + +void +ConversationsFilterWidget::handleNotifierOverlay(const QString& buttonName, + SmartlistSelectorButtonNotifier*& notifier, + lrc::api::profile::Type filter) +{ + auto button = this->findChild<QPushButton*>(buttonName); + if (!button) { + return; + } + if (!notifier) { + notifier = new SmartlistSelectorButtonNotifier(this); + button->stackUnder(notifier); + notifier->setTypeFilter(filter); + notifier->hide(); + QObject::connect(notifier, SIGNAL(clicked()), button, SLOT(click())); + } else { + notifier->setGeometry(getNotifierRect(button->frameGeometry())); + notifier->show(); + } +} + +ConversationsFilterWidget::ConversationsFilterWidget(QWidget *parent) + : QWidget(parent) +{ +} + +void ConversationsFilterWidget::paintEvent(QPaintEvent * event) +{ + QWidget::paintEvent(event); + + using namespace lrc::api::profile; + handleNotifierOverlay("buttonConversations", unreadMessagesNotifier_, Type::RING); + handleNotifierOverlay("buttonInvites", pendingInvitesNotifier_, Type::PENDING); +} diff --git a/quickactcontactrequestwidget.h b/conversationsfilterwidget.h similarity index 62% rename from quickactcontactrequestwidget.h rename to conversationsfilterwidget.h index b74c292..1ce9eef 100644 --- a/quickactcontactrequestwidget.h +++ b/conversationsfilterwidget.h @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * - * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> * + * Copyright (C) 2018 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 * @@ -15,32 +15,27 @@ * 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 -#ifndef QUICKACTCONTACTREQUESTWIDGET_H -#define QUICKACTCONTACTREQUESTWIDGET_H +#include "api/profile.h" +#include "smartlistselectorbuttonnotifier.h" #include <QWidget> - -namespace Ui { -class QuickActContactRequestWidget; -} - -class QuickActContactRequestWidget : public QWidget -{ - Q_OBJECT - -public: - explicit QuickActContactRequestWidget(QWidget *parent = 0); - ~QuickActContactRequestWidget(); - -signals: - void quickValidCRBtnClicked(); - void quickMuteCRBtnClicked(); - void quickBanCRBtnClicked(); - -private: - Ui::QuickActContactRequestWidget *ui; -}; - -#endif // QUICKACTCONTACTREQUESTWIDGET_H +class ConversationsFilterWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ConversationsFilterWidget(QWidget *parent = 0); + +protected: + virtual void paintEvent(QPaintEvent *event); + +private: + void handleNotifierOverlay(const QString& buttonName, + SmartlistSelectorButtonNotifier*& notifier, + lrc::api::profile::Type filter); + SmartlistSelectorButtonNotifier* unreadMessagesNotifier_{ nullptr }; + SmartlistSelectorButtonNotifier* pendingInvitesNotifier_{ nullptr }; +}; \ No newline at end of file diff --git a/currentaccountwidget.cpp b/currentaccountwidget.cpp index 9693217..a339061 100644 --- a/currentaccountwidget.cpp +++ b/currentaccountwidget.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2015-2017 by Savoir-faire Linux * * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * * Author: Olivier Soldano <olivier.soldano@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 * @@ -19,6 +20,7 @@ #include "currentaccountwidget.h" #include "ui_currentaccountwidget.h" + #include "globalinstances.h" #include "availableaccountmodel.h" #include "account.h" @@ -26,15 +28,36 @@ #include "profilemodel.h" #include "profile.h" #include "person.h" + #include "utils.h" -#include "globalinstances.h" +#include "lrcinstance.h" +#include "pixbufmanipulator.h" CurrentAccountWidget::CurrentAccountWidget(QWidget *parent) : QWidget(parent), ui(new Ui::CurrentAccountWidget) { ui->setupUi(this); - setup(); + + accountListModel_ = std::make_unique<AccountListModel>(); + ui->currentAccountSelector->setModel(accountListModel_.get()); + accountItemDelegate_ = new AccountItemDelegate(); + ui->currentAccountSelector->setItemDelegate(accountItemDelegate_); + + connect(&LRCInstance::accountModel(), + &lrc::api::NewAccountModel::accountAdded, + [this](const std::string& accountId) { + auto accountList = LRCInstance::accountModel().getAccountList(); + auto it = std::find(accountList.begin(), accountList.end(), accountId); + if (it != accountList.end()) { + auto index = std::distance(accountList.begin(), it); + // newly created account + // index should be 0 + QModelIndex idx = ui->currentAccountSelector->model()->index(index, 0); + emit currentAccountChanged(idx); + update(); + } + }); } CurrentAccountWidget::~CurrentAccountWidget() @@ -42,81 +65,42 @@ CurrentAccountWidget::~CurrentAccountWidget() delete ui; } -void -CurrentAccountWidget::setup() -{ - ui->accountsStatus->setText("No enabled account: impossible to communicate!"); - ui->accountsStatus->hide(); - ui->currentAccountSelector->setModel(&AvailableAccountModel::instance()); - updateAccounts(); - if (ui->currentAccountSelector->count() > 0) { - ui->currentAccountSelector->setCurrentIndex(0); - qDebug() << "CurrentAccount : setup over"; - } else { - qDebug() << "CurrentAccount : No account available"; - } -} - void CurrentAccountWidget::update() { - updateAccounts(); - -} - -void -CurrentAccountWidget::updateAccounts() -{ - auto selector = ui->currentAccountSelector; - - if (selector->count() <= 1){ - selector->hide(); - if (selector->count() < 1) { - ui->accountsStatus->show(); - setPhoto(); - } else { - ui->accountsStatus->hide(); - } + if (ui->currentAccountSelector->count() <= 1) { + ui->currentAccountSelector->setEnabled(false); + ui->currentAccountSelector->setStyleSheet( + "QComboBox:disabled{color: black;}" + "QComboBox{border:0;}" + "QComboBox::down-arrow{image:url('none');}" + ); } else { - selector->show(); - ui->accountsStatus->hide(); + ui->currentAccountSelector->setEnabled(true); + ui->currentAccountSelector->setStyleSheet(""); } + setPhoto(); } void CurrentAccountWidget::setPhoto() { - auto selector = ui->currentAccountSelector; - if (selector->count() > 0) { - if (ProfileModel::instance().selectedProfile()) { - if (auto p = ProfileModel::instance().selectedProfile()->person()) { - QVariant avatarImage = ProfileModel::instance().selectedProfile()->person()->roleData(Qt::DecorationRole); - QImage image = Utils::getCirclePhoto(avatarImage.value<QImage>(), ui->idDisplayLayout->contentsRect().height()); - ui->currentAccountPixmap->setPixmap(QPixmap::fromImage(image)); - qDebug() << "CurrentAccount : Photo set"; - } else - qDebug() << "CurrentAccount : selected profile has no person"; - } else - qDebug() << "CurrentAccount : Profilemodel: no selected profile"; - } else { - qDebug() << "CurrentAccount : account not set"; - ui->currentAccountPixmap->setPixmap(QPixmap()); + auto accountId = LRCInstance::getSelectedAccountId(); + try { + auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountId); + QVariant avatarImage = PixbufManipulator::accountPhoto(accountInfo); + QImage image = Utils::getCirclePhoto(avatarImage.value<QImage>(), ui->idDisplayLayout->contentsRect().height()); + ui->currentAccountPixmap->setPixmap(QPixmap::fromImage(image)); } + catch (...) {} } void CurrentAccountWidget::on_currentAccountSelector_currentIndexChanged(int index) { - QModelIndex idx = ui->currentAccountSelector->model()->index(index,0); - Account* ac = AccountModel::instance().getAccountByModelIndex(idx); - - if (ac) { - AvailableAccountModel::instance().selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); - setPhoto(); - } else { - qDebug() << "CurrentAccount : account not referenced correctly"; - //null for now - } + QModelIndex idx = ui->currentAccountSelector->model()->index(index, 0); + emit currentAccountChanged(idx); + setPhoto(); } void diff --git a/currentaccountwidget.h b/currentaccountwidget.h index 10d01f6..20f5f46 100644 --- a/currentaccountwidget.h +++ b/currentaccountwidget.h @@ -22,6 +22,9 @@ #include <QWidget> +#include "accountlistmodel.h" +#include "accountitemdelegate.h" + namespace Ui { class CurrentAccountWidget; } @@ -35,6 +38,9 @@ public: ~CurrentAccountWidget(); void changeSelectedIndex(int index); +signals: + void currentAccountChanged(const QModelIndex& current); + public slots: void update(); void setPhoto(); @@ -43,9 +49,9 @@ private slots: void on_currentAccountSelector_currentIndexChanged(int index); private: + AccountItemDelegate * accountItemDelegate_; + std::unique_ptr<AccountListModel> accountListModel_; Ui::CurrentAccountWidget *ui; - void setup(); - void updateAccounts(); }; #endif // CURRENTACCOUNTWIDGET_H diff --git a/currentaccountwidget.ui b/currentaccountwidget.ui index 51b5cee..c10708b 100644 --- a/currentaccountwidget.ui +++ b/currentaccountwidget.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>294</width> - <height>184</height> + <width>461</width> + <height>128</height> </rect> </property> <property name="sizePolicy"> @@ -48,12 +48,12 @@ <number>0</number> </property> <item> - <layout class="QVBoxLayout" name="fullLayout" stretch="4,0,0"> + <layout class="QVBoxLayout" name="fullLayout" stretch="4"> <property name="spacing"> <number>0</number> </property> <item> - <layout class="QHBoxLayout" name="idDisplayLayout" stretch="0,0,0"> + <layout class="QHBoxLayout" name="idDisplayLayout" stretch="0,0,0,0"> <property name="leftMargin"> <number>10</number> </property> @@ -71,9 +71,12 @@ <property name="orientation"> <enum>Qt::Horizontal</enum> </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> <property name="sizeHint" stdset="0"> <size> - <width>40</width> + <width>10</width> <height>20</height> </size> </property> @@ -82,15 +85,15 @@ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter"> <widget class="QLabel" name="currentAccountPixmap"> <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> - <width>0</width> - <height>60</height> + <width>48</width> + <height>48</height> </size> </property> <property name="toolTip"> @@ -106,42 +109,32 @@ <property name="orientation"> <enum>Qt::Horizontal</enum> </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> <property name="sizeHint" stdset="0"> <size> - <width>40</width> + <width>10</width> <height>20</height> </size> </property> </spacer> </item> + <item> + <widget class="QComboBox" name="currentAccountSelector"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>account selection combobox</string> + </property> + </widget> + </item> </layout> </item> - <item alignment="Qt::AlignHCenter"> - <widget class="QLabel" name="accountsStatus"> - <property name="minimumSize"> - <size> - <width>20</width> - <height>10</height> - </size> - </property> - <property name="toolTip"> - <string>Account status</string> - </property> - <property name="styleSheet"> - <string notr="true">text: centered;</string> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="currentAccountSelector"> - <property name="toolTip"> - <string>account selection combobox</string> - </property> - </widget> - </item> </layout> </item> </layout> diff --git a/deletecontactdialog.cpp b/deletecontactdialog.cpp deleted file mode 100644 index 85c15f0..0000000 --- a/deletecontactdialog.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * - * Author: Olivier Soldano <olivier.soldano@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 "deletecontactdialog.h" -#include "ui_deletecontactdialog.h" - -// LRC -#include "person.h" -#include "account.h" -#include "bannedcontactmodel.h" - -DeleteContactDialog::DeleteContactDialog(ContactMethod* cm, Account* ac, QWidget *parent) : - QDialog(parent), - ui(new Ui::DeleteContactDialog), - contactMethod_(cm), - account_(ac) -{ - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - ui->setupUi(this); - ui->contactNameLabel->setText(cm->bestName()); - if (cm->bestName() != cm->bestId()) - ui->contactIdLabel->setText(cm->bestId()); - else - ui->contactIdLabel->hide(); -} - -DeleteContactDialog::~DeleteContactDialog() -{ - delete ui; -} - -void DeleteContactDialog::on_deleteCancelBtn_clicked() -{ - close(); -} - -void DeleteContactDialog::on_deleteAcceptBtn_clicked() -{ - account_->removeContact(contactMethod_); - accept(); -} - -void DeleteContactDialog::on_deleteBanBtn_clicked() -{ - account_->removeContact(contactMethod_); - account_->bannedContactModel()->add(contactMethod_); - accept(); -} diff --git a/deletecontactdialog.ui b/deletecontactdialog.ui deleted file mode 100644 index fa97857..0000000 --- a/deletecontactdialog.ui +++ /dev/null @@ -1,181 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>DeleteContactDialog</class> - <widget class="QDialog" name="DeleteContactDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>200</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="windowTitle"> - <string>Dialog</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::MinimumExpanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>10</height> - </size> - </property> - </spacer> - </item> - <item alignment="Qt::AlignHCenter"> - <widget class="QLabel" name="label"> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="text"> - <string>Do you want to delete this contact?</string> - </property> - </widget> - </item> - <item alignment="Qt::AlignHCenter"> - <widget class="QLabel" name="contactNameLabel"> - <property name="minimumSize"> - <size> - <width>10</width> - <height>0</height> - </size> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item alignment="Qt::AlignHCenter"> - <widget class="QLabel" name="contactIdLabel"> - <property name="minimumSize"> - <size> - <width>10</width> - <height>0</height> - </size> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - <italic>true</italic> - </font> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::MinimumExpanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="buttonRow"> - <property name="spacing"> - <number>10</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <item> - <widget class="QPushButton" name="deleteCancelBtn"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>30</height> - </size> - </property> - <property name="toolTip"> - <string>Cancel contact deletion button</string> - </property> - <property name="text"> - <string>Cancel</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="deleteAcceptBtn"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>30</height> - </size> - </property> - <property name="toolTip"> - <string>Delete contact validation button</string> - </property> - <property name="text"> - <string>Delete</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="deleteBanBtn"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>30</height> - </size> - </property> - <property name="toolTip"> - <string>Delete and ban validation button</string> - </property> - <property name="text"> - <string>Delete and ban</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>10</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/images/icons/ic_block-24px.svg b/images/icons/ic_block-24px.svg new file mode 100644 index 0000000..8032acf --- /dev/null +++ b/images/icons/ic_block-24px.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM4 12c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69L5.69 16.9C4.63 15.55 4 13.85 4 12zm8 8c-1.85 0-3.55-.63-4.9-1.69L18.31 7.1C19.37 8.45 20 10.15 20 12c0 4.42-3.58 8-8 8z"/></svg> \ No newline at end of file diff --git a/images/icons/ic_clear-24px.svg b/images/icons/ic_clear-24px.svg new file mode 100644 index 0000000..dea8678 --- /dev/null +++ b/images/icons/ic_clear-24px.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/><path d="M0 0h24v24H0z" fill="none"/></svg> \ No newline at end of file diff --git a/imdelegate.cpp b/imdelegate.cpp index 55f10d0..6c13048 100644 --- a/imdelegate.cpp +++ b/imdelegate.cpp @@ -1,6 +1,7 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * + * Copyright (C) 2015-2018 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 * @@ -19,7 +20,6 @@ #include "imdelegate.h" #include <QApplication> -#include <QTextDocument> #include <QSettings> #include <QDateTime> @@ -28,6 +28,8 @@ #include "ringthemeutils.h" #include "settingskey.h" +#include "messagemodel.h" +#include "utils.h" ImDelegate::ImDelegate(QObject *parent) : QStyledItemDelegate(parent) @@ -35,25 +37,17 @@ ImDelegate::ImDelegate(QObject *parent) } void -ImDelegate::formatMsg(const QModelIndex& index, QString& msg) const +ImDelegate::formatMsg(const QModelIndex& index, QString& msgString) const { - QSettings settings; - QStringList meta; - if (settings.value(SettingsKey::imShowAuthor).toBool()) { - meta << index.data( - static_cast<int>(media::TextRecording::Role::AuthorDisplayname)).toString(); - } - if (settings.value(SettingsKey::imShowDate).toBool()) { - auto timeStamp = index.data( - static_cast<int>(media::TextRecording::Role::Timestamp)).value<uint>(); - auto date = QDateTime::fromTime_t(timeStamp); - auto now = QDateTime::currentDateTime(); - if (now.date() == date.date()) - meta << date.time().toString(); - else - meta << date.toString(); + auto date = index.data(static_cast<int>(MessageModel::Role::InteractionDate)).value<QDateTime>(); + auto now = QDateTime::currentDateTime(); + QString dateString; + if (now.date() == date.date()) { + dateString = date.time().toString(); + } else { + dateString = date.toString(); } - msg = QString("%2<footer><i>%1</i></footer>").arg(meta.join(" - "), msg); + msgString = QString("%1<br><footer><i>%2</i></footer>").arg(msgString, dateString); } void @@ -61,6 +55,16 @@ ImDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { + if (!index.isValid()) { + return; + } + + auto msg = index.data(static_cast<int>(MessageModel::Role::Body)).toString(); + auto type = static_cast<lrc::api::interaction::Type>(index.data(static_cast<int>(MessageModel::Role::Type)).value<int>()); + auto isOutgoing = index.data(static_cast<int>(MessageModel::Role::Direction)).value<bool>(); + auto isGenerated = Utils::isInteractionGenerated(type); + auto dir = isGenerated ? Qt::AlignHCenter : (isOutgoing ? Qt::AlignRight : Qt::AlignLeft); + QStyleOptionViewItem opt = option; initStyleOption(&opt, index); painter->setRenderHint(QPainter::Antialiasing); @@ -68,77 +72,69 @@ ImDelegate::paint(QPainter* painter, opt.font = fontMsg_; painter->setFont(fontMsg_); - if (index.isValid()) { - auto msg = index.data(static_cast<int>(media::TextRecording::Role::FormattedHtml)).toString(); - opt.text.clear(); - QStyle* style = opt.widget ? opt.widget->style() : QApplication::style(); + opt.text.clear(); + QStyle* style = opt.widget ? opt.widget->style() : QApplication::style(); - auto dir = index.data(static_cast<int>(media::TextRecording::Role::Direction)) - .value<media::Media::Direction>() == media::Media::Direction::IN - ? Qt::AlignLeft : Qt::AlignRight; + formatMsg(index, msg); - formatMsg(index, msg); + QTextDocument document; + document.setDefaultStyleSheet(defaultStylesheet_); + document.setDefaultFont(fontMsg_); + document.setHtml(msg); + auto textOptions = QTextOption(Qt::AlignLeft); + textOptions.setWrapMode(QTextOption::WrapMode::WordWrap); + document.setDefaultTextOption(textOptions); - QRect textRect = getBoundingRect(dir, msg, opt); + QRect textRect = getBoundingRect(dir, opt, document); + document.setTextWidth(textRect.width()); - if (dir == Qt::AlignLeft) { - opt.decorationSize = iconSize_; - opt.decorationPosition = (dir == Qt::AlignRight ? - QStyleOptionViewItem::Right : QStyleOptionViewItem::Left); - opt.decorationAlignment = Qt::AlignTop | Qt::AlignHCenter; - } else - opt.decorationSize = QSize(); + if (dir == Qt::AlignLeft) { + opt.decorationSize = iconSize_; + opt.decorationPosition = QStyleOptionViewItem::Left; + opt.decorationAlignment = Qt::AlignTop | Qt::AlignHCenter; style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); + } else { + opt.decorationSize = QSize(); + opt.decorationPosition = QStyleOptionViewItem::Right; + } - QPainterPath path; - path.addRoundedRect(textRect, padding_, padding_); - - if (dir == Qt::AlignRight) { - painter->fillPath(path, RingTheme::imBlue_); - } - else { - painter->fillPath(path, RingTheme::imGrey_); - } - - painter->save(); - - QTextDocument document; - document.setDefaultFont(fontMsg_); - - document.setDefaultStyleSheet("body { color : black; } i { opacity: 100; font-size : 11px; text-align : right; }"); + QPainterPath path; + path.addRoundedRect(textRect, bubbleRadius_, bubbleRadius_); - document.setHtml(msg); + if (dir == Qt::AlignRight) { + painter->fillPath(path, RingTheme::imGrey_); + } else if (dir == Qt::AlignHCenter) { + painter->fillPath(path, Qt::transparent); + } else { + painter->fillPath(path, RingTheme::imBlue_); + } - auto textOptions = QTextOption(Qt::AlignLeft); - textOptions.setWrapMode(QTextOption::WrapMode::WordWrap); - document.setDefaultTextOption(textOptions); - document.setTextWidth(textRect.width()); + painter->save(); - painter->translate(textRect.topLeft()); - document.drawContents(painter); - painter->restore(); - } + painter->translate(textRect.topLeft()); + document.drawContents(painter); + painter->restore(); } QRect ImDelegate::getBoundingRect(const Qt::AlignmentFlag& dir, - const QString& msg, - const QStyleOptionViewItem &option) const + const QStyleOptionViewItem &option, + QTextDocument& txtDoc) const { QRect textRect; - QTextDocument txtDoc; - txtDoc.setDefaultFont(fontMsg_); - txtDoc.setHtml(msg); - auto textOptions = QTextOption(Qt::AlignLeft); - textOptions.setWrapMode(QTextOption::WrapMode::WordWrap); - txtDoc.setDefaultTextOption(textOptions); - if (dir == Qt::AlignLeft) { txtDoc.setTextWidth(option.rect.width() - iconSize_.width() - padding_); textRect.setRect(option.rect.left() + iconSize_.width() + padding_, option.rect.top() + padding_, txtDoc.idealWidth(), txtDoc.size().height()); + } else if (dir == Qt::AlignHCenter) { + txtDoc.setTextWidth(option.rect.width() - padding_); + auto optCenter = option.rect.left() + option.rect.width() / 2; + textRect.setRect(optCenter - txtDoc.idealWidth() / 2, + option.rect.top() + padding_, + txtDoc.idealWidth(), + txtDoc.size().height()); } else { txtDoc.setTextWidth(option.rect.width() - padding_); textRect.setRect(option.rect.right() - padding_ - txtDoc.idealWidth(), @@ -158,22 +154,30 @@ ImDelegate::sizeHint(const QStyleOptionViewItem& option, QString msg = index.data(static_cast<int>(media::TextRecording::Role::FormattedHtml)).toString(); - auto dir = index.data( - static_cast<int>(media::TextRecording::Role::Direction)) - .value<media::Media::Direction>() == media::Media::Direction::IN - ? Qt::AlignLeft : Qt::AlignRight; + auto isOutgoing = index.data(static_cast<int>(MessageModel::Role::Direction)).value<bool>(); + auto isGenerated = Utils::isInteractionGenerated( + static_cast<lrc::api::interaction::Type>(index.data(static_cast<int>(MessageModel::Role::Type)).value<int>()) + ); + auto dir = isGenerated ? Qt::AlignHCenter : (isOutgoing ? Qt::AlignRight : Qt::AlignLeft); formatMsg(index, msg); - QRect boundingRect = getBoundingRect(dir, msg, opt); + QTextDocument document; + document.setDefaultFont(fontMsg_); + document.setHtml(msg); + auto textOptions = QTextOption(Qt::AlignLeft); + textOptions.setWrapMode(QTextOption::WrapMode::WordWrap); + document.setDefaultTextOption(textOptions); + + QRect boundingRect = getBoundingRect(dir, opt, document); - QSize size(option.rect.width(), boundingRect.height()); + QSize size(boundingRect.width() + 2 * margin_, boundingRect.height()); /* Keep the minimum height needed. */ if(size.height() < iconSize_.height()) size.setHeight(iconSize_.height()); - size.setHeight(size.height() + 2 * padding_); + size.setHeight(size.height() + 2 * margin_); return size; } diff --git a/imdelegate.h b/imdelegate.h index 5a6151a..c422610 100644 --- a/imdelegate.h +++ b/imdelegate.h @@ -19,6 +19,7 @@ #pragma once #include <QPainter> +#include <QTextDocument> #include <QStyledItemDelegate> class ImDelegate : public QStyledItemDelegate @@ -26,21 +27,21 @@ class ImDelegate : public QStyledItemDelegate Q_OBJECT public: explicit ImDelegate(QObject *parent = 0); - enum DisplayOptions { - AUTHOR = 1, - DATE - }; protected: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; private: void formatMsg(const QModelIndex& index, QString& msg) const; - QRect getBoundingRect(const Qt::AlignmentFlag& dir, const QString& msg, const QStyleOptionViewItem &option) const; + QRect getBoundingRect(const Qt::AlignmentFlag& dir, const QStyleOptionViewItem &option, + QTextDocument& txtDoc) const; const QFont fontMsg_ = QFont("Arial", 10); - const QSize iconSize_ {38,38}; + const QString defaultStylesheet_ = QString("body { color : black; } i { opacity: 100; font-size : 10px; text-align : right; }"); + const QSize iconSize_ {38, 38}; + constexpr static int margin_ = 5; constexpr static int padding_ = 5; + constexpr static int bubbleRadius_ = 12; }; diff --git a/instantmessagingwidget.cpp b/instantmessagingwidget.cpp index 95cce48..9473950 100644 --- a/instantmessagingwidget.cpp +++ b/instantmessagingwidget.cpp @@ -46,23 +46,6 @@ InstantMessagingWidget::InstantMessagingWidget(QWidget *parent) : connect(copyAction, &QAction::triggered, [=]() { copyToClipboard(); }); - QSettings settings; - auto displayDate = new QAction(tr("Display date"), this); - displayDate->setCheckable(true); - displayDate->setChecked(settings.value(SettingsKey::imShowDate).toBool()); - ui->listMessageView->addAction(displayDate); - auto displayAuthor = new QAction(tr("Display author"), this); - displayAuthor->setCheckable(true); - displayAuthor->setChecked(settings.value(SettingsKey::imShowAuthor).toBool()); - ui->listMessageView->addAction(displayAuthor); - auto lamdba = [=](){ - QSettings settings; - settings.setValue(SettingsKey::imShowAuthor, displayAuthor->isChecked()); - settings.setValue(SettingsKey::imShowDate, displayDate->isChecked()); - emit imDelegate_->sizeHintChanged(QModelIndex()); - }; - connect(displayAuthor, &QAction::triggered, lamdba); - connect(displayDate, &QAction::triggered, lamdba); } InstantMessagingWidget::~InstantMessagingWidget() @@ -86,12 +69,9 @@ InstantMessagingWidget::setMediaText(Call *call) textMedia = call->addOutgoingMedia<media::Text>(); } if (textMedia) { - ui->listMessageView->setModel( - textMedia->recording()-> - instantMessagingModel()); + ui->listMessageView->setModel(textMedia->recording()->instantMessagingModel()); ui->listMessageView->scrollToBottom(); - connect(ui->messageEdit, &QLineEdit::returnPressed, [=]() - { + connect(ui->messageEdit, &QLineEdit::returnPressed, [=]() { if (not ui->messageEdit->text().trimmed().isEmpty()) { QMap<QString, QString> messages; messages["text/plain"] = ui->messageEdit->text(); diff --git a/deletecontactdialog.h b/invitebuttonswidget.cpp similarity index 59% rename from deletecontactdialog.h rename to invitebuttonswidget.cpp index 792f654..ee18f90 100644 --- a/deletecontactdialog.h +++ b/invitebuttonswidget.cpp @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * - * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> * + * Copyright (C) 2018 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 * @@ -16,35 +16,32 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * **************************************************************************/ -#ifndef DELETECONTACTDIALOG_H -#define DELETECONTACTDIALOG_H +#include "ui_invitebuttonswidget.h" -#include <QDialog> +#include "invitebuttonswidget.h" -// LRC -#include "contactmethod.h" +InviteButtonsWidget::InviteButtonsWidget(QWidget* parent) : + QWidget(parent), + ui(new Ui::InviteButtonsWidget) +{ + ui->setupUi(this); + connect(ui->btnAcceptInvite, &QPushButton::clicked, this, + [=]() { + emit btnAcceptInviteClicked(); + }); + connect(ui->btnIgnoreInvite, &QPushButton::clicked, this, + [=]() { + emit btnIgnoreInviteClicked(); + }); + connect(ui->btnBlockInvite, &QPushButton::clicked, this, + [=]() { + emit btnBlockInviteClicked(); + }); -namespace Ui { -class DeleteContactDialog; } -class DeleteContactDialog : public QDialog +InviteButtonsWidget::~InviteButtonsWidget() { - Q_OBJECT - -public: - explicit DeleteContactDialog(ContactMethod* cm, Account *ac, QWidget *parent = 0); - ~DeleteContactDialog(); - -private slots: - void on_deleteCancelBtn_clicked(); - void on_deleteAcceptBtn_clicked(); - void on_deleteBanBtn_clicked(); - -private: - Ui::DeleteContactDialog *ui; - ContactMethod* contactMethod_; - Account* account_; -}; - -#endif // DELETECONTACTDIALOG_H + disconnect(this); + delete ui; +} \ No newline at end of file diff --git a/combar.h b/invitebuttonswidget.h similarity index 73% rename from combar.h rename to invitebuttonswidget.h index ca01889..7e1919b 100644 --- a/combar.h +++ b/invitebuttonswidget.h @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * - * Author: Jäger Nicolas <nicolas.jager@savoirfairelinux.com> * + * Copyright (C) 2018 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 * @@ -21,20 +21,22 @@ #include <QWidget> namespace Ui { -class ComBar; +class InviteButtonsWidget; } -class ComBar : public QWidget +class InviteButtonsWidget : public QWidget { Q_OBJECT public: - explicit ComBar(QWidget* parent = 0); - ~ComBar(); + explicit InviteButtonsWidget(QWidget* parent = 0); + ~InviteButtonsWidget(); private: - Ui::ComBar* ui; + Ui::InviteButtonsWidget* ui; signals: - void btnVideoClicked() const; + void btnAcceptInviteClicked() const; + void btnIgnoreInviteClicked() const; + void btnBlockInviteClicked() const; -}; +}; \ No newline at end of file diff --git a/invitebuttonswidget.ui b/invitebuttonswidget.ui new file mode 100644 index 0000000..e1f8bf2 --- /dev/null +++ b/invitebuttonswidget.ui @@ -0,0 +1,175 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>InviteButtonsWidget</class> + <widget class="QWidget" name="InviteButtonsWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>323</width> + <height>114</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string/> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <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>5</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>209</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnAcceptInvite"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="toolTip"> + <string>Accept invite</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_person_add_black_24dp_2x.png</normaloff>:/images/icons/ic_person_add_black_24dp_2x.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>18</width> + <height>18</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnIgnoreInvite"> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="toolTip"> + <string>Ignore invite</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_clear-24px.svg</normaloff>:/images/icons/ic_clear-24px.svg</iconset> + </property> + <property name="iconSize"> + <size> + <width>18</width> + <height>18</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnBlockInvite"> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="toolTip"> + <string>Block person</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_block-24px.svg</normaloff>:/images/icons/ic_block-24px.svg</iconset> + </property> + <property name="iconSize"> + <size> + <width>18</width> + <height>18</height> + </size> + </property> + </widget> + </item> + <item> + <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>13</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources> + <include location="ressources.qrc"/> + </resources> + <connections/> +</ui> diff --git a/lrcinstance.h b/lrcinstance.h index 573f7d3..e92dd34 100644 --- a/lrcinstance.h +++ b/lrcinstance.h @@ -21,6 +21,8 @@ #undef ERROR #endif +#include <QSettings> + #include "api/lrc.h" #include "api/account.h" #include "api/newaccountmodel.h" @@ -31,6 +33,8 @@ #include "api/contact.h" #include "api/datatransfermodel.h" +#include <settingskey.h> + class LRCInstance { public: static void init() { @@ -55,15 +59,51 @@ public: return instance().lrc_->isConnected(); }; + static const lrc::api::account::Info& + getCurrentAccountInfo() { + return accountModel().getAccountInfo(instance().selectedAccountId); + }; + + static lrc::api::ConversationModel* + getCurrentConversationModel() { + return getCurrentAccountInfo().conversationModel.get(); + }; + + static lrc::api::NewCallModel* + getCurrentCallModel() { + return getCurrentAccountInfo().callModel.get(); + }; + + static const std::string& getSelectedAccountId() { + return instance().selectedAccountId; + }; + + static void setSelectedAccountId(const std::string& accountId) { + instance().selectedAccountId = accountId; + QSettings settings; + settings.setValue(SettingsKey::selectedAccount, QString::fromStdString(accountId)); + }; + + static const std::string& getSelectedConvUid() { + return instance().selectedConvUid; + }; + + static void setSelectedConvId(const std::string& convUid) { + instance().selectedConvUid = convUid; + }; + private: std::unique_ptr<lrc::api::Lrc> lrc_; static LRCInstance& instance() { static LRCInstance instance_; return instance_; - } + }; LRCInstance() { lrc_ = std::make_unique<lrc::api::Lrc>(); }; + + std::string selectedAccountId; + std::string selectedConvUid; }; \ No newline at end of file diff --git a/main.cpp b/main.cpp index 61dec93..a0284ab 100644 --- a/main.cpp +++ b/main.cpp @@ -29,7 +29,6 @@ #include "pixbufmanipulator.h" #include "lrcinstance.h" -#include <QThread> #include <QTranslator> #include <QLibraryInfo> #include <QFontDatabase> diff --git a/mainwindow.cpp b/mainwindow.cpp index c3cd8f6..c6abaec 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright (C) 2015-2017 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 * @@ -42,10 +43,19 @@ MainWindow::MainWindow(QWidget* parent) : ui(new Ui::MainWindow) { ui->setupUi(this); + connect(ui->callwidget, &CallWidget::NavigationRequested, - [this](ScreenEnum scr){Utils::slidePage(ui->navStack, ui->navStack->widget(scr));}); + [this](ScreenEnum scr) { + Utils::setStackWidget(ui->navStack, ui->navStack->widget(scr)); + }); + connect(ui->configurationwidget, &ConfigurationWidget::NavigationRequested, - [this](ScreenEnum scr){Utils::slidePage(ui->navStack, ui->navStack->widget(scr));}); + [this](ScreenEnum scr) { + Utils::setStackWidget(ui->navStack, ui->navStack->widget(scr)); + if (scr == ScreenEnum::CallScreen) { + ui->callwidget->update(); + } + }); QIcon icon(":images/ring.png"); @@ -189,7 +199,7 @@ MainWindow::createThumbBar() settings->setIcon(icon); settings->setDismissOnClick(true); connect(settings, &QWinThumbnailToolButton::clicked, [this]() { - Utils::slidePage(ui->navStack, ui->configurationwidget); + Utils::setStackWidget(ui->navStack, ui->configurationwidget); }); thumbbar->addButton(settings); diff --git a/messagemodel.cpp b/messagemodel.cpp new file mode 100644 index 0000000..998c97f --- /dev/null +++ b/messagemodel.cpp @@ -0,0 +1,123 @@ +/*************************************************************************** +* Copyright (C) 2017 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 "messagemodel.h" + +// Qt +#include <QDateTime> + +// LRC +#include "globalinstances.h" +#include "api/contactmodel.h" +#include "api/conversationmodel.h" + +// Client +#include "pixbufmanipulator.h" +#include "utils.h" + +MessageModel::MessageModel(const ConversationInfo& conv, const AccountInfo& acc, QObject *parent) + : QAbstractItemModel(parent), + conv_(conv), + acc_(acc) +{ +} + +int MessageModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return conv_.interactions.size(); + } + return 0; // A valid QModelIndex returns 0 as no entry has sub-elements +} + +int MessageModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 1; +} + +QVariant MessageModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || conv_.interactions.size() == 0) { + return QVariant(); + } + + auto it = conv_.interactions.begin(); + std::advance(it, index.row()); + const auto& item = (*it).second; + switch (role) { + case Role::Body: + return QVariant(QString::fromStdString(item.body)); + case Role::Picture: + case Qt::DecorationRole: + return GlobalInstances::pixmapManipulator().decorationRole(conv_, acc_); + case Role::DisplayName: + case Qt::DisplayRole: + { + auto& contact = acc_.contactModel->getContact(conv_.participants[0]); + return QVariant(QString::fromStdString(Utils::bestNameForContact(contact))); + } + case Role::Presence: + { + auto& contact = acc_.contactModel->getContact(conv_.participants[0]); + return QVariant(contact.isPresent); + } + case Role::InteractionDate: + { + auto& date = item.timestamp; + return QVariant(QDateTime::fromTime_t(date)); + } + case Role::Status: + return QVariant::fromValue(static_cast<int>(item.status)); + case Role::Direction: + return QVariant::fromValue(lrc::api::interaction::isOutgoing(item)); + case Role::Type: + return QVariant::fromValue(static_cast<int>(item.type)); + } + return QVariant(); +} + +QModelIndex MessageModel::index(int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(parent); + if (column != 0) { + return QModelIndex(); + } + + if (row >= 0 && row < rowCount()) { + return createIndex(row, column); + } + return QModelIndex(); +} + +QModelIndex MessageModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child); + return QModelIndex(); +} + +Qt::ItemFlags MessageModel::flags(const QModelIndex &index) const +{ + auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable; + if (!index.isValid()) { + return QAbstractItemModel::flags(index); + } else { + flags &= ~(Qt::ItemIsSelectable); + } + return flags; +} diff --git a/messagemodel.h b/messagemodel.h new file mode 100644 index 0000000..b8411c3 --- /dev/null +++ b/messagemodel.h @@ -0,0 +1,61 @@ +/*************************************************************************** +* Copyright (C) 2017 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 + +// Qt include +#include <QAbstractItemModel> + +// LRC +#include "api/account.h" +#include "api/conversation.h" +#include "api/contact.h" + +class MessageModel : public QAbstractItemModel +{ + Q_OBJECT +public: + using AccountInfo = lrc::api::account::Info; + using ConversationInfo = lrc::api::conversation::Info; + using ContactInfo = lrc::api::contact::Info; + + enum Role { + Body = Qt::UserRole + 1, + DisplayName, + Picture, + Presence, + Status, + DataTransferStatus, + InteractionDate, + Direction, + Type + }; + + explicit MessageModel(const ConversationInfo& conv, const AccountInfo& acc, QObject *parent = 0); + + // QAbstractItemModel + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + +private: + ConversationInfo conv_; + const AccountInfo& acc_; +}; diff --git a/photoboothwidget.cpp b/photoboothwidget.cpp index 537f544..ded23f4 100644 --- a/photoboothwidget.cpp +++ b/photoboothwidget.cpp @@ -33,7 +33,6 @@ PhotoboothWidget::PhotoboothWidget(QWidget *parent) : ui->setupUi(this); ui->videoFeed->setIsFullPreview(true); ui->videoFeed->setPhotoMode(true); - startBooth(); } PhotoboothWidget::~PhotoboothWidget() @@ -44,12 +43,7 @@ PhotoboothWidget::~PhotoboothWidget() void PhotoboothWidget::startBooth() { - // // // // - // stop (or start before) to give Preview manager some time to start - // TODO go modify the daemon to ensure starting upon calling videomanager::startCamera Video::PreviewManager::instance().stopPreview(); - // // // // - Video::PreviewManager::instance().startPreview(); ui->videoFeed->show(); } diff --git a/pixbufmanipulator.cpp b/pixbufmanipulator.cpp index 3ca4956..f0fe02e 100644 --- a/pixbufmanipulator.cpp +++ b/pixbufmanipulator.cpp @@ -35,6 +35,13 @@ #include "contactmethod.h" #include "profilemodel.h" #include "profile.h" +#include "globalinstances.h" + + // new LRC +#include <api/contactmodel.h> +#include <api/conversation.h> +#include <api/account.h> +#include <api/contact.h> #include "utils.h" #include "ringthemeutils.h" @@ -51,20 +58,13 @@ getAvatarColor(const QString& canonicalUri) { if (h.isEmpty() || h.isNull()) { return RingTheme::defaultAvatarColor_; } - uint8_t colorsLength = sizeof(RingTheme::avatarColors_) / sizeof(QColor); - bool ok; - auto colorIndex = QString(h.at(0)).toUInt(&ok, colorsLength); + auto colorIndex = std::string("0123456789abcdef").find(h.at(0).toLatin1()); return RingTheme::avatarColors_[colorIndex]; } -// // Generate a QImage representing a dummy user avatar, when user doesn't provide it. // Current rendering is a flat colored circle with a centered letter. // The color of the letter is computed from the circle color to be visible whaterver be the circle color. -// -// \param color circle color -// \param letter centerer letter -// static QImage fallbackAvatar(const QSize size, const QString& canonicalUriStr, const QString& letterStr = QString()) { @@ -84,6 +84,8 @@ fallbackAvatar(const QSize size, const QString& canonicalUriStr, const QString& // If a letter was passed, then we paint a letter in the circle, // otherwise we draw the default avatar icon + QString letterStrCleaned(letterStr); + letterStrCleaned.remove(QRegExp("[\\n\\t\\r]")); if (!letterStr.isEmpty()) { auto letter = letterStr.at(0).toUpper().toLatin1(); QFont font("Arial", avatar.height() / 2.66667, QFont::Medium); @@ -104,8 +106,7 @@ fallbackAvatar(const QSize size, const QString& canonicalUriStr, const QString& } QImage -fallbackAvatar -(const QSize size, const ContactMethod* cm) +fallbackAvatar(const QSize size, const ContactMethod* cm) { if (cm == nullptr) { return QImage(); @@ -121,6 +122,14 @@ fallbackAvatar return image; } +QImage +fallbackAvatar(const QSize size, const std::string& alias, const std::string& uri) +{ + return fallbackAvatar(size, + QString::fromStdString(uri), + QString::fromStdString(alias)); +} + /*Namespace Interfaces collide with QBuffer*/ QByteArray QImageToByteArray(QImage image) { @@ -174,11 +183,12 @@ PixbufManipulator::contactPhoto(Person* p, const QSize& size, bool displayPresen QVariant PixbufManipulator::personPhoto(const QByteArray& data, const QString& type) { QImage avatar; - QByteArray ba = type.toLatin1(); - const char* c_str2 = ba.data(); - if (avatar.loadFromData(data.fromBase64(data), c_str2)) - return Utils::getCirclePhoto(avatar, avatar.size().width()); - return fallbackAvatar(IMAGE_SIZE, QString()); + const bool ret = avatar.loadFromData(QByteArray::fromBase64(data), type.toLatin1()); + if (!ret) { + qDebug() << "vCard image loading failed"; + return QVariant(); + } + return QPixmap::fromImage(Utils::getCirclePhoto(avatar, avatar.size().width())); } QVariant @@ -287,3 +297,65 @@ QVariant PixbufManipulator::decorationRole(const Account* acc) selectedProfile()->person()->photo().value<QImage>(), IMAGE_SIZE.width()); } + +QVariant +PixbufManipulator::decorationRole(const lrc::api::conversation::Info & conversationInfo, + const lrc::api::account::Info & accountInfo) +{ + QImage photo; + auto contacts = conversationInfo.participants; + if (!contacts.empty()) { + try { + // Get first contact photo + auto contactUri = contacts.front(); + auto contactInfo = accountInfo.contactModel->getContact(contactUri); + auto contactPhoto = contactInfo.profileInfo.avatar; + auto bestName = Utils::bestNameForContact(contactInfo); + auto bestId = Utils::bestIdForContact(contactInfo); + if (accountInfo.profileInfo.type == lrc::api::profile::Type::SIP && + contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY) { + photo = fallbackAvatar(IMAGE_SIZE, QString(), QString()); + } + else if (accountInfo.profileInfo.type == lrc::api::profile::Type::SIP) { + photo = fallbackAvatar(IMAGE_SIZE, + QString::fromStdString("sip:" + bestId), + QString()); + } + else if (contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY && contactInfo.profileInfo.uri.empty()) { + photo = fallbackAvatar(IMAGE_SIZE, QString(), QString()); + } + else if (!contactPhoto.empty()) { + QByteArray byteArray(contactPhoto.c_str(), contactPhoto.length()); + photo = personPhoto(byteArray, nullptr).value<QImage>(); + } + else { + auto avatarName = contactInfo.profileInfo.uri == bestName ? + QString() : + QString::fromStdString(bestName); + photo = fallbackAvatar(IMAGE_SIZE, + QString::fromStdString("ring:" + bestId), + avatarName); + } + } + catch (...) {} + } + return QVariant::fromValue(scaleAndFrame(photo, IMAGE_SIZE)); +} + +QVariant +PixbufManipulator::accountPhoto(const lrc::api::account::Info& accountInfo) +{ + QImage photo; + if (!accountInfo.profileInfo.avatar.empty()) { + QByteArray ba = QByteArray::fromStdString(accountInfo.profileInfo.avatar); + photo = GlobalInstances::pixmapManipulator().personPhoto(ba, nullptr).value<QImage>(); + } + else { + auto bestId = Utils::bestIdForAccount(accountInfo); + auto bestName = Utils::bestNameForAccount(accountInfo); + photo = fallbackAvatar( IMAGE_SIZE, + QString::fromStdString("ring:" + bestId), + QString::fromStdString(bestName)); + } + return QVariant::fromValue(scaleAndFrame(photo, IMAGE_SIZE)); +} diff --git a/pixbufmanipulator.h b/pixbufmanipulator.h index 4155e5d..8bbe96a 100644 --- a/pixbufmanipulator.h +++ b/pixbufmanipulator.h @@ -52,7 +52,9 @@ public: QVariant decorationRole(const ContactMethod* cm) override; QVariant decorationRole(const Person* p) override; QVariant decorationRole(const Account* acc) override; + QVariant decorationRole(const lrc::api::conversation::Info& conversation, + const lrc::api::account::Info& accountInfo) override; static QImage scaleAndFrame(const QImage photo, const QSize& size); - static QImage scaleAndFrame(const QImage photo, const int& size); + static QVariant accountPhoto(const lrc::api::account::Info& accountInfo); }; diff --git a/quickactcontactrequestwidget.cpp b/quickactcontactrequestwidget.cpp deleted file mode 100644 index 020d9e6..0000000 --- a/quickactcontactrequestwidget.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * - * Author: Olivier Soldano <olivier.soldano@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 "quickactcontactrequestwidget.h" -#include "ui_quickactcontactrequestwidget.h" - -#include <QFont> - -// CLIENT -#include "contactrequestitemdelegate.h" - -QuickActContactRequestWidget::QuickActContactRequestWidget(QWidget *parent) : - QWidget(parent), - ui(new Ui::QuickActContactRequestWidget) -{ - ui->setupUi(this); - - // set symbols in buttons using FontAwsome - ui->quickValidCRBtn->setText(QChar(0xf00c)); - ui->quickMuteCRBtn->setText(QChar(0xf12d)); - ui->quickBanCRBtn->setText(QChar(0xf00d)); - - connect(ui->quickValidCRBtn, &QPushButton::clicked, this, [=](){ - emit quickValidCRBtnClicked(); - }); - - connect(ui->quickMuteCRBtn, &QPushButton::clicked, this, [=](){ - emit quickMuteCRBtnClicked(); - }); - - connect(ui->quickBanCRBtn, &QPushButton::clicked, this, [=](){ - emit quickBanCRBtnClicked(); - }); - -} - -QuickActContactRequestWidget::~QuickActContactRequestWidget() -{ - disconnect(this); - delete ui; -} diff --git a/ressources.qrc b/ressources.qrc index e93b7c1..fa04106 100644 --- a/ressources.qrc +++ b/ressources.qrc @@ -44,5 +44,7 @@ <file>images/icons/ic_person_add_black_24dp_2x.png</file> <file>images/waiting.gif</file> <file>images/default-avatar-overlay.svg</file> + <file>images/icons/ic_clear-24px.svg</file> + <file>images/icons/ic_block-24px.svg</file> </qresource> </RCC> diff --git a/ring-client-windows.pro b/ring-client-windows.pro deleted file mode 100644 index 9ee5b41..0000000 --- a/ring-client-windows.pro +++ /dev/null @@ -1,287 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2018-06-28T15:11:54 -# -#------------------------------------------------- - -QT += core gui - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets svg xml network winextras - -VERSION = 2.0.0 -GIT_VERSION = $$system(git --git-dir $$PWD/.git --work-tree $$PWD describe --always --tags) - -DEFINES += NIGHTLY_VERSION=$$system("echo %date:~10,4%%date:~4,2%%date:~7,2%") - -TARGET = Ring -TEMPLATE = app - -contains(BUILD, Debug) { - QMAKE_STRIP = echo - CONFIG += console -} - -isEmpty(QMAKE_LRELEASE) { - QMAKE_LRELEASE = lrelease -} - -SOURCES += - main.cpp\ - mainwindow.cpp \ - callwidget.cpp \ - configurationwidget.cpp \ - navwidget.cpp \ - accountdetails.cpp \ - aboutdialog.cpp \ - videowidget.cpp \ - utils.cpp \ - wizarddialog.cpp \ - windowscontactbackend.cpp \ - selectareadialog.cpp \ - accountserializationadapter.cpp \ - instantmessagingwidget.cpp \ - accountstatedelegate.cpp \ - videoview.cpp \ - videooverlay.cpp \ - imdelegate.cpp \ - contactpicker.cpp \ - contactmethodpicker.cpp \ - globalsystemtray.cpp \ - smartlistdelegate.cpp \ - callutilsdialog.cpp \ - combar.cpp \ - idlabel.cpp \ - smartlist.cpp \ - ringcontactlineedit.cpp \ - pixbufmanipulator.cpp \ - qualitydialog.cpp \ - ringbutton.cpp \ - photoboothdialog.cpp \ - sendcontactrequestwidget.cpp \ - currentaccountwidget.cpp \ - contactrequestwidget.cpp \ - contactrequestitemdelegate.cpp \ - quickactcontactrequestwidget.cpp \ - contactrequestlistwidget.cpp \ - deleteaccountdialog.cpp \ - bannedcontactswidget.cpp \ - photoboothwidget.cpp \ - deletecontactdialog.cpp - -HEADERS += - mainwindow.h \ - callwidget.h \ - configurationwidget.h \ - navwidget.h \ - accountdetails.h \ - aboutdialog.h \ - videowidget.h \ - utils.h \ - wizarddialog.h \ - windowscontactbackend.h \ - selectareadialog.h \ - accountserializationadapter.h \ - instantmessagingwidget.h \ - accountstatedelegate.h \ - videoview.h \ - videooverlay.h \ - imdelegate.h \ - contactpicker.h \ - contactmethodpicker.h \ - settingskey.h \ - globalsystemtray.h \ - smartlistdelegate.h \ - callutilsdialog.h \ - combar.h \ - idlabel.h \ - smartlist.h \ - ringcontactlineedit.h \ - pixbufmanipulator.h \ - qualitydialog.h \ - ringthemeutils.h \ - ringbutton.h \ - photoboothdialog.h \ - sendcontactrequestwidget.h \ - currentaccountwidget.h \ - contactrequestwidget.h \ - contactrequestitemdelegate.h \ - quickactcontactrequestwidget.h \ - contactrequestlistwidget.h \ - deleteaccountdialog.h \ - bannedcontactswidget.h \ - photoboothwidget.h \ - deletecontactdialog.h \ - lrcinstance.h - -contains(DEFINES, URI_PROTOCOL) { - HEADERS += shmclient.h - SOURCES += shmclient.cpp -} - -FORMS += - mainwindow.ui \ - callwidget.ui \ - configurationwidget.ui \ - accountdetails.ui \ - aboutdialog.ui \ - wizarddialog.ui \ - instantmessagingwidget.ui \ - videoview.ui \ - videooverlay.ui \ - contactpicker.ui \ - contactmethodpicker.ui \ - callutilsdialog.ui \ - combar.ui \ - qualitydialog.ui \ - ringbutton.ui \ - photoboothdialog.ui \ - sendcontactrequestwidget.ui \ - currentaccountwidget.ui \ - contactrequestwidget.ui \ - quickactcontactrequestwidget.ui \ - deleteaccountdialog.ui \ - bannedcontactswidget.ui \ - photoboothwidget.ui \ - deletecontactdialog.ui - -INCLUDEPATH += $${RING}/lrc/src -INCLUDEPATH += $${RING}/client-windows/winsparkle/include -INCLUDEPATH += $${RING}/client-windows/qrencode-win32/qrencode-win32 - - -CONFIG( debug, debug|release ) { - # debug - # daemon lib - LIBS += -L$$PWD/../daemon/contrib/msvc/lib/x64/ - LIBS += -L$$PWD/../daemon/MSVC/x64/DebugLib_win32/bin/ -ldring - - # lrc lib - LIBS += -L$$PWD/../lrc/msvc/Debug/ -lringclient_s - - # winsparkle lib - LIBS += -L$$PWD/winsparkle/x64/release/ -lWinSparkle - - # qrcode lib - LIBS += -L$$PWD/qrencode-win32/qrencode-win32/vc8/qrcodelib/x64/Release-Lib/ -lqrcodelib -} else { - # release - # debug - # daemon lib - LIBS += -L$$PWD/../daemon/contrib/msvc/lib/x64/ - LIBS += -L$$PWD/../daemon/MSVC/x64/ReleaseLib_win32/bin/ -ldring - - # lrc lib - LIBS += -L$$PWD/../lrc/msvc/Release/ -lringclient_s - - # winsparkle lib - LIBS += -L$$PWD/winsparkle/x64/release/ -lWinSparkle - - # qrcode lib - LIBS += -L$$PWD/qrencode-win32/qrencode-win32/vc8/qrcodelib/x64/Release-Lib/ -lqrcodelib - - QMAKE_LFLAGS_RELEASE += /FORCE:MULTIPLE -} - -LIBS += -lOle32 -lAdvapi32 -lShlwapi -lUser32 -lGdi32 -lCrypt32 -lStrmiids - -RESOURCES += \ - ressources.qrc - -RC_FILE = ico.rc - -TRANSLATIONS = \ - translations/ring_client_windows_nb.ts \ - translations/ring_client_windows_pa.ts \ - translations/ring_client_windows_pt_BR.ts \ - translations/ring_client_windows_pt.ts \ - translations/ring_client_windows_ms.ts \ - translations/ring_client_windows_de.ts \ - translations/ring_client_windows_uk.ts \ - translations/ring_client_windows_sq_AL.ts \ - translations/ring_client_windows_ca.ts \ - translations/ring_client_windows_es.ts \ - translations/ring_client_windows_da_DK.ts \ - translations/ring_client_windows_et_EE.ts \ - translations/ring_client_windows_de_DE.ts \ - translations/ring_client_windows_lt.ts \ - translations/ring_client_windows_fr_FR.ts \ - translations/ring_client_windows_nl_BE.ts \ - translations/ring_client_windows_he.ts \ - translations/ring_client_windows_sk_SK.ts \ - translations/ring_client_windows_pl.ts \ - translations/ring_client_windows_es_AR.ts \ - translations/ring_client_windows_nl.ts \ - translations/ring_client_windows_it_IT.ts \ - translations/ring_client_windows_bg.ts \ - translations/ring_client_windows_id.ts \ - translations/ring_client_windows_en_GB.ts \ - translations/ring_client_windows_pl_PL.ts \ - translations/ring_client_windows.ts \ - translations/ring_client_windows_eu.ts \ - translations/ring_client_windows_eo.ts \ - translations/ring_client_windows_nl_NL.ts \ - translations/ring_client_windows_ru_RU.ts \ - translations/ring_client_windows_hr.ts \ - translations/ring_client_windows_zh_CN.ts \ - translations/ring_client_windows_fr.ts \ - translations/ring_client_windows_tr.ts \ - translations/ring_client_windows_cs_CZ.ts \ - translations/ring_client_windows_zh_TW.ts \ - translations/ring_client_windows_fr_CA.ts \ - translations/ring_client_windows_ko_KR.ts \ - translations/ring_client_windows_zh.ts \ - translations/ring_client_windows_fa_IR.ts \ - translations/ring_client_windows_fi.ts \ - translations/ring_client_windows_sv.ts \ - translations/ring_client_windows_it.ts \ - translations/ring_client_windows_el.ts \ - translations/ring_client_windows_ja.ts \ - translations/ring_client_windows_hu.ts \ - translations/ring_client_windows_sl.ts \ - translations/ring_client_windows_hi_IN.ts \ - translations/ring_client_windows_ro.ts \ - translations/ring_client_windows_ru.ts \ - translations/ring_client_windows_ar.ts \ - -RINGTONES.files = $${RING}/daemon/ringtones -RINGTONES.path = $$OUT_PWD/release - -PACKAGING.files = ring.nsi images/ring.ico -PACKAGING.path = $$OUT_PWD/release - -LICENSE.files = License.rtf -LICENSE.path = $$OUT_PWD/release - -RUNTIMEDIR=$$[QT_INSTALL_BINS] - -RUNTIME.files = $${RING}/lrc/msvc/Release/ringclient.dll -RUNTIME.path = $$OUT_PWD/release - -LRC_TRANSLATION.files = $${RING}/share/libringclient/translations -LRC_TRANSLATION.path = $$OUT_PWD/release/share/libringclient/ - -QTRUNTIME.files = $$RUNTIMEDIR/Qt5Core.dll $$RUNTIMEDIR/Qt5Widgets.dll \ - $$RUNTIMEDIR/Qt5Gui.dll $$RUNTIMEDIR/Qt5Svg.dll \ - $$RUNTIMEDIR/Qt5Xml.dll $$RUNTIMEDIR/Qt5WinExtras.dll \ - $$RUNTIMEDIR/Qt5Network.dll $$RUNTIMEDIR/Qt5Sql.dll -QTRUNTIME.path = $$OUT_PWD/release - -QTDEPSRUNTIME.path = $$OUT_PWD/release - -QTPLATFORMS.files = $$[QT_INSTALL_PLUGINS]/platforms/qwindows.dll -QTPLATFORMS.path = $$OUT_PWD/release/platforms - -QTPLUGINIMAGE.files = $$[QT_INSTALL_PLUGINS]/imageformats/ -QTPLUGINIMAGE.path = $$OUT_PWD/release - -QTSQLDRIVERS.files = $$[QT_INSTALL_PLUGINS]/sqldrivers/qsqlite.dll -QTSQLDRIVERS.path = $$OUT_PWD/release/sqldrivers - -LIBSTD.files = $$RUNTIMEDIR/libgcc_s_sjlj-1.dll $$RUNTIMEDIR/libstdc++-6.dll \ - $$RUNTIMEDIR/libwinpthread-1.dll $$RUNTIMEDIR/libgcc_s_seh-1.dll -LIBSTD.path = $$OUT_PWD/release - -INSTALLS += RINGTONES PACKAGING LICENSE RUNTIME LRC_TRANSLATION QTRUNTIME QTDEPSRUNTIME \ - QTPLUGINIMAGE QTPLATFORMS QTSQLDRIVERS LIBSTD - -DEFINES += ENABLE_AUTOUPDATE diff --git a/ring-client-windows.sln b/ring-client-windows.sln index f2e9245..222923c 100644 --- a/ring-client-windows.sln +++ b/ring-client-windows.sln @@ -37,15 +37,16 @@ Global RelWithDebInfo|x86 = RelWithDebInfo|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0F6318E4-4C06-384E-BCA8-F344DA187957}.Debug|x64.ActiveCfg = Debug|x64 - {0F6318E4-4C06-384E-BCA8-F344DA187957}.Debug|x64.Build.0 = Debug|x64 - {0F6318E4-4C06-384E-BCA8-F344DA187957}.Debug|x86.ActiveCfg = Debug|x64 - {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib_win32|x64.ActiveCfg = Debug|x64 - {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib_win32|x64.Build.0 = Debug|x64 + {0F6318E4-4C06-384E-BCA8-F344DA187957}.Debug|x64.ActiveCfg = Release|x64 + {0F6318E4-4C06-384E-BCA8-F344DA187957}.Debug|x64.Build.0 = Release|x64 + {0F6318E4-4C06-384E-BCA8-F344DA187957}.Debug|x86.ActiveCfg = Release|x64 + {0F6318E4-4C06-384E-BCA8-F344DA187957}.Debug|x86.Build.0 = Release|x64 + {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib_win32|x64.ActiveCfg = Release|x64 + {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib_win32|x64.Build.0 = Release|x64 {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib_win32|x86.ActiveCfg = Release|x64 {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib_win32|x86.Build.0 = Release|x64 - {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib|x64.ActiveCfg = Debug|x64 - {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib|x64.Build.0 = Debug|x64 + {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib|x64.ActiveCfg = Release|x64 + {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib|x64.Build.0 = Release|x64 {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib|x86.ActiveCfg = Release|x64 {0F6318E4-4C06-384E-BCA8-F344DA187957}.DebugLib|x86.Build.0 = Release|x64 {0F6318E4-4C06-384E-BCA8-F344DA187957}.MinSizeRel|x64.ActiveCfg = Release|x64 diff --git a/ring-client-windows.vcxproj b/ring-client-windows.vcxproj index d092da0..cb7f54b 100644 --- a/ring-client-windows.vcxproj +++ b/ring-client-windows.vcxproj @@ -5,10 +5,6 @@ <Configuration>Release</Configuration> <Platform>x64</Platform> </ProjectConfiguration> - <ProjectConfiguration Include="Debug|x64"> - <Configuration>Debug</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> <ProjectGuid>{0F6318E4-4C06-384E-BCA8-F344DA187957}</ProjectGuid> @@ -26,15 +22,6 @@ <IntermediateDirectory>release\</IntermediateDirectory> <PrimaryOutput>Ring</PrimaryOutput> </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <PlatformToolset>v141</PlatformToolset> - <OutputDirectory>debug\</OutputDirectory> - <ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage> - <CharacterSet>NotSet</CharacterSet> - <ConfigurationType>Application</ConfigurationType> - <IntermediateDirectory>debug\</IntermediateDirectory> - <PrimaryOutput>Ring</PrimaryOutput> - </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <PropertyGroup Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')"> <QtMsBuild>$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild> @@ -49,9 +36,6 @@ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> - </ImportGroup> <PropertyGroup Label="UserMacros" /> <PropertyGroup> <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir> @@ -59,19 +43,15 @@ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Ring</TargetName> <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Ring</TargetName> - <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> - <AdditionalIncludeDirectories>.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)../daemon/contrib/msvc/include;$(ProjectDir)../lrc/src;$(ProjectDir)../client-windows/winsparkle/include;$(ProjectDir)../client-windows/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\QtCore;$(QTDIR)\mkspecs\win32-msvc;release;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions> <AssemblerListingLocation>release\</AssemblerListingLocation> <BrowseInformation>false</BrowseInformation> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> - <DisableSpecificWarnings>4068;4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <DisableSpecificWarnings>4068;4099;4189;4267;4577;4467;4715;%(DisableSpecificWarnings)</DisableSpecificWarnings> <ExceptionHandling>Sync</ExceptionHandling> <ObjectFileName>$(IntDir)</ObjectFileName> <Optimization>MaxSpeed</Optimization> @@ -90,7 +70,7 @@ <Link> <AdditionalDependencies>..\daemon\MSVC\x64\ReleaseLib_win32\bin\dring.lib;..\lrc\msvc\src\qtwrapper\Release\qtwrapper.lib;..\lrc\msvc\release\ringclient_static.lib;.\winsparkle\x64\release\WinSparkle.lib;.\qrencode-win32\qrencode-win32\vc8\qrcodelib\x64\Release-Lib\qrcodelib.lib;shell32.lib;Ole32.lib;Advapi32.lib;Shlwapi.lib;User32.lib;Gdi32.lib;Crypt32.lib;Strmiids.lib;$(QTDIR)\lib\qtmain.lib;$(QTDIR)\lib\Qt5Svg.lib;$(QTDIR)\lib\Qt5Widgets.lib;$(QTDIR)\lib\Qt5WinExtras.lib;$(QTDIR)\lib\Qt5Gui.lib;$(QTDIR)\lib\Qt5Xml.lib;$(QTDIR)\lib\Qt5Network.lib;$(QTDIR)\lib\Qt5Core.lib;$(QTDIR)\lib\Qt5Sql.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories>$(QTDIR)\lib;..\daemon\contrib\msvc\lib\x64;..\daemon\MSVC\x64\ReleaseLib_win32\bin;..\lrc\msvc\release;.\winsparkle\x64\release;.\qrencode-win32\qrencode-win32\vc8\qrcodelib\x64\Release-Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /ignore:4006,4049,4078,4098 /LTCG /NODEFAULTLIB:LIBCMT %(AdditionalOptions)</AdditionalOptions> <DataExecutionPrevention>true</DataExecutionPrevention> <GenerateDebugInformation>true</GenerateDebugInformation> <IgnoreImportLibrary>true</IgnoreImportLibrary> @@ -136,109 +116,53 @@ <QTDIR>$(QTDIR)</QTDIR> </QtUic> </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <AdditionalIncludeDirectories>.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)../lrc/src;$(ProjectDir)../client-windows/winsparkle/include;$(ProjectDir)../client-windows/qrencode-win32/qrencode-win32;$(QTDIR)\include;debug;$(QTDIR)\mkspecs\win32-msvc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions> - <AssemblerListingLocation>debug\</AssemblerListingLocation> - <BrowseInformation>false</BrowseInformation> - <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> - <DisableSpecificWarnings>4068;4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings> - <ExceptionHandling>Sync</ExceptionHandling> - <ObjectFileName>$(IntDir)</ObjectFileName> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <PreprocessToFile>false</PreprocessToFile> - <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> - <SuppressStartupBanner>true</SuppressStartupBanner> - <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> - <WarningLevel>Level3</WarningLevel> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> - </ClCompile> - <Link> - <AdditionalDependencies>$(QTDIR)\lib\qtmaind.lib;shell32.lib;C:\Users\fner\Desktop\RINGVS2017\ring-project\daemon\MSVC\x64\DebugLib_win32\bin\dringd.lib;C:\Users\fner\Desktop\RINGVS2017\ring-project\lrc\msvc\debug\ringclient_s.lib;.\winsparkle\x64\release\WinSparkle.lib;.\qrencode-win32\qrencode-win32\vc8\qrcodelib\x64\Release-Lib\qrcodelib.lib;Ole32.lib;Advapi32.lib;Shlwapi.lib;User32.lib;Gdi32.lib;Crypt32.lib;Mmdevapi.lib;$(QTDIR)\lib\Qt5Svgd.lib;$(QTDIR)\lib\Qt5Widgetsd.lib;$(QTDIR)\lib\Qt5WinExtrasd.lib;$(QTDIR)\lib\Qt5Guid.lib;$(QTDIR)\lib\Qt5Xmld.lib;$(QTDIR)\lib\Qt5Networkd.lib;$(QTDIR)\lib\Qt5Cored.lib;$(QTDIR)\lib\Qt5Sqld.lib;%(AdditionalDependencies)</AdditionalDependencies> - <AdditionalLibraryDirectories>$(QTDIR)\lib;C:\utils\my_sql\my_sql\lib;C:\utils\postgresql\pgsql\lib;$(QTDIR)\lib;C:\Users\fner\Desktop\RINGVS2017\ring-project\daemon\contrib\msvc\lib\x64;C:\Users\fner\Desktop\RINGVS2017\ring-project\daemon\MSVC\x64\ReleaseLib\bin;C:\Users\fner\Desktop\RINGVS2017\ring-project\lrc\msvc\release;.\winsparkle\x64\release;.\qrencode-win32\qrencode-win32\vc8\qrcodelib\x64\Release-Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions> - <DataExecutionPrevention>true</DataExecutionPrevention> - <GenerateDebugInformation>true</GenerateDebugInformation> - <IgnoreImportLibrary>true</IgnoreImportLibrary> - <OutputFile>$(OutDir)\Ring.exe</OutputFile> - <RandomizedBaseAddress>true</RandomizedBaseAddress> - <SubSystem>Windows</SubSystem> - <SuppressStartupBanner>true</SuppressStartupBanner> - <Version>2.0</Version> - </Link> - <Midl> - <DefaultCharType>Unsigned</DefaultCharType> - <EnableErrorChecks>None</EnableErrorChecks> - <WarningLevel>0</WarningLevel> - </Midl> - <ResourceCompile> - <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_SVG_LIB;QT_WIDGETS_LIB;QT_WINEXTRAS_LIB;QT_GUI_LIB;QT_XML_LIB;QT_NETWORK_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ResourceCompile> - <QtRcc> - <QTDIR>$(QTDIR)</QTDIR> - <ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription> - <Compression>default</Compression> - <InitFuncName>ressources</InitFuncName> - <OutputFile>.\GeneratedFiles\qrc_%(Filename).cpp</OutputFile> - <InputFile>%(FullPath)</InputFile> - </QtRcc> - <QtMoc> - <QTDIR>$(QTDIR)</QTDIR> - <OutputFile>.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</OutputFile> - <Define>_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;%(PreprocessorDefinitions)</Define> - <CompilerFlavor>msvc</CompilerFlavor> - <Include>$(Configuration)/moc_predefs.h</Include> - <ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription> - <InputFile>%(FullPath)</InputFile> - <DynamicSource>output</DynamicSource> - <IncludePath>.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)../lrc/src;$(ProjectDir)../client-windows/winsparkle/include;$(ProjectDir)../client-windows/qrencode-win32/qrencode-win32;$(QTDIR)\include;debug;$(QTDIR)\mkspecs\win32-msvc;%(AdditionalIncludeDirectories)</IncludePath> - </QtMoc> - <QtUic> - <InputFile>%(FullPath)</InputFile> - <ExecutionDescription>Uic'ing %(Identity)...</ExecutionDescription> - <OutputFile>.\GeneratedFiles\ui_%(Filename).h</OutputFile> - <QTDIR>$(QTDIR)</QTDIR> - </QtUic> - </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="aboutdialog.cpp" /> <ClCompile Include="accountdetails.cpp" /> + <ClCompile Include="accountitemdelegate.cpp" /> <ClCompile Include="accountserializationadapter.cpp" /> + <ClCompile Include="accountlistmodel.cpp" /> <ClCompile Include="accountstatedelegate.cpp" /> <ClCompile Include="bannedcontactswidget.cpp" /> <ClCompile Include="callutilsdialog.cpp" /> - <ClCompile Include="callwidget.cpp" /> - <ClCompile Include="combar.cpp" /> + <ClCompile Include="callwidget.cpp"> + <OutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\%(Filename).moc</OutputFile> + <DynamicSource Condition="'$(Configuration)|$(Platform)'=='Release|x64'">input</DynamicSource> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG</Define> + </ClCompile> <ClCompile Include="configurationwidget.cpp" /> - <ClCompile Include="contactmethodpicker.cpp" /> <ClCompile Include="contactpicker.cpp" /> - <ClCompile Include="contactrequestitemdelegate.cpp" /> - <ClCompile Include="contactrequestlistwidget.cpp" /> <ClCompile Include="contactrequestwidget.cpp" /> <ClCompile Include="currentaccountwidget.cpp" /> <ClCompile Include="deleteaccountdialog.cpp" /> - <ClCompile Include="deletecontactdialog.cpp" /> <ClCompile Include="globalsystemtray.cpp" /> <ClCompile Include="idlabel.cpp" /> <ClCompile Include="imdelegate.cpp" /> <ClCompile Include="instantmessagingwidget.cpp" /> + <ClCompile Include="invitebuttonswidget.cpp" /> <ClCompile Include="main.cpp" /> <ClCompile Include="mainwindow.cpp" /> + <ClCompile Include="messagemodel.cpp" /> <ClCompile Include="navwidget.cpp" /> <ClCompile Include="photoboothdialog.cpp" /> <ClCompile Include="photoboothwidget.cpp" /> <ClCompile Include="pixbufmanipulator.cpp" /> <ClCompile Include="qualitydialog.cpp" /> - <ClCompile Include="quickactcontactrequestwidget.cpp" /> <ClCompile Include="ringbutton.cpp" /> <ClCompile Include="ringcontactlineedit.cpp" /> <ClCompile Include="selectareadialog.cpp" /> <ClCompile Include="sendcontactrequestwidget.cpp" /> - <ClCompile Include="smartlist.cpp" /> - <ClCompile Include="smartlistdelegate.cpp" /> + <ClCompile Include="conversationsfilterwidget.cpp"> + <OutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\%(Filename).moc</OutputFile> + <DynamicSource Condition="'$(Configuration)|$(Platform)'=='Release|x64'">input</DynamicSource> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG</Define> + </ClCompile> + <ClCompile Include="smartlistselectorbuttonnotifier.cpp" /> + <ClCompile Include="smartlistview.cpp" /> + <ClCompile Include="conversationitemdelegate.cpp" /> + <ClCompile Include="smartlistmodel.cpp" /> <ClCompile Include="utils.cpp" /> <ClCompile Include="videooverlay.cpp" /> <ClCompile Include="videoview.cpp" /> @@ -261,16 +185,17 @@ </QtMoc> <QtMoc Include="callwidget.h"> </QtMoc> - <QtMoc Include="combar.h"> - </QtMoc> <QtMoc Include="configurationwidget.h"> </QtMoc> - <QtMoc Include="contactmethodpicker.h"> - </QtMoc> <QtMoc Include="contactpicker.h"> </QtMoc> - <ClInclude Include="contactrequestitemdelegate.h" /> - <QtMoc Include="contactrequestlistwidget.h"> + <QtMoc Include="accountlistmodel.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG;QT_SVG_LIB;QT_WIDGETS_LIB;QT_WINEXTRAS_LIB;QT_GUI_LIB;QT_XML_LIB;QT_NETWORK_LIB;QT_CORE_LIB</Define> + </QtMoc> + <QtMoc Include="accountitemdelegate.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG;QT_SVG_LIB;QT_WIDGETS_LIB;QT_WINEXTRAS_LIB;QT_GUI_LIB;QT_XML_LIB;QT_NETWORK_LIB;QT_CORE_LIB</Define> </QtMoc> <QtMoc Include="contactrequestwidget.h"> </QtMoc> @@ -278,8 +203,6 @@ </QtMoc> <QtMoc Include="deleteaccountdialog.h"> </QtMoc> - <QtMoc Include="deletecontactdialog.h"> - </QtMoc> <QtMoc Include="globalsystemtray.h"> </QtMoc> <QtMoc Include="idlabel.h"> @@ -296,12 +219,18 @@ </QtMoc> <QtMoc Include="photoboothwidget.h"> </QtMoc> + <QtMoc Include="invitebuttonswidget.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG</Define> + </QtMoc> <ClInclude Include="lrcinstance.h" /> + <QtMoc Include="messagemodel.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG;QT_SVG_LIB;QT_WIDGETS_LIB;QT_WINEXTRAS_LIB;QT_GUI_LIB;QT_XML_LIB;QT_NETWORK_LIB;QT_CORE_LIB</Define> + </QtMoc> <ClInclude Include="pixbufmanipulator.h" /> <QtMoc Include="qualitydialog.h"> </QtMoc> - <QtMoc Include="quickactcontactrequestwidget.h"> - </QtMoc> <QtMoc Include="ringbutton.h"> </QtMoc> <QtMoc Include="ringcontactlineedit.h"> @@ -312,9 +241,25 @@ <QtMoc Include="sendcontactrequestwidget.h"> </QtMoc> <ClInclude Include="settingskey.h" /> - <QtMoc Include="smartlist.h"> + <QtMoc Include="smartlistview.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG;QT_SVG_LIB;QT_WIDGETS_LIB;QT_WINEXTRAS_LIB;QT_GUI_LIB;QT_XML_LIB;QT_NETWORK_LIB;QT_CORE_LIB</Define> + </QtMoc> + <QtMoc Include="conversationitemdelegate.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG</Define> + </QtMoc> + <QtMoc Include="smartlistmodel.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG;QT_SVG_LIB;QT_WIDGETS_LIB;QT_WINEXTRAS_LIB;QT_GUI_LIB;QT_XML_LIB;QT_NETWORK_LIB;QT_CORE_LIB</Define> </QtMoc> - <QtMoc Include="smartlistdelegate.h"> + <QtMoc Include="conversationsfilterwidget.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG</Define> + </QtMoc> + <QtMoc Include="smartlistselectorbuttonnotifier.h"> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\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\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> + <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG</Define> </QtMoc> <ClInclude Include="utils.h" /> <QtMoc Include="videooverlay.h"> @@ -331,10 +276,6 @@ <CustomBuild Include="debug\moc_predefs.h.cbt"> <FileType>Document</FileType> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> - <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs> - <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h</Command> - <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generate moc_predefs.h</Message> - <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">debug\moc_predefs.h;%(Outputs)</Outputs> </CustomBuild> <CustomBuild Include="release\moc_predefs.h.cbt"> <FileType>Document</FileType> @@ -342,21 +283,17 @@ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h</Command> <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generate moc_predefs.h</Message> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">release\moc_predefs.h;%(Outputs)</Outputs> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> </CustomBuild> <ClInclude Include="ui_aboutdialog.h" /> <ClInclude Include="ui_accountdetails.h" /> <ClInclude Include="ui_bannedcontactswidget.h" /> <ClInclude Include="ui_callutilsdialog.h" /> <ClInclude Include="ui_callwidget.h" /> - <ClInclude Include="ui_combar.h" /> <ClInclude Include="ui_configurationwidget.h" /> - <ClInclude Include="ui_contactmethodpicker.h" /> <ClInclude Include="ui_contactpicker.h" /> <ClInclude Include="ui_contactrequestwidget.h" /> <ClInclude Include="ui_currentaccountwidget.h" /> <ClInclude Include="ui_deleteaccountdialog.h" /> - <ClInclude Include="ui_deletecontactdialog.h" /> <ClInclude Include="ui_instantmessagingwidget.h" /> <ClInclude Include="ui_mainwindow.h" /> <ClInclude Include="ui_photoboothdialog.h" /> @@ -433,13 +370,10 @@ <QtUic Include="callutilsdialog.ui"> </QtUic> <QtUic Include="callwidget.ui"> - </QtUic> - <QtUic Include="combar.ui"> + <SubType>Designer</SubType> </QtUic> <QtUic Include="configurationwidget.ui"> </QtUic> - <QtUic Include="contactmethodpicker.ui"> - </QtUic> <QtUic Include="contactpicker.ui"> </QtUic> <QtUic Include="contactrequestwidget.ui"> @@ -448,10 +382,9 @@ </QtUic> <QtUic Include="deleteaccountdialog.ui"> </QtUic> - <QtUic Include="deletecontactdialog.ui"> - </QtUic> <QtUic Include="instantmessagingwidget.ui"> </QtUic> + <QtUic Include="invitebuttonswidget.ui" /> <QtUic Include="mainwindow.ui"> </QtUic> <QtUic Include="photoboothdialog.ui"> diff --git a/ring-client-windows.vcxproj.filters b/ring-client-windows.vcxproj.filters index a777fab..276995b 100644 --- a/ring-client-windows.vcxproj.filters +++ b/ring-client-windows.vcxproj.filters @@ -75,27 +75,12 @@ <ClCompile Include="callutilsdialog.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="callwidget.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="combar.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="configurationwidget.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="contactmethodpicker.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="contactpicker.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="contactrequestitemdelegate.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="contactrequestlistwidget.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="contactrequestwidget.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -105,9 +90,6 @@ <ClCompile Include="deleteaccountdialog.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="deletecontactdialog.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="globalsystemtray.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -141,9 +123,6 @@ <ClCompile Include="qualitydialog.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="quickactcontactrequestwidget.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="ringbutton.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -156,12 +135,6 @@ <ClCompile Include="sendcontactrequestwidget.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="smartlist.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="smartlistdelegate.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="utils.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -180,6 +153,36 @@ <ClCompile Include="wizarddialog.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="smartlistview.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="smartlistmodel.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="messagemodel.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="accountlistmodel.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="accountitemdelegate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="callwidget.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="conversationitemdelegate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="conversationsfilterwidget.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="smartlistselectorbuttonnotifier.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="invitebuttonswidget.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <QtMoc Include="aboutdialog.h"> @@ -203,24 +206,12 @@ <QtMoc Include="callwidget.h"> <Filter>Header Files</Filter> </QtMoc> - <QtMoc Include="combar.h"> - <Filter>Header Files</Filter> - </QtMoc> <QtMoc Include="configurationwidget.h"> <Filter>Header Files</Filter> </QtMoc> - <QtMoc Include="contactmethodpicker.h"> - <Filter>Header Files</Filter> - </QtMoc> <QtMoc Include="contactpicker.h"> <Filter>Header Files</Filter> </QtMoc> - <ClInclude Include="contactrequestitemdelegate.h"> - <Filter>Header Files</Filter> - </ClInclude> - <QtMoc Include="contactrequestlistwidget.h"> - <Filter>Header Files</Filter> - </QtMoc> <QtMoc Include="contactrequestwidget.h"> <Filter>Header Files</Filter> </QtMoc> @@ -230,9 +221,6 @@ <QtMoc Include="deleteaccountdialog.h"> <Filter>Header Files</Filter> </QtMoc> - <QtMoc Include="deletecontactdialog.h"> - <Filter>Header Files</Filter> - </QtMoc> <QtMoc Include="globalsystemtray.h"> <Filter>Header Files</Filter> </QtMoc> @@ -263,9 +251,6 @@ <QtMoc Include="qualitydialog.h"> <Filter>Header Files</Filter> </QtMoc> - <QtMoc Include="quickactcontactrequestwidget.h"> - <Filter>Header Files</Filter> - </QtMoc> <QtMoc Include="ringbutton.h"> <Filter>Header Files</Filter> </QtMoc> @@ -284,12 +269,6 @@ <ClInclude Include="settingskey.h"> <Filter>Header Files</Filter> </ClInclude> - <QtMoc Include="smartlist.h"> - <Filter>Header Files</Filter> - </QtMoc> - <QtMoc Include="smartlistdelegate.h"> - <Filter>Header Files</Filter> - </QtMoc> <ClInclude Include="utils.h"> <Filter>Header Files</Filter> </ClInclude> @@ -308,6 +287,33 @@ <QtMoc Include="wizarddialog.h"> <Filter>Header Files</Filter> </QtMoc> + <QtMoc Include="smartlistmodel.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="smartlistview.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="messagemodel.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="accountlistmodel.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="accountitemdelegate.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="conversationitemdelegate.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="conversationsfilterwidget.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="smartlistselectorbuttonnotifier.h"> + <Filter>Header Files</Filter> + </QtMoc> + <QtMoc Include="invitebuttonswidget.h"> + <Filter>Header Files</Filter> + </QtMoc> </ItemGroup> <ItemGroup> <CustomBuild Include="debug\moc_predefs.h.cbt"> @@ -331,15 +337,9 @@ <ClInclude Include="ui_callwidget.h"> <Filter>Generated Files</Filter> </ClInclude> - <ClInclude Include="ui_combar.h"> - <Filter>Generated Files</Filter> - </ClInclude> <ClInclude Include="ui_configurationwidget.h"> <Filter>Generated Files</Filter> </ClInclude> - <ClInclude Include="ui_contactmethodpicker.h"> - <Filter>Generated Files</Filter> - </ClInclude> <ClInclude Include="ui_contactpicker.h"> <Filter>Generated Files</Filter> </ClInclude> @@ -352,9 +352,6 @@ <ClInclude Include="ui_deleteaccountdialog.h"> <Filter>Generated Files</Filter> </ClInclude> - <ClInclude Include="ui_deletecontactdialog.h"> - <Filter>Generated Files</Filter> - </ClInclude> <ClInclude Include="ui_instantmessagingwidget.h"> <Filter>Generated Files</Filter> </ClInclude> @@ -563,15 +560,9 @@ <QtUic Include="callwidget.ui"> <Filter>Form Files</Filter> </QtUic> - <QtUic Include="combar.ui"> - <Filter>Form Files</Filter> - </QtUic> <QtUic Include="configurationwidget.ui"> <Filter>Form Files</Filter> </QtUic> - <QtUic Include="contactmethodpicker.ui"> - <Filter>Form Files</Filter> - </QtUic> <QtUic Include="contactpicker.ui"> <Filter>Form Files</Filter> </QtUic> @@ -584,9 +575,6 @@ <QtUic Include="deleteaccountdialog.ui"> <Filter>Form Files</Filter> </QtUic> - <QtUic Include="deletecontactdialog.ui"> - <Filter>Form Files</Filter> - </QtUic> <QtUic Include="instantmessagingwidget.ui"> <Filter>Form Files</Filter> </QtUic> @@ -620,6 +608,9 @@ <QtUic Include="wizarddialog.ui"> <Filter>Form Files</Filter> </QtUic> + <QtUic Include="invitebuttonswidget.ui"> + <Filter>Form Files</Filter> + </QtUic> </ItemGroup> <ItemGroup> <None Include="images\FontAwesome.otf"> diff --git a/ringthemeutils.h b/ringthemeutils.h index da8e504..8b77e73 100644 --- a/ringthemeutils.h +++ b/ringthemeutils.h @@ -26,11 +26,13 @@ static const QColor lightGrey_ {242, 242, 242}; static const QColor imGrey_ {"#dedee0"}; static const QColor imBlue_ {"#cfebf5"}; static const QColor lightBlack_ {63, 63, 63}; -static const QColor grey_ {192, 192, 192}; +static const QColor grey_ {160, 160, 160 }; static const QColor red_ {251, 72, 71}; static const QColor lightRed_ {252, 91, 90}; static const QColor darkRed_ {219, 55, 54}; +static const QColor notificationRed_{ 255, 59, 48 }; static const QColor green_ {127, 255, 0}; +static const QColor presenceGreen_{ 76, 217, 100 }; static const QColor smartlistSelection_ { 237, 237, 237 }; static const QColor smartlistHighlight_ { 242, 242, 242 }; diff --git a/settingskey.h b/settingskey.h index 9fd4234..8a2453a 100644 --- a/settingskey.h +++ b/settingskey.h @@ -24,9 +24,8 @@ constexpr static char closeOrMinimized[] = "closeOrMin"; constexpr static char autoAnswer[] = "autoAnswer"; constexpr static char geometry[] = "geometry"; constexpr static char windowState[] = "windowState"; -constexpr static char imShowAuthor[] = "imShowAuthor"; -constexpr static char imShowDate[] = "imShowDate"; constexpr static char enableNotifications[] = "enableNotifications"; +constexpr static char selectedAccount[] = "selectedAccount"; } #define accountAutoAnswer(A) (A+SettingsKey::autoAnswer) diff --git a/smartlist.cpp b/smartlist.cpp deleted file mode 100644 index 21db00e..0000000 --- a/smartlist.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * - * Author: Jäger Nicolas <nicolas.jager@savoirfairelinux.com> * - * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * - * Author: Olivier Soldano <olivier.soldano@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 <QStyledItemDelegate> -#include <QEvent> -#include <QTreeWidgetItem> -#include <QScrollBar> - -#include "smartlistdelegate.h" -#include "combar.h" -#include "smartlist.h" - -#include <ciso646> - -SmartList::SmartList(QWidget *parent) : - QTreeView(parent) -{ - verticalScrollBar()->hide(); - - connect(this, &QAbstractItemView::entered, [this](const QModelIndex & index) { - auto widget = indexWidget(index); - if (!widget) { - ComBar* bar = new ComBar(); - setIndexWidget(index, bar); - connect(bar, &ComBar::btnVideoClicked, this, [=](){ emit btnVideoClicked(); }); - } - else if (index.isValid()) - indexWidget(index)->setVisible(true); - - if(hoveredRow_.isValid() and indexWidget(hoveredRow_)) - indexWidget(hoveredRow_)->setVisible(false); - - hoveredRow_ = index; - }); - - setVerticalScrollMode(ScrollPerPixel); -} - -SmartList::~SmartList() -{ - reset(); -} - -void -SmartList::enterEvent(QEvent* event) -{ - Q_UNUSED(event); - verticalScrollBar()->show(); -} - -void -SmartList::leaveEvent(QEvent* event) -{ - Q_UNUSED(event); - - hoveredRow_ = QModelIndex(); - verticalScrollBar()->hide(); -} - -void -SmartList::setSmartListItemDelegate(SmartListDelegate* delegate) -{ - if (delegate) { - setItemDelegate(delegate); - smartListDelegate_ = delegate; - } -} - -bool -SmartList::eventFilter(QObject* watched, QEvent* event) -{ - - if (qobject_cast<QScrollBar*>(watched) && event->type() == QEvent::Enter) { - hoveredRow_ = QModelIndex(); - return true; - } - - return QObject::eventFilter(watched, event); -} - - -void -SmartList::drawRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const -{ - if(index == hoveredRow_ && indexWidget(hoveredRow_)) - indexWidget(index)->setVisible(true); - else if(indexWidget(index)) - indexWidget(index)->setVisible(false); - - QTreeView::drawRow(painter, option, index); -} diff --git a/smartlistdelegate.cpp b/smartlistdelegate.cpp deleted file mode 100644 index cb9d964..0000000 --- a/smartlistdelegate.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015-2017 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 * - * 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 "smartlistdelegate.h" - -#include <QApplication> -#include <QSortFilterProxyModel> -#include <QPainter> -#include <QPixmap> -#include <QDebug> - -// LRC -#include "itemdataroles.h" -#include "person.h" -#include "recentmodel.h" -#include "call.h" - -// Client -#include "combar.h" -#include "ringthemeutils.h" - -#include <ciso646> - -SmartListDelegate::SmartListDelegate(QObject* parent) : - QItemDelegate(parent) -{ -} - -void -SmartListDelegate::paint(QPainter* painter - , const QStyleOptionViewItem& option - , const QModelIndex& index - ) const -{ - QStyleOptionViewItem opt(option); - painter->setRenderHint(QPainter::Antialiasing); - - // Not having focus removes dotted lines around the item - if (opt.state & QStyle::State_HasFocus) - opt.state ^= QStyle::State_HasFocus; - - // First, we draw the control itself - QStyle* style = opt.widget ? opt.widget->style() : QApplication::style(); - style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); - - bool selected = false; - if (option.state & QStyle::State_Selected) { - selected = true; - opt.state ^= QStyle::State_Selected; - painter->fillRect(option.rect, RingTheme::smartlistSelection_); - } - else if (option.state & QStyle::State_MouseOver) { - painter->fillRect(option.rect, RingTheme::smartlistHighlight_); - } - - QRect &rect = opt.rect; - - // Avatar drawing - opt.decorationSize = QSize(sizeImage_, sizeImage_); - opt.decorationPosition = QStyleOptionViewItem::Left; - opt.decorationAlignment = Qt::AlignCenter; - - QRect rectAvatar(16 + 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()); - - // If there's unread messages, a message count is displayed - if (auto messageCount = index.data(static_cast<int>(Ring::Role::UnreadTextMessageCount)).toInt()) { - font.setPointSize(8); - QFontMetrics textFontMetrics(font); - - // If there is more than 10 unread messages, "10+" is displayed - QString messageCountText = (messageCount >= 10)? "9+" : QString::number(messageCount); - - // This QRect is the bounding one containing the message count to be displayed - QRect pastilleRect = textFontMetrics.boundingRect(QRect(rectAvatar.left() - (2 * sizeImage_)/9, - rectAvatar.bottom() - sizeImage_/3 - textFontMetrics.height(), sizeImage_, textFontMetrics.height()), - Qt::AlignVCenter | Qt::AlignLeft, messageCountText); - - // This one is larger than pastilleRect and is used to prepare the red background - QRect bubbleRect(pastilleRect.left() - 3, pastilleRect.top(), - pastilleRect.width() + 6, pastilleRect.height() + 1); - - // The background is displayed - QPainterPath path; - path.addRoundedRect(bubbleRect, 3, 3); - QPen pen(RingTheme::red_, 5); - painter->setOpacity(0.9); - painter->setPen(pen); - painter->fillPath(path, RingTheme::red_); - - // Then the message count - painter->setPen(Qt::white); - painter->setOpacity(1); - painter->setFont(font); - painter->drawText(pastilleRect, Qt::AlignCenter, messageCountText); - } - - // Presence indicator - QPainterPath outerCircle, innerCircle; - QPointF center(rectAvatar.right() - sizeImage_/6, (rectAvatar.bottom() - sizeImage_/6) + 1); - qreal outerCRadius = sizeImage_ / 6, innerCRadius = outerCRadius * 0.75; - outerCircle.addEllipse(center, outerCRadius, outerCRadius); - innerCircle.addEllipse(center, innerCRadius, innerCRadius); - if (index.data(static_cast<int>(Ring::Role::IsPresent)).value<bool>()) { - painter->fillPath(outerCircle, Qt::white); - painter->fillPath(innerCircle, RingTheme::green_); - } - font.setPointSize(fontSize_); - QPen pen(painter->pen()); - - if (index.column() != 0) { - if (selected) { - opt.state ^= QStyle::State_Selected; - } - QItemDelegate::paint(painter, opt, index); - return; - } - - painter->setPen(pen); - - QRect rectTexts(16 + rect.left() + dx_ + sizeImage_, - rect.top(), - rect.width(), - rect.height() / 2); - - // The name is displayed at the avatar's right - QVariant name = index.data(static_cast<int>(Ring::Role::Name)); - if (name.isValid()) - { - pen.setColor(RingTheme::lightBlack_); - painter->setPen(pen); - font.setBold(true); - painter->setFont(font); - QFontMetrics fontMetrics(font); - QString nameStr = fontMetrics.elidedText(name.toString(), Qt::ElideRight - , rectTexts.width()- sizeImage_ - effectiveComBarSize_ - dx_); - painter->drawText(rectTexts, Qt::AlignVCenter | Qt::AlignLeft, nameStr); - } - - // Display the ID under the name - QString idStr = index.data(static_cast<int>(Ring::Role::Number)).value<QString>(); - if (idStr != name.toString()){ - pen.setColor(RingTheme::grey_); - painter->setPen(pen); - font.setItalic(true); - font.setBold(false); - painter->setFont(font); - QFontMetrics fontMetrics(font); - if (!idStr.isNull()){ - idStr = fontMetrics.elidedText(idStr, Qt::ElideRight, rectTexts.width()- sizeImage_ - effectiveComBarSize_ - dx_); - painter->drawText(QRect(16 + rect.left() + dx_ + sizeImage_, - rect.top() + rect.height()/7, - rect.width(), - rect.height()/2), - Qt::AlignBottom | Qt::AlignLeft, idStr); - - } else { - qDebug() << "This is not a Person"; - } - } - - // Finally, either last interaction date or call state is displayed - QVariant state = index.data(static_cast<int>(Ring::Role::FormattedState)); - pen.setColor(RingTheme::grey_); - painter->setPen(pen); - font.setItalic(false); - font.setBold(false); - painter->setFont(font); - rectTexts.moveTop(cellHeight_/2); - if (state.isValid() && RecentModel::instance().getActiveCall(RecentModel::instance().peopleProxy()->mapToSource(index))) - { - painter->drawText(QRect(16 + rect.left() + dx_ + sizeImage_, - rect.top() + rect.height()/2, - rect.width(), - rect.height()/2), - Qt::AlignLeft | Qt::AlignVCenter, state.toString()); - } - else - { - QVariant lastUsed = index.data(static_cast<int>(Ring::Role::FormattedLastUsed)); - if (lastUsed.isValid()) - { - painter->drawText(QRect(16 + rect.left() + dx_ + sizeImage_, - rect.top() + rect.height()/2, - rect.width(), - rect.height()/2), - Qt::AlignLeft | Qt::AlignVCenter, lastUsed.toString()); - } - } -} - -QSize -SmartListDelegate::sizeHint(const QStyleOptionViewItem& option - , const QModelIndex& index - ) const -{ - QSize size = QItemDelegate::sizeHint(option, index); - size.setHeight(cellHeight_); - return size; -} diff --git a/smartlistmodel.cpp b/smartlistmodel.cpp new file mode 100644 index 0000000..d767a03 --- /dev/null +++ b/smartlistmodel.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2017 by Savoir-faire Linux * + * Author: Anthony L�onard <anthony.leonard@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 "smartlistmodel.h" + +// Qt +#include <QDateTime> + +// LRC +#include "globalinstances.h" +#include "api/contactmodel.h" +#include "api/conversationmodel.h" + +// Client +#include "pixbufmanipulator.h" +#include "messagemodel.h" +#include "utils.h" + +SmartListModel::SmartListModel(const lrc::api::account::Info &acc, QObject *parent) + : QAbstractItemModel(parent), + acc_(acc) +{ +} + +int SmartListModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return acc_.conversationModel->allFilteredConversations().size(); + } + return 0; // A valid QModelIndex returns 0 as no entry has sub-elements +} + +int SmartListModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 1; +} + +QVariant SmartListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + const auto& item = acc_.conversationModel->filteredConversation(index.row()); + if (item.participants.size() > 0) { + try { + switch (role) { + case Role::Picture: + case Qt::DecorationRole: + return GlobalInstances::pixmapManipulator().decorationRole(item, acc_); + case Role::DisplayName: + case Qt::DisplayRole: + { + auto& contact = acc_.contactModel->getContact(item.participants[0]); + return QVariant(QString::fromStdString(Utils::bestNameForContact(contact))); + } + case Role::DisplayID: + { + auto& contact = acc_.contactModel->getContact(item.participants[0]); + return QVariant(QString::fromStdString(Utils::bestIdForContact(contact))); + } + case Role::Presence: + { + auto& contact = acc_.contactModel->getContact(item.participants[0]); + return QVariant(contact.isPresent); + } + case Role::URI: + { + auto& contact = acc_.contactModel->getContact(item.participants[0]); + return QVariant(QString::fromStdString(contact.profileInfo.uri)); + } + case Role::UnreadMessagesCount: + return QVariant(item.unreadMessages); + case Role::LastInteractionDate: + { + auto& date = item.interactions.at(item.lastMessageUid).timestamp; + return QVariant(QString::fromStdString(Utils::formatTimeString(date))); + } + case Role::LastInteraction: + return QVariant(QString::fromStdString(item.interactions.at(item.lastMessageUid).body)); + case Role::ContactType: + { + auto& contact = acc_.contactModel->getContact(item.participants[0]); + return QVariant(Utils::toUnderlyingValue(contact.profileInfo.type)); + } + case Role::UID: + return QVariant(QString::fromStdString(item.uid)); + case Role::ContextMenuOpen: + return QVariant(isContextMenuOpen_); + } + } catch (...) {} + } + return QVariant(); +} + +QModelIndex SmartListModel::index(int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(parent); + if (column != 0) { + return QModelIndex(); + } + + if (row >= 0 && row < rowCount()) { + return createIndex(row, column); + } + return QModelIndex(); +} + +QModelIndex SmartListModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child); + return QModelIndex(); +} + +Qt::ItemFlags SmartListModel::flags(const QModelIndex &index) const +{ + auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable; + auto type = Utils::toEnum<lrc::api::profile::Type>(data(index, Role::ContactType).value<int>()); + auto displayName = data(index, Role::DisplayName).value<QString>(); + auto uid = data(index, Role::UID).value<QString>(); + if (!index.isValid()) { + return QAbstractItemModel::flags(index); + } else if ( type == lrc::api::profile::Type::TEMPORARY && + uid.isEmpty()) { + flags &= ~(Qt::ItemIsSelectable); + } + return flags; +} diff --git a/smartlistmodel.h b/smartlistmodel.h new file mode 100644 index 0000000..9071599 --- /dev/null +++ b/smartlistmodel.h @@ -0,0 +1,70 @@ +/*************************************************************************** +* Copyright (C) 2017 by Savoir-faire Linux * +* Author: Anthony L�onard <anthony.leonard@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 + +// Qt include +#include <QAbstractItemModel> + +// LRC +#include "api/account.h" +#include "api/conversation.h" +#include "api/contact.h" + +#include "messagemodel.h" + +namespace lrc { namespace api { class ConversationModel; } } + +class SmartListModel : public QAbstractItemModel +{ + Q_OBJECT +public: + using AccountInfo = lrc::api::account::Info; + using ConversationInfo = lrc::api::conversation::Info; + using ContactInfo = lrc::api::contact::Info; + + + enum Role { + DisplayName = Qt::UserRole + 1, + DisplayID, + Picture, + Presence, + URI, + UnreadMessagesCount, + LastInteractionDate, + LastInteraction, + ContactType, + UID, + ContextMenuOpen + }; + + explicit SmartListModel(const lrc::api::account::Info& acc, QObject *parent = 0); + + // QAbstractItemModel + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + + bool isContextMenuOpen_{false}; + +private: + const AccountInfo& acc_; + +}; diff --git a/smartlistselectorbuttonnotifier.cpp b/smartlistselectorbuttonnotifier.cpp new file mode 100644 index 0000000..a7b3764 --- /dev/null +++ b/smartlistselectorbuttonnotifier.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2018 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 "smartlistselectorbuttonnotifier.h" + +#include "lrcinstance.h" +#include "ringthemeutils.h" + +#include "api/conversationmodel.h" + +#include <QPainter> + +SmartlistSelectorButtonNotifier::SmartlistSelectorButtonNotifier(QWidget *parent) + : QPushButton(parent) +{ +} + +void SmartlistSelectorButtonNotifier::setTypeFilter(lrc::api::profile::Type filter) +{ + typeFilter_ = filter; +} + +void +SmartlistSelectorButtonNotifier::paintEvent(QPaintEvent *event) +{ + // nb: don't paint the 'button' here! + // QPushButton::paintEvent(event); + Q_UNUSED(event); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + QFont font(painter.font()); + + int totalUnreadMessages = 0; + + using namespace lrc::api::profile; + switch (typeFilter_) { + case Type::RING: + { + auto convModel = LRCInstance::getCurrentConversationModel(); + auto ringConversations = convModel->getFilteredConversations(Type::RING); + std::for_each(ringConversations.begin(), ringConversations.end(), + [&totalUnreadMessages, convModel](const auto& conversation) { + totalUnreadMessages += convModel->getNumberOfUnreadMessagesFor(conversation.uid); + }); + break; + } + case Type::PENDING: + { + auto& accountInfo = LRCInstance::getCurrentAccountInfo(); + totalUnreadMessages = accountInfo.contactModel->pendingRequestCount(); + break; + } + default: + break; + } + + if (totalUnreadMessages) { + QString messageCountText = (totalUnreadMessages > 9) ? "9+" : QString::number(totalUnreadMessages); + qreal fontSize = messageCountText.count() > 1 ? 7 : 8; + font.setPointSize(fontSize); + + QRect buttonRect(this->rect()); + + // ellipse + QPainterPath ellipse; + qreal radius = buttonRect.width() / 2; + ellipse.addRoundedRect(buttonRect, radius, radius); + painter.fillPath(ellipse, RingTheme::notificationRed_); + + // text + painter.setPen(Qt::white); + painter.setOpacity(1); + painter.setFont(font); + buttonRect.setTop(buttonRect.top() - 2); + painter.drawText(buttonRect, Qt::AlignCenter, messageCountText); + } +} \ No newline at end of file diff --git a/combar.cpp b/smartlistselectorbuttonnotifier.h similarity index 66% rename from combar.cpp rename to smartlistselectorbuttonnotifier.h index 757f319..3a928c3 100644 --- a/combar.cpp +++ b/smartlistselectorbuttonnotifier.h @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * - * Author: Jäger Nicolas <nicolas.jager@savoirfairelinux.com> * + * Copyright (C) 2018 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 * @@ -15,24 +15,23 @@ * 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 "ui_combar.h" +#include "api/profile.h" +#include "smartlistselectorbuttonnotifier.h" -#include "combar.h" +#include <QPushButton> -ComBar::ComBar(QWidget* parent) : - QWidget(parent), - ui(new Ui::ComBar) +class SmartlistSelectorButtonNotifier : public QPushButton { - ui->setupUi(this); - connect(ui->btnComBarVideo, &QPushButton::clicked , this , [=](){ - emit btnVideoClicked(); - }); + Q_OBJECT -} +public: + SmartlistSelectorButtonNotifier(QWidget *parent = 0); + void setTypeFilter(lrc::api::profile::Type filter); -ComBar::~ComBar() -{ - disconnect(this); - delete ui; -} +protected: + virtual void paintEvent(QPaintEvent *event); + + lrc::api::profile::Type typeFilter_{ lrc::api::profile::Type::INVALID }; +}; \ No newline at end of file diff --git a/smartlistview.cpp b/smartlistview.cpp new file mode 100644 index 0000000..ae44423 --- /dev/null +++ b/smartlistview.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** + * Copyright (C) 2015-2017 by Savoir-faire Linux * + * Author: Jäger Nicolas <nicolas.jager@savoirfairelinux.com> * + * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * + * Author: Olivier Soldano <olivier.soldano@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 "smartlistview.h" + +#include "invitebuttonswidget.h" +#include "smartlistmodel.h" +#include "utils.h" + +#include <QScrollBar> +#include <QMouseEvent> +#include <QDebug> + +#include <ciso646> + +SmartListView::SmartListView(QWidget *parent) : + QTreeView(parent) +{ + verticalScrollBar()->setEnabled(true); + setVerticalScrollMode(ScrollPerPixel); + verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 0px; }"); + setDragEnabled(true); + setAcceptDrops(true); + setDropIndicatorShown(true); + setSelectionMode(QAbstractItemView::SingleSelection); + setMouseTracking(true); + installEventFilter(this); + + QObject::connect(this, &QAbstractItemView::entered, + [this](const QModelIndex & index) { + auto type = Utils::toEnum<lrc::api::profile::Type>( + index.data(static_cast<int>(SmartListModel::Role::ContactType)).value<int>() + ); + if (type == lrc::api::profile::Type::PENDING) { + auto widget = indexWidget(index); + if (!widget) { + InviteButtonsWidget* buttons = new InviteButtonsWidget(); + setIndexWidget(index, buttons); + + QObject::connect(buttons, &InviteButtonsWidget::btnAcceptInviteClicked, this, + [this, index]() { + hoveredRow_ = QModelIndex(); + emit btnAcceptInviteClicked(index); + }); + QObject::connect(buttons, &InviteButtonsWidget::btnIgnoreInviteClicked, this, + [this, index]() { + hoveredRow_ = QModelIndex(); + emit btnIgnoreInviteClicked(index); + }); + QObject::connect(buttons, &InviteButtonsWidget::btnBlockInviteClicked, this, + [this, index]() { + hoveredRow_ = QModelIndex(); + emit btnBlockInviteClicked(index); + }); + } + else { + widget->show(); + } + + if (hoveredRow_.isValid() && indexWidget(hoveredRow_)) { + indexWidget(hoveredRow_)->hide(); + } + + hoveredRow_ = index; + } + }); +} + +SmartListView::~SmartListView() +{ + reset(); +} + +void +SmartListView::enterEvent(QEvent* event) +{ + Q_UNUSED(event); +} + +void +SmartListView::leaveEvent(QEvent* event) +{ + Q_UNUSED(event); + hoveredRow_ = QModelIndex(); +} + +void +SmartListView::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::RightButton) { + emit customContextMenuRequested(event->pos()); + } + else { + QTreeView::mousePressEvent(event); + } +} + +bool +SmartListView::eventFilter(QObject* watched, QEvent* event) +{ + auto index = this->indexAt(static_cast<QMouseEvent*>(event)->pos()); + if (!index.isValid()) { + hoveredRow_ = QModelIndex(); + } + if (qobject_cast<QScrollBar*>(watched) && event->type() == QEvent::Enter) { + hoveredRow_ = QModelIndex(); + return true; + } + return QObject::eventFilter(watched, event); +} + +void +SmartListView::hideButtonsWidgets() +{ + auto model = this->model(); + if (!model) { + return; + } + for (int i = 0; i < model->rowCount(); ++i) { + auto index = model->index(i, 0); + if (index.isValid() && indexWidget(index)) { + qDebug() << "hide a ButtonsWidgets"; + indexWidget(index)->setVisible(false); + } + } +} + +void +SmartListView::drawRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + if (index == hoveredRow_ && indexWidget(hoveredRow_)) { + indexWidget(index)->setVisible(true); + } + else if (indexWidget(index)) { + indexWidget(index)->setVisible(false); + } + QTreeView::drawRow(painter, option, index); +} \ No newline at end of file diff --git a/smartlist.h b/smartlistview.h similarity index 75% rename from smartlist.h rename to smartlistview.h index 1dfa915..a7e6d89 100644 --- a/smartlist.h +++ b/smartlistview.h @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright (C) 2015-2017 by Savoir-faire Linux * * Author: Jäger Nicolas <nicolas.jager@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 * @@ -20,27 +21,29 @@ #include <QTreeView> -class SmartListDelegate; +class ConversationItemDelegate; -class SmartList : public QTreeView +class SmartListView : public QTreeView { Q_OBJECT public: - explicit SmartList(QWidget* parent = 0); - ~SmartList(); - void setSmartListItemDelegate(SmartListDelegate* delegate); + explicit SmartListView(QWidget* parent = 0); + ~SmartListView(); protected: void enterEvent(QEvent* event); void leaveEvent(QEvent* event); + void mousePressEvent(QMouseEvent *event); bool eventFilter(QObject* watched, QEvent* event); void drawRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; private: - SmartListDelegate* smartListDelegate_; - QPersistentModelIndex hoveredRow_; - void removeCombar(); + void hideButtonsWidgets(); + QModelIndex hoveredRow_; + +signals: + void btnAcceptInviteClicked(const QModelIndex& index) const; + void btnBlockInviteClicked(const QModelIndex& index) const; + void btnIgnoreInviteClicked(const QModelIndex& index) const; -signals: - void btnVideoClicked() const; }; diff --git a/stylesheet.css b/stylesheet.css index b5d7c35..285d674 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -26,6 +26,40 @@ QPushButton#refuseButton:pressed, QPushButton#cancelButton:pressed{ background-color: #db3c30; } +QPushButton#buttonConversations, QPushButton#buttonInvites { + background-color: rgb(242, 242, 242); + border-style: solid; + border-width: 0px; + border-radius: 5px; + padding: 8px; + color: rgb(32, 32, 32); +} + +QPushButton#buttonConversations:hover, QPushButton#buttonInvites:hover { + background-color: rgb(237, 237, 237); +} + +QPushButton#buttonConversations:pressed, QPushButton#buttonInvites:pressed { + background-color: rgb(212, 212, 212); +} + +QPushButton#btnAcceptInvite, QPushButton#btnIgnoreInvite, QPushButton#btnBlockInvite { + background-color: transparent; + border-style: solid; + border-width: 0px; + border-radius: 9px; + padding: 8px; + color: rgb(32, 32, 32); +} + +QPushButton#btnAcceptInvite:hover, QPushButton#btnIgnoreInvite:hover, QPushButton#btnBlockInvite:hover { + background-color: rgb(212, 212, 212); +} + +QPushButton#btnAcceptInvite:pressed, QPushButton#btnIgnoreInvite:pressed, QPushButton#btnBlockInvite:pressed { + background-color: rgb(187, 187, 187); +} + QWidget#callInvitePage, QWidget#outboundCallPage{ background-color : rgb(77, 77, 77); background-image : url(:/images/background-dark.png); @@ -54,7 +88,7 @@ QScrollBar::handle:vertical, QScrollBar::handle:horizontal{ background: rgb(255, 255, 255); } -SmartList, ContactRequestListWidget{ +SmartListView { background-color: white; border: none; } @@ -106,14 +140,14 @@ QListView#cipherListView::item:disabled background-color: transparent; } -SmartList::item:selected, QListView#accountView::item:selected, QListView#contactView::item:selected, -QTreeView#contactRequestList::item:selected, QListView#BannedList::item:selected{ +SmartListView::item:selected, QListView#accountView::item:selected, QListView#contactView::item:selected, +QListView#contactRequestList::item:selected, QListView#BannedList::item:selected { background-color: rgba(220, 220, 220, 255); border: none; } -SmartList::item:hover, QListView#accountView::item:hover, QListView#contactView::item:hover, -QTreeView#contactRequestList::item:hover, QListView#BannedList::item:hover{ +SmartListView::item:hover, QListView#accountView::item:hover, QListView#contactView::item:hover, +QListView#contactRequestList::item:hover, QListView#BannedList::item:hover { background-color: rgba(242, 242, 242, 255); } @@ -371,6 +405,7 @@ QComboBox{ border-style: solid; border-width: 2px; border-color: #414141; + border-bottom: transparent; border-top: transparent; border-left: transparent; border-right: transparent; @@ -378,10 +413,6 @@ QComboBox{ padding: 2px; } -QComboBox:focus{ - border-color: #3AC0D2; -} - QComboBox::down-arrow{ border-radius: 0px; border-style: solid; diff --git a/utils.cpp b/utils.cpp index 03864d8..5923946 100644 --- a/utils.cpp +++ b/utils.cpp @@ -1,6 +1,7 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * + * Copyright (C) 2015-2018 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 * @@ -27,13 +28,18 @@ #include <shlwapi.h> #endif - //Qt #include <QObject> #include <QErrorMessage> #include <QPainter> #include <QStackedWidget> #include <QPropertyAnimation> +#include <QApplication> + +#include "globalinstances.h" +#include "pixbufmanipulator.h" + +#include "globalsystemtray.h" bool Utils::CreateStartupLink() @@ -212,17 +218,161 @@ Utils::getCirclePhoto(const QImage original, int sizePhoto) } void -Utils::slidePage(QStackedWidget* stack, QWidget* widget, bool toRight) +Utils::setStackWidget(QStackedWidget* stack, QWidget* widget) { - if (stack->indexOf(widget) != -1 && stack->currentWidget() != widget){ - QPropertyAnimation* pageAnim = new QPropertyAnimation(); - int dir = (toRight ? -1 : 1); + if (stack->indexOf(widget) != -1 && stack->currentWidget() != widget) { stack->setCurrentWidget(widget); - 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(); } } + +void Utils::showSystemNotification(QWidget* widget, const QString & message, long delay) +{ + GlobalSystemTray::instance().showMessage("Ring", message); + QApplication::alert(widget, delay); +} + +// new lrc helpers + +inline std::string +removeEndlines(const std::string& str) +{ + std::string trimmed(str); + trimmed.erase(std::remove(trimmed.begin(), trimmed.end(), '\n'), trimmed.end()); + trimmed.erase(std::remove(trimmed.begin(), trimmed.end(), '\r'), trimmed.end()); + return trimmed; +} + +std::string +Utils::bestIdForConversation(const lrc::api::conversation::Info& conv, const lrc::api::ConversationModel& model) +{ + auto contact = model.owner.contactModel->getContact(conv.participants[0]); + if (!contact.registeredName.empty()) { + return removeEndlines(contact.registeredName); + } + return removeEndlines(contact.profileInfo.uri); +} + +std::string +Utils::bestIdForAccount(const lrc::api::account::Info& account) +{ + if (!account.registeredName.empty()) { + return removeEndlines(account.registeredName); + } + return removeEndlines(account.profileInfo.uri); +} + +std::string +Utils::bestNameForAccount(const lrc::api::account::Info& account) +{ + if (account.profileInfo.alias.empty()) { + return bestIdForAccount(account); + } + return account.profileInfo.alias; +} + +std::string +Utils::bestIdForContact(const lrc::api::contact::Info& contact) +{ + if (!contact.registeredName.empty()) { + return removeEndlines(contact.registeredName); + } + return removeEndlines(contact.profileInfo.uri); +} + +std::string +Utils::bestNameForContact(const lrc::api::contact::Info& contact) +{ + auto alias = removeEndlines(contact.profileInfo.alias); + if (alias.length() == 0) { + return bestIdForContact(contact); + } + return alias; +} + +std::string +Utils::bestNameForConversation(const lrc::api::conversation::Info& conv, const lrc::api::ConversationModel& model) +{ + auto contact = model.owner.contactModel->getContact(conv.participants[0]); + auto alias = removeEndlines(contact.profileInfo.alias); + if (alias.length() == 0) { + return bestIdForConversation(conv, model); + } + return alias; +} + +lrc::api::profile::Type +Utils::profileType(const lrc::api::conversation::Info& conv, const lrc::api::ConversationModel& model) +{ + try { + auto contact = model.owner.contactModel->getContact(conv.participants[0]); + return contact.profileInfo.type; + } + catch (...) { + return lrc::api::profile::Type::INVALID; + } +} + +std::string +Utils::formatTimeString(const std::time_t& timestamp) +{ + std::time_t now = std::time(nullptr); + char interactionDay[64]; + char nowDay[64]; + std::strftime(interactionDay, sizeof(interactionDay), "%D", std::localtime(×tamp)); + std::strftime(nowDay, sizeof(nowDay), "%D", std::localtime(&now)); + if (std::string(interactionDay) == std::string(nowDay)) { + char interactionTime[64]; + std::strftime(interactionTime, sizeof(interactionTime), "%R", std::localtime(×tamp)); + return interactionTime; + } + else { + return interactionDay; + } +} + +lrc::api::ConversationModel::ConversationQueue::const_iterator +Utils::getConversationFromUid(const std::string& uid, const lrc::api::ConversationModel& model) { + return std::find_if(model.allFilteredConversations().begin(), model.allFilteredConversations().end(), + [&](const lrc::api::conversation::Info& conv) { + return uid == conv.uid; + }); +} + +lrc::api::ConversationModel::ConversationQueue::const_iterator +Utils::getConversationFromUri(const std::string& uri, const lrc::api::ConversationModel& model) { + return std::find_if(model.allFilteredConversations().begin(), model.allFilteredConversations().end(), + [&](const lrc::api::conversation::Info& conv) { + return uri == conv.participants[0]; + }); +} + +bool +Utils::isInteractionGenerated(const lrc::api::interaction::Type& type) +{ + return type == lrc::api::interaction::Type::CALL || + type == lrc::api::interaction::Type::CONTACT; +} + +bool +Utils::isContactValid(const std::string& contactUid, const lrc::api::ConversationModel& model) +{ + auto contact = model.owner.contactModel->getContact(contactUid); + return (contact.profileInfo.type == lrc::api::profile::Type::PENDING || + contact.profileInfo.type == lrc::api::profile::Type::TEMPORARY || + contact.profileInfo.type == lrc::api::profile::Type::RING || + contact.profileInfo.type == lrc::api::profile::Type::SIP) && + !contact.profileInfo.uri.empty(); +} + +QImage +Utils::conversationPhoto(const std::string & convUid, const lrc::api::account::Info& accountInfo) +{ + auto& convModel = accountInfo.conversationModel; + auto conversation = Utils::getConversationFromUid(convUid, *convModel); + if (conversation == (*convModel).allFilteredConversations().end()) { + return QImage(); + } + + QVariant var = GlobalInstances::pixmapManipulator().decorationRole(*conversation, accountInfo); + return var.value<QImage>(); +} diff --git a/utils.h b/utils.h index cd21780..f304b31 100644 --- a/utils.h +++ b/utils.h @@ -1,6 +1,7 @@ /*************************************************************************** - * Copyright (C) 2015-2017 by Savoir-faire Linux * + * Copyright (C) 2015-2018 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 * @@ -24,6 +25,9 @@ #ifdef Q_OS_WIN #include <windows.h> #include <ciso646> +#undef OUT +#undef IN +#undef ERROR #else //LINUX #define LPCWSTR char* #endif @@ -33,6 +37,11 @@ #include <QImage> #include <QStackedWidget> +#include "api/conversationmodel.h" +#include "api/account.h" +#include "api/contactmodel.h" +#include "api/contact.h" + namespace Utils { constexpr int animDuration_ = 200; // animation duration for sliding page in ms @@ -47,6 +56,50 @@ namespace Utils QString GetCurrentUserName(); void InvokeMailto(const QString& subject, const QString& body, const QString& attachement = QString()); QImage getCirclePhoto(const QImage original, int sizePhoto); - void slidePage(QStackedWidget *stack, QWidget *widget, bool toRight = false); -} + void setStackWidget(QStackedWidget *stack, QWidget *widget); + void showSystemNotification(QWidget* widget, const QString& message, long delay = 5000); + + std::string bestIdForConversation(const lrc::api::conversation::Info& conv, const lrc::api::ConversationModel& model); + std::string bestIdForAccount(const lrc::api::account::Info & account); + std::string bestNameForAccount(const lrc::api::account::Info & account); + std::string bestIdForContact(const lrc::api::contact::Info & contact); + std::string bestNameForContact(const lrc::api::contact::Info & contact); + std::string bestNameForConversation(const lrc::api::conversation::Info & conv, const lrc::api::ConversationModel & model); + lrc::api::profile::Type profileType(const lrc::api::conversation::Info & conv, const lrc::api::ConversationModel & model); + std::string formatTimeString(const std::time_t& timestamp); + lrc::api::ConversationModel::ConversationQueue::const_iterator getConversationFromUid(const std::string& uid, const lrc::api::ConversationModel& model); + lrc::api::ConversationModel::ConversationQueue::const_iterator getConversationFromUri(const std::string& uri, const lrc::api::ConversationModel& model); + bool isInteractionGenerated(const lrc::api::interaction::Type& interaction); + bool isContactValid(const std::string& contactUid, const lrc::api::ConversationModel& model); + QImage conversationPhoto(const std::string& convUid, const lrc::api::account::Info& accountInfo); + // helpers + template<typename E> + constexpr inline typename std::enable_if< std::is_enum<E>::value, + typename std::underlying_type<E>::type + >::type + toUnderlyingValue(E e) noexcept + { + return static_cast<typename std::underlying_type<E>::type >(e); + } + + template<typename E, typename T> + constexpr inline typename std::enable_if< std::is_enum<E>::value && std::is_integral<T>::value, + E + >::type + toEnum(T value) noexcept + { + return static_cast<E>(value); + } + + template<typename T> + ptrdiff_t + indexInVector(const std::vector<T>& vec, const T& item) + { + auto it = std::find(vec.begin(), vec.end(), item); + if (it == vec.end()) { + return -1; + } + return std::distance(vec.begin(), it); + } +} diff --git a/videooverlay.cpp b/videooverlay.cpp index 572fbcb..f0706fe 100644 --- a/videooverlay.cpp +++ b/videooverlay.cpp @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright (C) 2015-2017 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 * @@ -28,7 +29,8 @@ #include "person.h" #include "account.h" - +#include "lrcinstance.h" +#include "utils.h" VideoOverlay::VideoOverlay(QWidget* parent) : QWidget(parent), @@ -38,70 +40,15 @@ VideoOverlay::VideoOverlay(QWidget* parent) : { ui->setupUi(this); + ui->bottomButtons->setMouseTracking(true); + ui->chatButton->setCheckable(true); - actionModel_ = CallModel::instance().userActionModel(); setAttribute(Qt::WA_NoSystemBackground); ui->noMicButton->setCheckable(true); - connect(actionModel_,&UserActionModel::dataChanged, [=](const QModelIndex& tl, const QModelIndex& br) { - const int first(tl.row()),last(br.row()); - for(int i = first; i <= last;i++) { - const QModelIndex& idx = actionModel_->index(i,0); - switch (idx.data(UserActionModel::Role::ACTION).value<UserActionModel::Action>()) { - case UserActionModel::Action::MUTE_AUDIO: - ui->noMicButton->setChecked(idx.data(Qt::CheckStateRole).value<bool>()); - ui->noMicButton->setEnabled(idx.flags() & Qt::ItemIsEnabled); - break; - case UserActionModel::Action::MUTE_VIDEO: - ui->noVideoButton->setChecked(idx.data(Qt::CheckStateRole).value<bool>()); - ui->noVideoButton->setEnabled(idx.flags() & Qt::ItemIsEnabled); - break; - case UserActionModel::Action::HOLD: - ui->holdButton->setChecked(idx.data(Qt::CheckStateRole).value<bool>()); - ui->holdButton->setEnabled(idx.flags() & Qt::ItemIsEnabled); - ui->onHoldLabel->setVisible(idx.data(Qt::CheckStateRole).value<bool>()); - break; - case UserActionModel::Action::RECORD: - ui->recButton->setChecked(idx.data(Qt::CheckStateRole).value<bool>()); - ui->recButton->setEnabled(idx.flags() & Qt::ItemIsEnabled); - default: - break; - } - } - }); - - connect(CallModel::instance().selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { - Q_UNUSED(previous) - Call* c = current.data(static_cast<int>(Call::Role::Object)).value<Call*>(); - if (c) { - if (c->hasParentCall()) { - ui->holdButton->hide(); - ui->transferButton->hide(); - ui->addPersonButton->hide(); - ui->chatButton->hide(); - - ui->joinButton->show(); - } else { - ui->holdButton->show(); - ui->transferButton->show(); - ui->addPersonButton->show(); - ui->chatButton->show(); - - ui->joinButton->hide(); - } - - if (auto* contactMethod = c->peerContactMethod()) - ui->addToContactButton->setVisible(not contactMethod->contact() - || contactMethod->contact()->isPlaceHolder()); - - if (auto* acc = c->account()) - ui->transferButton->setVisible(acc->isIp2ip()); - else - ui->transferButton->setVisible(false); // Hide transferButton as fallback so it is not displayed for Ring calls - } - }); + ui->onHoldLabel->setVisible(false); transferDialog_->setAttribute(Qt::WA_TranslucentBackground); connect(transferDialog_, &CallUtilsDialog::isVisible, [this] (bool visible) { @@ -142,10 +89,29 @@ void VideoOverlay::toggleContextButtons(bool visible) } } +void +VideoOverlay::setVideoMuteVisibility(bool visible) +{ + ui->noVideoButton->setVisible(visible); +} + +bool +VideoOverlay::shouldShowOverlay() +{ + return ui->bottomButtons->underMouse() || ui->topInfoBar->underMouse(); +} + void VideoOverlay::on_hangupButton_clicked() { - actionModel_->execute(UserActionModel::Action::HANGUP); + auto selectedConvUid = LRCInstance::getSelectedConvUid(); + auto conversation = Utils::getConversationFromUid(selectedConvUid, + *LRCInstance::getCurrentConversationModel()); + auto& callId = conversation->callId; + auto callModel = LRCInstance::getCurrentCallModel(); + if (callModel->hasCall(callId)) { + callModel->hangUp(callId); + } ui->chatButton->setChecked(false); } @@ -182,25 +148,52 @@ VideoOverlay::on_addPersonButton_clicked() void VideoOverlay::on_holdButton_clicked() { - actionModel_->execute(UserActionModel::Action::HOLD); + 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; + ui->holdButton->setChecked(!onHold); + ui->onHoldLabel->setVisible(!onHold); + callModel->togglePause(callId); + } } void VideoOverlay::on_noMicButton_clicked() { - actionModel_->execute(UserActionModel::Action::MUTE_AUDIO); + auto selectedConvUid = LRCInstance::getSelectedConvUid(); + auto conversation = Utils::getConversationFromUid(selectedConvUid, + *LRCInstance::getCurrentConversationModel()); + auto& callId = conversation->callId; + auto callModel = LRCInstance::getCurrentCallModel(); + if (callModel->hasCall(callId)) { + ui->noMicButton->setChecked(callModel->getCall(callId).audioMuted); + callModel->toggleMedia(callId, lrc::api::NewCallModel::Media::AUDIO); + } } void VideoOverlay::on_noVideoButton_clicked() { - actionModel_->execute(UserActionModel::Action::MUTE_VIDEO); + auto selectedConvUid = LRCInstance::getSelectedConvUid(); + auto conversation = Utils::getConversationFromUid(selectedConvUid, + *LRCInstance::getCurrentConversationModel()); + auto& callId = conversation->callId; + auto callModel = LRCInstance::getCurrentCallModel(); + if (callModel->hasCall(callId)) { + ui->noVideoButton->setChecked(callModel->getCall(callId).videoMuted); + callModel->toggleMedia(callId, lrc::api::NewCallModel::Media::VIDEO); + } } void VideoOverlay::on_joinButton_clicked() { - CallModel::instance().selectedCall()->joinToParent(); + // TODO:(newlrc) conferences + //CallModel::instance().selectedCall()->joinToParent(); } void @@ -214,22 +207,17 @@ VideoOverlay::on_qualityButton_clicked() qualityDialog_->show(); } -void -VideoOverlay::on_addToContactButton_clicked() -{ - QPoint globalPos = mapToGlobal(ui->addToContactButton->pos()); - if (auto contactMethod = CallModel::instance().selectedCall()->peerContactMethod()) { - ContactPicker contactPicker(contactMethod); - contactPicker.move(globalPos.x(), - globalPos.y() + ui->addToContactButton->height()); - contactPicker.exec(); - } -} - void VideoOverlay::on_recButton_clicked() { - actionModel_->execute(UserActionModel::Action::RECORD); + 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); + } } void VideoOverlay::on_videoCfgBtn_clicked() diff --git a/videooverlay.h b/videooverlay.h index 002a9aa..bf49b1f 100644 --- a/videooverlay.h +++ b/videooverlay.h @@ -43,6 +43,8 @@ public: void setTime(const QString& time); inline bool isDialogVisible(){ return dialogVisible_; }; void toggleContextButtons(bool visible); + void setVideoMuteVisibility(bool visible); + bool shouldShowOverlay(); //UI SLOTS private slots: @@ -55,13 +57,11 @@ private slots: void on_noMicButton_clicked(); void on_noVideoButton_clicked(); void on_qualityButton_clicked(); - void on_addToContactButton_clicked(); void on_recButton_clicked(); void on_videoCfgBtn_clicked(); private: Ui::VideoOverlay* ui; - UserActionModel* actionModel_; CallUtilsDialog* transferDialog_; QualityDialog* qualityDialog_; bool dialogVisible_ = false; diff --git a/videooverlay.ui b/videooverlay.ui index 9697ad0..956d5bb 100644 --- a/videooverlay.ui +++ b/videooverlay.ui @@ -23,8 +23,523 @@ <string/> </property> <layout class="QGridLayout" name="gridLayout" rowstretch="0,1,0" columnstretch="0,0,2,0,0"> - <item row="1" column="2"> + <item row="2" column="0" colspan="5"> + <widget class="QWidget" name="bottomButtons" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="hangupButton"> + <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>Hangup</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_close_white_24dp.png</normaloff>:/images/icons/ic_close_white_24dp.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="holdButton"> + <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>Hold / Unhold</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_pause_white_24dp.png</normaloff>:/images/icons/ic_pause_white_24dp.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="chatButton"> + <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>Chat</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_chat_white_24dp.png</normaloff>:/images/icons/ic_chat_white_24dp.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="addPersonButton"> + <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>Add person to call</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_person_add_white_24dp.png</normaloff>:/images/icons/ic_person_add_white_24dp.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="transferButton"> + <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 call</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_call_transfer_white_24px.png</normaloff>:/images/icons/ic_call_transfer_white_24px.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="noMicButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <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>Mute Mic</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_mic_off_white_24dp.png</normaloff>:/images/icons/ic_mic_off_white_24dp.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="noVideoButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <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>Mute Video</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_videocam_off_white_24dp.png</normaloff>:/images/icons/ic_videocam_off_white_24dp.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="recButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <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>Record call</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_voicemail_white_24dp_2x.png</normaloff>:/images/icons/ic_voicemail_white_24dp_2x.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="qualityButton"> + <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>Quality</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_high_quality_white_24dp.png</normaloff>:/images/icons/ic_high_quality_white_24dp.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="joinButton"> + <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>Join Calls</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_group_add_white_24dp.png</normaloff>:/images/icons/ic_group_add_white_24dp.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item row="0" column="2"> + <widget class="QWidget" name="topInfoBar" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <item> + <widget class="QLabel" name="nameLabel"> + <property name="palette"> + <palette> + <active> + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + </active> + <inactive> + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + </inactive> + <disabled> + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>143</red> + <green>146</green> + <blue>147</blue> + </color> + </brush> + </colorrole> + </disabled> + </palette> + </property> + <property name="toolTip"> + <string>Name label</string> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="timerLabel"> + <property name="palette"> + <palette> + <active> + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + </active> + <inactive> + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + </inactive> + <disabled> + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>143</red> + <green>146</green> + <blue>147</blue> + </color> + </brush> + </colorrole> + </disabled> + </palette> + </property> + <property name="toolTip"> + <string>Time elapsed</string> + </property> + <property name="text"> + <string>00:00</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="videoCfgBtn"> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="toolTip"> + <string>Configuration</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="ressources.qrc"> + <normaloff>:/images/icons/ic_settings_white_48dp_2x.png</normaloff>:/images/icons/ic_settings_white_48dp_2x.png</iconset> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0" colspan="5"> <layout class="QHBoxLayout" name="horizontalLayout_5"> + <property name="spacing"> + <number>7</number> + </property> <item alignment="Qt::AlignHCenter|Qt::AlignVCenter"> <widget class="QLabel" name="onHoldLabel"> <property name="minimumSize"> @@ -54,546 +569,6 @@ </item> </layout> </item> - <item row="2" column="0" colspan="5"> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="hangupButton"> - <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>Hangup</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_close_white_24dp.png</normaloff>:/images/icons/ic_close_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="holdButton"> - <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>Hold / Unhold</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_pause_white_24dp.png</normaloff>:/images/icons/ic_pause_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="chatButton"> - <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>Chat</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_chat_white_24dp.png</normaloff>:/images/icons/ic_chat_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="addPersonButton"> - <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>Add person to call</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_person_add_white_24dp.png</normaloff>:/images/icons/ic_person_add_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="transferButton"> - <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 call</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_call_transfer_white_24px.png</normaloff>:/images/icons/ic_call_transfer_white_24px.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="noMicButton"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <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>Mute Mic</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_mic_off_white_24dp.png</normaloff>:/images/icons/ic_mic_off_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="noVideoButton"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <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>Mute Video</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_videocam_off_white_24dp.png</normaloff>:/images/icons/ic_videocam_off_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="recButton"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <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>Record call</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_voicemail_white_24dp_2x.png</normaloff>:/images/icons/ic_voicemail_white_24dp_2x.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="qualityButton"> - <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>Quality</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_high_quality_white_24dp.png</normaloff>:/images/icons/ic_high_quality_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="joinButton"> - <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>Join Calls</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_group_add_white_24dp.png</normaloff>:/images/icons/ic_group_add_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item row="0" column="2"> - <layout class="QHBoxLayout" name="horizontalLayout_7"> - <item> - <widget class="QLabel" name="nameLabel"> - <property name="palette"> - <palette> - <active> - <colorrole role="WindowText"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>255</blue> - </color> - </brush> - </colorrole> - </active> - <inactive> - <colorrole role="WindowText"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>255</blue> - </color> - </brush> - </colorrole> - </inactive> - <disabled> - <colorrole role="WindowText"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>143</red> - <green>146</green> - <blue>147</blue> - </color> - </brush> - </colorrole> - </disabled> - </palette> - </property> - <property name="toolTip"> - <string>Name label</string> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="addToContactButton"> - <property name="minimumSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - <property name="toolTip"> - <string>Add to contact</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_person_add_white_24dp.png</normaloff>:/images/icons/ic_person_add_white_24dp.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>18</width> - <height>18</height> - </size> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="timerLabel"> - <property name="palette"> - <palette> - <active> - <colorrole role="WindowText"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>255</blue> - </color> - </brush> - </colorrole> - </active> - <inactive> - <colorrole role="WindowText"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>255</blue> - </color> - </brush> - </colorrole> - </inactive> - <disabled> - <colorrole role="WindowText"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>143</red> - <green>146</green> - <blue>147</blue> - </color> - </brush> - </colorrole> - </disabled> - </palette> - </property> - <property name="toolTip"> - <string>Time elapsed</string> - </property> - <property name="text"> - <string>00:00</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="videoCfgBtn"> - <property name="minimumSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - <property name="toolTip"> - <string>Configuration</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="ressources.qrc"> - <normaloff>:/images/icons/ic_settings_white_48dp_2x.png</normaloff>:/images/icons/ic_settings_white_48dp_2x.png</iconset> - </property> - </widget> - </item> - </layout> - </item> </layout> </widget> <resources> diff --git a/videoview.cpp b/videoview.cpp index b88f82e..5a9c70a 100644 --- a/videoview.cpp +++ b/videoview.cpp @@ -19,6 +19,9 @@ #include "videoview.h" #include "ui_videoview.h" +#include "utils.h" +#include "lrcinstance.h" + #include "video/devicemodel.h" #include "video/sourcemodel.h" #include "recentmodel.h" @@ -46,7 +49,7 @@ VideoView::VideoView(QWidget* parent) : connect(&CallModel::instance(), SIGNAL(callStateChanged(Call*, Call::State)), this, SLOT(callStateChanged(Call*, Call::State))); - + overlay_ = new VideoOverlay(this); auto effect = new QGraphicsOpacityEffect(overlay_); effect->setOpacity(maxOverlayOpacity_); @@ -58,7 +61,7 @@ VideoView::VideoView(QWidget* parent) : fadeAnim_->setStartValue(effect->opacity()); fadeAnim_->setEndValue(0); fadeAnim_->setEasingCurve(QEasingCurve::OutQuad); - + // Setup the timer to start the fade when the mouse stops moving this->setMouseTracking(true); overlay_->setMouseTracking(true); @@ -145,8 +148,9 @@ VideoView::showOverlay() void VideoView::fadeOverlayOut() { - if (not overlay_->isDialogVisible()) + if (!overlay_->isDialogVisible() && !overlay_->shouldShowOverlay()) { fadeAnim_->start(QAbstractAnimation::KeepWhenStopped); + } } void @@ -192,8 +196,19 @@ void VideoView::dropEvent(QDropEvent* event) { auto urls = event->mimeData()->urls(); - if (auto call = CallModel::instance().selectedCall()) { - if (auto outVideo = call->firstMedia<media::Video>(media::Media::Direction::OUT)) { + auto selectedConvUid = LRCInstance::getSelectedConvUid(); + auto convModel = LRCInstance::getCurrentConversationModel(); + auto conversation = Utils::getConversationFromUid(selectedConvUid, *convModel); + auto callList = CallModel::instance().getActiveCalls(); + Call* thisCall = nullptr; + for (auto call : callList) { + if (call->historyId() == QString::fromStdString(conversation->callId)) { + thisCall = call; + break; + } + } + if (thisCall) { + if (auto outVideo = thisCall->firstMedia<media::Video>(media::Media::Direction::OUT)) { outVideo->sourceModel()->setFile(urls.at(0)); } } @@ -225,8 +240,19 @@ VideoView::showContextMenu(const QPoint& pos) media::Video* outVideo = nullptr; int activeIndex = -1; - if (auto call = CallModel::instance().selectedCall()) { - outVideo = call->firstMedia<media::Video>(media::Media::Direction::OUT); + auto selectedConvUid = LRCInstance::getSelectedConvUid(); + auto convModel = LRCInstance::getCurrentConversationModel(); + auto conversation = Utils::getConversationFromUid(selectedConvUid, *convModel); + auto callList = CallModel::instance().getActiveCalls(); + Call* thisCall = nullptr; + for (auto call : callList) { + if (call->historyId() == QString::fromStdString(conversation->callId)) { + thisCall = call; + break; + } + } + if (thisCall) { + outVideo = thisCall->firstMedia<media::Video>(media::Media::Direction::OUT); if (outVideo) activeIndex = outVideo->sourceModel()->activeIndex(); } @@ -315,6 +341,26 @@ VideoView::pushRenderer(Call* call) { ui->videoWidget->setPreviewDisplay(call->type() != Call::Type::CONFERENCE); } +void +VideoView::pushRenderer(const std::string& callUid) { + auto callModel = LRCInstance::getCurrentCallModel(); + + QObject::disconnect(videoStartedConnection_); + if (!callModel->hasCall(callUid)) { + return; + } + + auto call = callModel->getCall(callUid); + + videoStartedConnection_ = QObject::connect(callModel, &lrc::api::NewCallModel::remotePreviewStarted, + [this](const std::string& callId, Video::Renderer* renderer) { + Q_UNUSED(callId); + slotVideoStarted(renderer); + this->overlay_->setVideoMuteVisibility(LRCInstance::getCurrentCallModel()->getCall(callId).isAudioOnly); + }); + ui->videoWidget->setPreviewDisplay(call.type != lrc::api::call::Type::CONFERENCE); +} + void VideoView::slotVideoStarted(Video::Renderer* renderer) { ui->videoWidget->show(); @@ -357,7 +403,7 @@ VideoView::mouseMoveEvent(QMouseEvent* event) } else { fadeTimer_.start(startfadeOverlayTime_); } - + QRect& previewRect = ui->videoWidget->getPreviewRect(); if (draggingPreview_) { if (previewRect.left() > 0 diff --git a/videoview.h b/videoview.h index 159c373..41f02f0 100644 --- a/videoview.h +++ b/videoview.h @@ -37,6 +37,7 @@ public: explicit VideoView(QWidget* parent = 0); ~VideoView(); void pushRenderer(Call* call); + void pushRenderer(const std::string& callUid); protected: void resizeEvent(QResizeEvent* event); @@ -80,7 +81,7 @@ private: constexpr static int startfadeOverlayTime_ = 2000; //msec // TODO: fix when changing Qt version - // Full(1.0) opacity bug affecting many Qt version (macOS + win10) + // Full(1.0) opacity bug affecting many Qt versions (macOS + win10) // causing the render to take a buggy code path which can be avoided // by using opacity values other than precisely 1.0. // https://bugreports.qt.io/browse/QTBUG-65981 diff --git a/wizarddialog.cpp b/wizarddialog.cpp index 7fedb37..c315334 100644 --- a/wizarddialog.cpp +++ b/wizarddialog.cpp @@ -3,6 +3,7 @@ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * * Author: Olivier Soldano <olivier.soldano@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 * @@ -35,7 +36,7 @@ const QString DEFAULT_RING_ACCT_ALIAS = QObject::tr("Ring account", "Default alias for new Ring account"); -WizardDialog::WizardDialog(WizardMode wizardMode, Account* toBeMigrated, QWidget* parent) : +WizardDialog::WizardDialog(WizardMode wizardMode, AccountInfo* toBeMigrated, QWidget* parent) : QDialog(parent), ui(new Ui::WizardDialog), account_(toBeMigrated), @@ -61,9 +62,9 @@ WizardDialog::WizardDialog(WizardMode wizardMode, Account* toBeMigrated, QWidget movie_->start(); if (wizardMode_ == MIGRATION) { - Utils::slidePage(ui->stackedWidget, ui->profilePage); + Utils::setStackWidget(ui->stackedWidget, ui->profilePage); ui->usernameEdit->setEnabled(false); - ui->usernameEdit->setText(toBeMigrated->displayName()); + ui->usernameEdit->setText(QString::fromStdString(toBeMigrated->profileInfo.alias)); ui->previousButton->hide(); ui->photoBooth->hide(); ui->pinEdit->hide(); @@ -126,57 +127,9 @@ WizardDialog::processWizardInformations() ui->pinEdit->clear(); } - ui->navBarWidget->hide(); - Utils::slidePage(ui->stackedWidget, ui->spinnerPage); - repaint(); Utils::CreateStartupLink(); } -void -WizardDialog::endSetup(Account::RegistrationState state) -{ -#pragma push_macro("ERROR") -#undef ERROR - switch (state) { - case Account::RegistrationState::UNREGISTERED: - case Account::RegistrationState::READY: - if (ui->signUpCheckbox->isChecked()) { // If the user wants to register its name on the blockchain - bool regSuccess = account_->registerName(ui->passwordEdit->text(), ui->usernameEdit->text()); - ui->usernameEdit->clear(); - if (!regSuccess) { - usernameFailedRegistration(); - } else { - connect(account_, SIGNAL(nameRegistrationEnded(NameDirectory::RegisterNameStatus,QString)), - this, SLOT(handle_nameRegistrationEnded(NameDirectory::RegisterNameStatus,QString))); - ui->progressLabel->setText(tr("Registering your public username, it may take a few minutes...")); - } - } else { - account_->performAction(Account::EditAction::RELOAD); - accept(); - } - - { //avoid scope crossing init - auto profile = ProfileModel::instance().selectedProfile(); - if (profile && AccountModel::instance().size() == 1) { - profile->setAccounts({account_}); - profile->save(); - } - } - break; - case Account::RegistrationState::ERROR: - ui->spinnerLabel->hide(); - ui->navBarWidget->show(); - ui->nextButton->hide(); - ui->progressLabel->setText(tr("An error has occured during your account creation")); - AccountModel::instance().remove(account_); - break; - case Account::RegistrationState::TRYING: - case Account::RegistrationState::COUNT__: - break; - } -#pragma pop_macro("ERROR") -} - void WizardDialog::closeEvent(QCloseEvent* event) { @@ -188,12 +141,6 @@ WizardDialog::closeEvent(QCloseEvent* event) } } -void -WizardDialog::usernameFailedRegistration() -{ - QMessageBox::warning(this, "Username not registered", "Your account has been created, but we could not register your username. Try again from the settings menu."); -} - void WizardDialog::on_photoTaken(QString fileName) { @@ -210,7 +157,7 @@ WizardDialog::on_existingPushButton_clicked() { ui->navBarWidget->show(); ui->nextButton->hide(); - Utils::slidePage(ui->stackedWidget, ui->linkMethodPage); + Utils::setStackWidget(ui->stackedWidget, ui->linkMethodPage); } void @@ -225,11 +172,11 @@ WizardDialog::changePage(bool existingAccount) { if (existingAccount) { // If user want to add a device ui->accountLabel->setText(tr("Add a device")); - Utils::slidePage(ui->stackedWidget, ui->explanationPage); + Utils::setStackWidget(ui->stackedWidget, ui->explanationPage); ui->photoBooth->hide(); } else { // If user want to create a new account ui->accountLabel->setText(tr("Create your account")); - Utils::slidePage(ui->stackedWidget, ui->profilePage); + Utils::setStackWidget(ui->stackedWidget, ui->profilePage); ui->photoBooth->startBooth(); ui->photoBooth->show(); } @@ -249,9 +196,11 @@ void WizardDialog::on_nextButton_clicked() { const QWidget* curWidget = ui->stackedWidget->currentWidget(); - + if (curWidget == ui->profilePage) { + ui->photoBooth->stopBooth(); + } if (curWidget == ui->profilePage || curWidget == ui->explanationPage) { - Utils::slidePage(ui->stackedWidget, ui->accountPage); + Utils::setStackWidget(ui->stackedWidget, ui->accountPage); } else if (curWidget == ui->accountPage) { processWizardInformations(); } else if (curWidget == ui->fileImportPage) { @@ -266,17 +215,21 @@ WizardDialog::on_previousButton_clicked() if (curWidget == ui->profilePage) { ui->navBarWidget->hide(); - Utils::slidePage(ui->stackedWidget, ui->welcomePage); + Utils::setStackWidget(ui->stackedWidget, ui->welcomePage); } else if (curWidget == ui->explanationPage || curWidget == ui->fileImportPage) { ui->navBarWidget->show(); ui->nextButton->hide(); - Utils::slidePage(ui->stackedWidget, ui->linkMethodPage); + Utils::setStackWidget(ui->stackedWidget, ui->linkMethodPage); } else if (curWidget == ui->accountPage) { - if (ui->pinEdit->isVisible()) // If we are adding a device - Utils::slidePage(ui->stackedWidget, ui->explanationPage); - else // If we are creating a new account - Utils::slidePage(ui->stackedWidget, ui->profilePage); + if (ui->pinEdit->isVisible()) { + // If we are adding a device + Utils::setStackWidget(ui->stackedWidget, ui->explanationPage); + } else { + ui->photoBooth->startBooth(); + ui->photoBooth->show(); + Utils::setStackWidget(ui->stackedWidget, ui->profilePage); + } ui->passwordEdit->setStyleSheet("border-color: rgb(0, 192, 212);"); ui->confirmPasswordEdit->setStyleSheet("border-color: rgb(0, 192, 212);"); @@ -285,11 +238,11 @@ WizardDialog::on_previousButton_clicked() } else if (curWidget == ui->linkMethodPage) { ui->navBarWidget->hide(); ui->nextButton->show(); - Utils::slidePage(ui->stackedWidget, ui->welcomePage); + Utils::setStackWidget(ui->stackedWidget, ui->welcomePage); } else if (curWidget == ui->spinnerPage) { ui->nextButton->show(); ui->navBarWidget->hide(); - Utils::slidePage(ui->stackedWidget, ui->welcomePage); + Utils::setStackWidget(ui->stackedWidget, ui->welcomePage); } } @@ -354,14 +307,8 @@ WizardDialog::handle_registeredNameFound (Account* account, NameDirectory::Looku void WizardDialog::handle_nameRegistrationEnded(NameDirectory::RegisterNameStatus status, const QString& name) { - Q_UNUSED(name) - - disconnect(account_, SIGNAL(nameRegistrationEnded(NameDirectory::RegisterNameStatus,QString)), - this, SLOT(handle_nameRegistrationEnded(NameDirectory::RegisterNameStatus,QString))); - if(status != NameDirectory::RegisterNameStatus::SUCCESS) { - usernameFailedRegistration(); - } - account_->performAction(Account::EditAction::RELOAD); + Q_UNUSED(name); + Q_UNUSED(status); accept(); } @@ -417,35 +364,30 @@ WizardDialog::createRingAccount(const QString &displayName, const QString &pin, const QString &archivePath) { - QString alias = (displayName.isEmpty() || displayName.isNull()) ? DEFAULT_RING_ACCT_ALIAS : - displayName; - // set display name - account_ = AccountModel::instance().add(alias, Account::Protocol::RING); - account_->setDisplayName(alias); - - // archive properties - account_->setArchivePassword(password); - // import from DHT - if (!pin.isEmpty() && !pin.isNull()) - account_->setArchivePin(pin); - // import from file - if (!archivePath.isEmpty() && !archivePath.isNull()) - account_->setArchivePath(archivePath); - - // set default UPNP behavior - account_->setUpnpEnabled(true); - - //set default ringtone - account_->setRingtonePath(Utils::GetRingtonePath()); - - connect(account_, &Account::stateChanged, this, &WizardDialog::endSetup); - - account_->performAction(Account::EditAction::SAVE); - auto profile = ProfileModel::instance().selectedProfile(); - if (profile && AccountModel::instance().size() == 1) { - profile->person()->setFormattedName(alias); - } + QtConcurrent::run( + [=] { + LRCInstance::accountModel().createNewAccount( + lrc::api::profile::Type::RING, + displayName.toStdString(), + archivePath.toStdString(), + password.toStdString(), + pin.toStdString() + ); + }); + + connect(&LRCInstance::accountModel(), + &lrc::api::NewAccountModel::accountAdded, + [this](const std::string& accountId) { + //set default ringtone + auto confProps = LRCInstance::accountModel().getAccountConfig(accountId); + confProps.Ringtone.ringtonePath = Utils::GetRingtonePath().toStdString(); + LRCInstance::accountModel().setAccountConfig(accountId, confProps); + accept(); + }); + ui->navBarWidget->hide(); + Utils::setStackWidget(ui->stackedWidget, ui->spinnerPage); + repaint(); } void @@ -461,6 +403,6 @@ WizardDialog::on_fileImportBtn_clicked() ui->navBarWidget->show(); ui->nextButton->show(); wizardMode_ = IMPORT; - Utils::slidePage(ui->stackedWidget, ui->fileImportPage); + Utils::setStackWidget(ui->stackedWidget, ui->fileImportPage); } diff --git a/wizarddialog.h b/wizarddialog.h index 097c1c1..6d4cfda 100644 --- a/wizarddialog.h +++ b/wizarddialog.h @@ -26,6 +26,9 @@ #include "account.h" #include "person.h" +// new lrc +#include "lrcinstance.h" + namespace Ui { class WizardDialog; } @@ -35,6 +38,8 @@ class WizardDialog : public QDialog Q_OBJECT public: + using AccountInfo = lrc::api::account::Info; + enum WizardMode { WIZARD, NEW_ACCOUNT, @@ -43,7 +48,7 @@ public: }; public: - explicit WizardDialog(WizardMode wizardMode = WIZARD, Account* toBeMigrated = nullptr, QWidget* parent = 0); + explicit WizardDialog(WizardMode wizardMode = WIZARD, AccountInfo* toBeMigrated = nullptr, QWidget* parent = 0); ~WizardDialog(); //UI Slots @@ -55,7 +60,6 @@ private slots: void on_passwordEdit_textChanged(const QString& arg1); private slots: - void endSetup(Account::RegistrationState state); void on_usernameEdit_textChanged(const QString& arg1); void handle_registeredNameFound(Account *account, NameDirectory::LookupStatus status, const QString& address, const QString& name); void handle_nameRegistrationEnded(NameDirectory::RegisterNameStatus status, const QString& name); @@ -69,14 +73,13 @@ private slots: private: Ui::WizardDialog* ui; - Account* account_; + AccountInfo* account_; WizardMode wizardMode_; QMovie* movie_; QTimer nameLookupTimer_; void setup(); void changePage(bool existingAccount); - void usernameFailedRegistration(); void validateFileImport(); void createRingAccount(const QString &displayName = QString(), const QString &password = QString(), -- GitLab