diff --git a/RingWinClient.pro b/RingWinClient.pro index 06c6805249706095f9ba2d4b48df47af4a04019f..af7e37b988a2a4090530782084ce018570494f8d 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 0000000000000000000000000000000000000000..346d750fb31e7e8ffb421d97971b2066692d80c8 --- /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 2b5e413c6f6a14999455288983d2b2e25869b9a2..c3a798c5e93bb495c7d4cec16a78c869cc947c99 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 0000000000000000000000000000000000000000..fb7b2da67c09bd9fc45b7fb17502c70b79e09425 --- /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 0000000000000000000000000000000000000000..127cb882b379d4a6dc9459c569dbcc81c3c71b80 --- /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 db2453bb68326ad5c0f00bb6b2aae54b32040058..5e416204c0b4e67f973ca93e879d37728a87189a 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 0ab44910d296b0a3aa10ac65cf99fda8557bfdc3..e4b913071e5de5e7323f2491778a5f45132c3b8c 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 e15cf7d388142e4336ed80700cd467818e699172..e41a38ede14dbc03ea643fd8bb4756b2014bdd88 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 f77d82e865221b5b3984291cd3637ace82fca71f..9fb61784f72a017dc44b56acba807ac03588dfdd 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 7b7031a5eed7bb09f11007245172c30f84f4c5ca..1efddad91acef5757365da37d8926e46c31ae2f6 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 8b9e661f23757abaaf6c4f5a6e9e03f1fe2b61e6..0000000000000000000000000000000000000000 --- 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 67e93886f31d11ac4202a79a04283c444d854214..81f9b554ab8ba7c273363fb8a9e405d5df17726c 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 9d7d11ac0fe539da1c440601915780b8639627ac..0000000000000000000000000000000000000000 --- 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 489ab98f9d02d64170032e474e155207d62952bb..0000000000000000000000000000000000000000 --- 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 338d2df865d5a4194c399d747f62b20ed459f6a9..0000000000000000000000000000000000000000 --- 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 6e6d9f6bf4013b8545df6e6022ebccd2fe6a1451..0000000000000000000000000000000000000000 --- 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 1e74d391d874d89951c8d40d3ce0118c281e3b7f..0000000000000000000000000000000000000000 --- 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 4dc61e3ef558efe6bd98c2823e493d2dcf19c37c..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..f260519a90d68e438ce75f4116a734f5a269bbef --- /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 2d059e34e1f344c7ff3578a37e3f5ceb08268990..249d77bac8351f7c0912e7a72295b58a42565db3 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 0000000000000000000000000000000000000000..07abdf517c91e3a9a85a7db96548827e2e3e9c5a --- /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 b74c292a7e4dc0b9f2a170dcc2a8b6cc64bc083b..1ce9eefe69938b0aa8e1f24a325c5e76c74909b8 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 96932173cc5534cc7fadf74a69c3f22607489c55..a339061dbf206c19be5462b912b7b07a719c00d5 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 10d01f695bd252fea479f72371641ef65bfd0ea6..20f5f46c6bb5e9f1be1c1edca6b4d2296d21361f 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 51b5cee3b3bbc611f2775eefc6fbae2287cf77bf..c10708bf078037708f76d5766f6df4e3a96a68b3 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 85c15f0d07c92956a440ba9bd5e4175518e0ed7e..0000000000000000000000000000000000000000 --- 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 fa97857f0be0b8de0e09434d66bd26e329773cef..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..8032acfdf2e1f2ee3ab275f9482b6556f6d3032c --- /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 0000000000000000000000000000000000000000..dea86781d3ed7f12339a84930570bc4788e89803 --- /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 55f10d03b8f8a9e51817a417253626872811a64d..6c130488c685eef4ad8d763f5aaa12c37c1ade43 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 5a6151a1693bbeffbb12320266d86b48b00faa6c..c422610ef44690c4d6f1e19252cdd5660fba319e 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 95cce48958e86ccd0a51e102cfc982850c53692d..94739506f33b61e12964536010c98922f08e2aae 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 792f6549de1386a6657448188006be47da930cb5..ee18f90c02679c1d97d79068c6f15f1688b818a9 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 ca0188982ce0a1bbeef3c561815a9cb381a455d6..7e1919bae1307a8e14a3ec5a36ad89ecb5dddd3b 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 0000000000000000000000000000000000000000..e1f8bf21d744ce72ec2cf337a577f617f6a48b07 --- /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 573f7d3f68ba8a16066461b096daadc18c8f813a..e92dd3450e241b352e072bbe9d3436d0f0c6d590 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 61dec93fd171141fe6aafb65d0b3c938321e7f83..a0284ab08da1bbc6bbd63d965dc2c1c248531117 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 c3cd8f69a9934ae59ff9f708380180e392fd62bb..c6abaec3c0db0a51682d43653a3dfb99ae5fd923 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 0000000000000000000000000000000000000000..998c97f7eb5113f42577ed840831a5f530a46891 --- /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 0000000000000000000000000000000000000000..b8411c37c60501a9af56c05dbfedf557ac69ceb7 --- /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 537f544399ce96425c527ecdded15d1cdf5b0222..ded23f4eb903f905f6aa38638dd7e0d4a567bf8a 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 3ca4956a6a8b507a419cbfcf6e0d5838da322570..f0fe02e8513ad58ba6fb938a4de0c02abdd925d2 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 4155e5d554dd88554fc5aeb2dd31e15be02e45b3..8bbe96af6cc67e6c118368033752c7a21f900a10 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 020d9e6dc57f419e5870479d6afbc510bdef321d..0000000000000000000000000000000000000000 --- 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 e93b7c12702de4f4fffd52917e00e4a39f479ed3..fa041061af96e018d1a9a4bae9473fda54c34985 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 9ee5b4112d5e9d0a8b474b0f40fec1fdd8d1b7f0..0000000000000000000000000000000000000000 --- 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 f2e9245d7fcef9eedea3db16e5061990ea50210b..222923c254e432fa3952dc76e671e6d3be14d29d 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 d092da0b32f201b9ad4038d4e1fde196e6697fdc..cb7f54bfcad3314710d9650a58414066a238500c 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 a777fabdf83eac57a2f4c90ece5d672497425cb8..276995b28b93ae79447d640b23a12f50fe4ee0b9 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 da8e504baa268b077db5e686ca07000ef07cab76..8b77e733b3f4f7d7d34e7a31e4e7217e16d039db 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 9fd4234c27928fac71b4f24dab1b8547a83d93ed..8a2453ab43d2bdf50fceb8ac25bdc2fc2ff87844 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 21db00e2f101f64f53480855c4473c0d334e34e1..0000000000000000000000000000000000000000 --- 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 cb9d9644ee62122e278bd3f725c01a1daec718c4..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..d767a0360e4e037aa52e86dfb552a61ad511a0a8 --- /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 0000000000000000000000000000000000000000..907159993ebdecbbad6594825133208d077d3387 --- /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 0000000000000000000000000000000000000000..a7b3764add72de8087c8a67319a7d73c8386cbed --- /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 757f319a89d262ac221ede4abf997511222aed83..3a928c334a1f644822baaf64886e381daf6f2590 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 0000000000000000000000000000000000000000..ae44423122c58667de061ecf65c92ccc22dcd330 --- /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 1dfa9156ca136f8daab44aae6e7fec3dc773e028..a7e6d892e547bfa0932721dbbd72b13ed02ec86b 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 b5d7c3535a0f210095fdc3b2f173a4ccd0947cf0..285d6749c027a58537deba2f24821ceeb182e13a 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 03864d851ed033b2b4be699bc33977eed6ad23f8..592394602e1bfde984813f4888ca1f85e758cdb9 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 cd21780d0b46b8b9202453155780ca678c61f158..f304b31d6dd2a77941ec072125ed59b8bdcfa2af 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 572fbcb987bde51316803cb963e9d16025f1e66b..f0706fe3253e089e012c858807100e7900f1365a 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 002a9aa68bcb40ad4e7f868d4e82636f398046c1..bf49b1f8e85ce2883e54bf1749e0727f85886c41 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 9697ad062145bfeff32d35af9c29a43e080f4e37..956d5bb22744adf58662fed5ce73009634afe980 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 b88f82e2386941baedea4e04ce765299831e8dc9..5a9c70a78649789059985d4b82fe03798b577004 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 159c373eff171f998593631517aa1c3335110f2c..41f02f0547b6480127907378ee838d06baf8a0c2 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 7fedb3753e1e788335cc401bec8b59699e2e04d7..c315334f8987cd5cde2f24c700aa35f865d9c66f 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 097c1c13ebfbdbdf176cea46a8b39c9b6c7c67a1..6d4cfdacd6b732e6587293b7f980d7da78a5eee0 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(),