Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • master
  • native
  • packaging
  • release-0.2.x
  • release/201808
  • release/201811
  • release/201812
  • release/201901
  • release/201902
  • release/201903
  • release/201904
  • release/201905
  • release/201906
  • release/201908
  • release/201910
  • release/201911
  • release/201912
  • release/202001
  • release/202005
  • releases/beta1
  • 0.1.0
  • 0.1.1
  • 0.2.0
  • 1.0.0
24 results

Target

Select target project
  • savoirfairelinux/jami-client-windows
1 result
Select Git revision
  • master
  • native
  • packaging
  • release-0.2.x
  • release/201808
  • release/201811
  • release/201812
  • release/201901
  • release/201902
  • release/201903
  • release/201904
  • release/201905
  • release/201906
  • release/201908
  • release/201910
  • release/201911
  • release/201912
  • release/202001
  • release/202005
  • releases/beta1
  • 0.1.0
  • 0.1.1
  • 0.2.0
  • 1.0.0
24 results
Show changes
Showing
with 5270 additions and 290 deletions
/**************************************************************************
* Copyright (C) 2015-2019 by Savoir-faire Linux *
* Author: Yang Wang <yang.wang@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/>. *
**************************************************************************/
// directly related to this file
#include "callaudioonlyavataroverlay.h"
#include "ui_callaudioonlyavataroverlay.h"
CallAudioOnlyAvatarOverlay::CallAudioOnlyAvatarOverlay(QWidget *parent) :
QWidget(parent),
ui(new Ui::CallAudioOnlyAvatarOverlay)
{
ui->setupUi(this);
}
CallAudioOnlyAvatarOverlay::~CallAudioOnlyAvatarOverlay()
{
delete ui;
}
void
CallAudioOnlyAvatarOverlay::setAvatarVisible(bool visible)
{
this->setVisible(visible);
ui->avatarLabel->setVisible(visible);
ui->nameLabel->setVisible(visible);
}
void
CallAudioOnlyAvatarOverlay::writeAvatarOverlay(const lrc::api::conversation::Info& convInfo)
{
auto contact = LRCInstance::getCurrentAccountInfo().contactModel->getContact(convInfo.participants.at(0));
ui->avatarLabel->setPixmap(QPixmap::fromImage(Utils::conversationPhoto(convInfo.uid, LRCInstance::getCurrentAccountInfo())));
if (contact.profileInfo.type == lrc::api::profile::Type::SIP) {
ui->nameLabel->setText(contact.profileInfo.uri);
} else {
QString name = contact.profileInfo.alias;
QString id = contact.registeredName;
ui->nameLabel->setText(name + "\n" + id);
}
}
void
CallAudioOnlyAvatarOverlay::respondToPauseLabel(bool isPaused)
{
setAvatarVisible(!isPaused);
}
/**************************************************************************
* Copyright (C) 2015-2019 by Savoir-faire Linux *
* Author: Yang Wang <yang.wang@savoirfairelinux.com> *
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#pragma once
// qt
#include <QWidget>
// project
#include "lrcinstance.h"
#include "utils.h"
namespace Ui {
class CallAudioOnlyAvatarOverlay;
}
class CallAudioOnlyAvatarOverlay : public QWidget
{
Q_OBJECT
public:
explicit CallAudioOnlyAvatarOverlay(QWidget *parent = nullptr);
~CallAudioOnlyAvatarOverlay();
void setAvatarVisible(bool visible);
void writeAvatarOverlay(const lrc::api::conversation::Info& convInfo);
void respondToPauseLabel(bool isPaused);
private:
Ui::CallAudioOnlyAvatarOverlay *ui;
};
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CallAudioOnlyAvatarOverlay</class>
<widget class="QWidget" name="CallAudioOnlyAvatarOverlay">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1821</width>
<height>1231</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item alignment="Qt::AlignHCenter|Qt::AlignBottom">
<widget class="QLabel" name="avatarLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter|Qt::AlignTop">
<widget class="QLabel" name="nameLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> * * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> *
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> * * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> *
* Author: Isa Nanic <isa.nanic@savoirfairelinux.com> * * Author: Isa Nanic <isa.nanic@savoirfairelinux.com> *
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -23,26 +24,13 @@ ...@@ -23,26 +24,13 @@
#include "callwidget.h" #include "callwidget.h"
#include "ui_callwidget.h" #include "ui_callwidget.h"
#include <QComboBox> // client
#include <QDesktopServices>
#include <QScrollBar>
#include <QWebEngineScript>
#include <QMimeData>
#include <algorithm>
#include <memory>
#include <qrencode.h>
//ERROR is defined in windows.h
#include "utils.h" #include "utils.h"
#ifdef Q_OS_WIN
//ERROR is defined in windows.h
#undef ERROR #undef ERROR
#undef interface #undef interface
#endif
// lrc
#include "globalinstances.h"
// client
#include "animationhelpers.h" #include "animationhelpers.h"
#include "conversationitemdelegate.h" #include "conversationitemdelegate.h"
#include "globalsystemtray.h" #include "globalsystemtray.h"
...@@ -51,6 +39,23 @@ ...@@ -51,6 +39,23 @@
#include "pixbufmanipulator.h" #include "pixbufmanipulator.h"
#include "ringthemeutils.h" #include "ringthemeutils.h"
#include "settingskey.h" #include "settingskey.h"
#include "aboutdialog.h"
#include "userprofile.h"
#include "globalinstances.h"
#include <qrencode.h>
#include <QComboBox>
#include <QtConcurrent/QtConcurrent>
#include <QDesktopServices>
#include <QScrollBar>
#include <QWebEngineScript>
#include <QMimeData>
#include <QShortcut>
#include <algorithm>
#include <memory>
CallWidget::CallWidget(QWidget* parent) : CallWidget::CallWidget(QWidget* parent) :
NavWidget(parent), NavWidget(parent),
...@@ -70,20 +75,17 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -70,20 +75,17 @@ CallWidget::CallWidget(QWidget* parent) :
ui->qrLabel->hide(); ui->qrLabel->hide();
videoRenderer_ = nullptr;
QSettings settings("jami.net", "Jami"); QSettings settings("jami.net", "Jami");
// select last used account if stored in registry // select last used account if stored in registry
auto accountList = LRCInstance::accountModel().getAccountList(); auto accountList = LRCInstance::accountModel().getAccountList();
if (!accountList.empty()) { if (!accountList.empty()) {
std::string accountIdToStartWith; QString accountIdToStartWith;
if (settings.contains(SettingsKey::selectedAccount)) { if (settings.contains(SettingsKey::selectedAccount)) {
accountIdToStartWith = settings accountIdToStartWith = settings
.value(SettingsKey::selectedAccount, true) .value(SettingsKey::selectedAccount, true)
.value<QString>() .value<QString>();
.toStdString(); if (!accountList.contains(accountIdToStartWith)) {
if (Utils::indexInVector(accountList, accountIdToStartWith) == -1) {
accountIdToStartWith = accountList.at(0); accountIdToStartWith = accountList.at(0);
} }
} }
...@@ -92,7 +94,7 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -92,7 +94,7 @@ CallWidget::CallWidget(QWidget* parent) :
} }
setSelectedAccount(accountIdToStartWith); setSelectedAccount(accountIdToStartWith);
// get account index and set the currentAccountComboBox // get account index and set the currentAccountComboBox
auto index = Utils::indexInVector(accountList, accountIdToStartWith); auto index = accountList.indexOf(accountIdToStartWith);
if (index != -1) { if (index != -1) {
ui->currentAccountComboBox->setCurrentIndex(index); ui->currentAccountComboBox->setCurrentIndex(index);
} }
...@@ -101,6 +103,8 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -101,6 +103,8 @@ CallWidget::CallWidget(QWidget* parent) :
if (settings.contains(SettingsKey::mainSplitterState)) { if (settings.contains(SettingsKey::mainSplitterState)) {
auto splitterStates = settings.value(SettingsKey::mainSplitterState).toByteArray(); auto splitterStates = settings.value(SettingsKey::mainSplitterState).toByteArray();
ui->mainActivitySplitter->restoreState(splitterStates); ui->mainActivitySplitter->restoreState(splitterStates);
splitterStates = settings.value(SettingsKey::smartListToWebviewSplitterState).toByteArray();
ui->splitter->restoreState(splitterStates);
} }
ui->mainActivitySplitter->setCollapsible(0, false); ui->mainActivitySplitter->setCollapsible(0, false);
...@@ -117,6 +121,9 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -117,6 +121,9 @@ CallWidget::CallWidget(QWidget* parent) :
ui->spinnerLabel->setMovie(miniSpinner_); ui->spinnerLabel->setMovie(miniSpinner_);
ui->spinnerLabel->hide(); ui->spinnerLabel->hide();
// shortcuts
registerShortCuts();
// connections // connections
connect(ui->currentAccountComboBox, &CurrentAccountComboBox::settingsButtonClicked, connect(ui->currentAccountComboBox, &CurrentAccountComboBox::settingsButtonClicked,
this, &CallWidget::settingsButtonClicked); this, &CallWidget::settingsButtonClicked);
...@@ -126,15 +133,6 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -126,15 +133,6 @@ CallWidget::CallWidget(QWidget* parent) :
emit NavigationRequested(ScreenEnum::WizardScreen); emit NavigationRequested(ScreenEnum::WizardScreen);
}); });
connect(ui->videoWidget, &VideoView::setChatVisibility,
[this](bool visible) {
if (visible) {
ui->messagesWidget->show();
} else {
ui->messagesWidget->hide();
}
});
connect(ui->mainActivitySplitter, &QSplitter::splitterMoved, connect(ui->mainActivitySplitter, &QSplitter::splitterMoved,
[this](int pos, int index) { [this](int pos, int index) {
Q_UNUSED(index); Q_UNUSED(index);
...@@ -143,14 +141,13 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -143,14 +141,13 @@ CallWidget::CallWidget(QWidget* parent) :
settings.setValue(SettingsKey::mainSplitterState, ui->mainActivitySplitter->saveState()); settings.setValue(SettingsKey::mainSplitterState, ui->mainActivitySplitter->saveState());
}); });
connect(ui->videoWidget, &VideoView::videoSettingsClicked, connect(ui->splitter, &QSplitter::splitterMoved,
this, &CallWidget::settingsButtonClicked); [this](int pos, int index) {
Q_UNUSED(index);
connect(ui->videoWidget, &VideoView::toggleFullScreenClicked, Q_UNUSED(pos);
this, &CallWidget::slotToggleFullScreenClicked); QSettings settings("jami.net", "Jami");
settings.setValue(SettingsKey::smartListToWebviewSplitterState, ui->splitter->saveState());
connect(ui->videoWidget, &VideoView::closing, });
this, &CallWidget::slotVideoViewDestroyed);
connect(ui->btnConversations, &QPushButton::clicked, connect(ui->btnConversations, &QPushButton::clicked,
this, &CallWidget::conversationsButtonClicked); this, &CallWidget::conversationsButtonClicked);
...@@ -170,15 +167,6 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -170,15 +167,6 @@ CallWidget::CallWidget(QWidget* parent) :
connect(ui->smartList, &SmartListView::btnIgnoreInviteClicked, connect(ui->smartList, &SmartListView::btnIgnoreInviteClicked,
this, &CallWidget::slotIgnoreInviteClicked); this, &CallWidget::slotIgnoreInviteClicked);
connect(&LRCInstance::behaviorController(), &BehaviorController::showCallView,
this, &CallWidget::slotShowCallView);
connect(&LRCInstance::behaviorController(), &BehaviorController::showIncomingCallView,
this, &CallWidget::slotShowIncomingCallView);
connect(&LRCInstance::behaviorController(), &BehaviorController::showChatView,
this, &CallWidget::slotShowChatView);
connect(ui->currentAccountComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), connect(ui->currentAccountComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CallWidget::slotAccountChanged); this, &CallWidget::slotAccountChanged);
...@@ -208,6 +196,50 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -208,6 +196,50 @@ CallWidget::CallWidget(QWidget* parent) :
connect(ui->messageView, &MessageWebView::pasteKeyDetected, connect(ui->messageView, &MessageWebView::pasteKeyDetected,
this, &CallWidget::Paste); this, &CallWidget::Paste);
connect(ui->messageView, &MessageWebView::invitationAccepted,
[this] {
auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->makePermanent(convUid);
ui->sendContactRequestButton->hide();
});
// video view
connect(ui->videoView, &VideoView::setChatVisibility,
this, &CallWidget::slotSetChatVisibility, Qt::DirectConnection);
connect(ui->videoView, &VideoView::toggleFullScreenClicked,
this, &CallWidget::slotToggleFullScreenClicked);
connect(&LRCInstance::behaviorController(), &BehaviorController::showCallView,
this, &CallWidget::slotShowCallView);
connect(&LRCInstance::behaviorController(), &BehaviorController::showChatView,
this, &CallWidget::slotShowChatView);
// these may trigger notifications
connect(&LRCInstance::behaviorController(), &BehaviorController::showIncomingCallView,
this, &CallWidget::slotShowIncomingCallView);
connect(&LRCInstance::behaviorController(), &BehaviorController::newTrustRequest,
this, &CallWidget::slotNewTrustRequest);
connect(&LRCInstance::behaviorController(), &BehaviorController::newUnreadInteraction,
[this](const QString& accountId, const QString& conversation,
uint64_t interactionId, const interaction::Info& interaction) {
if (LRCInstance::getCurrAccId() != accountId) {
onNewInteraction(accountId, conversation, interactionId, interaction);
}
});
connect(LRCInstance::renderer(), &RenderManager::videoDeviceListChanged,
this, &CallWidget::slotVideoDeviceListChanged);
connect(ui->changelogButton, &QAbstractButton::clicked,
[this] {
AboutDialog aboutDialog (&MainWindow::instance());
aboutDialog.getContainer().toStrongRef()->exec();
});
// set first view to welcome view // set first view to welcome view
ui->stackedWidget->setCurrentWidget(ui->welcomePage); ui->stackedWidget->setCurrentWidget(ui->welcomePage);
ui->btnConversations->setChecked(true); ui->btnConversations->setChecked(true);
...@@ -219,7 +251,11 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -219,7 +251,11 @@ CallWidget::CallWidget(QWidget* parent) :
// hide the call stack // hide the call stack
setCallPanelVisibility(false); setCallPanelVisibility(false);
ui->containerWidget->setVisible(false); setVisible(false);
ui->sipCallerBestIdLabel->setVisible(false);
// set collapsible
ui->splitter->setCollapsible(ui->splitter->indexOf(ui->stackedWidget), false);
} }
CallWidget::~CallWidget() CallWidget::~CallWidget()
...@@ -231,29 +267,45 @@ CallWidget::~CallWidget() ...@@ -231,29 +267,45 @@ CallWidget::~CallWidget()
void void
CallWidget::navigated(bool to) CallWidget::navigated(bool to)
{ {
ui->containerWidget->setVisible(to); setVisible(to);
if (to) { if (to) {
updateSmartList(); updateSmartList();
connectConversationModel(); connectConversationModel();
try { try {
auto accountList = LRCInstance::accountModel().getAccountList(); auto accountList = LRCInstance::accountModel().getAccountList();
if (accountList.size() == 1) { if (accountList.size() == 1) {
auto index = Utils::indexInVector(accountList, LRCInstance::getCurrAccId()); auto index = accountList.indexOf(LRCInstance::getCurrAccId());
if (index != -1) { if (index != -1) {
slotAccountChanged(index); slotAccountChanged(index);
} }
} else if (!GlobalSystemTray::instance().getTriggeredAccountId().isEmpty()) {
slotAccountChanged(accountList.indexOf(GlobalSystemTray::instance().getTriggeredAccountId()));
// one shot connect
Utils::oneShotConnect(this, &CallWidget::slotAccountChangedFinished,
[this] {
if (!GlobalSystemTray::instance().getPossibleOnGoingConversationInfo().callId.isEmpty()) {
slotShowIncomingCallView(GlobalSystemTray::instance().getTriggeredAccountId(), GlobalSystemTray::instance().getPossibleOnGoingConversationInfo());
lrc::api::conversation::Info convInfo;
GlobalSystemTray::instance().setPossibleOnGoingConversationInfo(convInfo);
}
GlobalSystemTray::instance().setTriggeredAccountId("");
});
} }
} catch (...) {} } catch (...) {}
ui->currentAccountComboBox->updateComboBoxDisplay(); ui->currentAccountComboBox->updateComboBoxDisplay();
auto selectedConvUid = LRCInstance::getSelectedConvUid(); auto& conversation = LRCInstance::getCurrentConversation();
auto convModel = LRCInstance::getCurrentConversationModel(); if (!conversation.uid.isEmpty()) {
auto conversation = Utils::getConversationFromUid(selectedConvUid, *convModel); selectSmartlistItem(conversation.uid);
if (!selectedConvUid.empty() && conversation != convModel->allFilteredConversations().end()) {
selectSmartlistItem(selectedConvUid);
ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget); ui->stackedWidget->setCurrentWidget(ui->mainActivityWidget);
} else { } else {
backToWelcomePage(); backToWelcomePage();
} }
/**
* This will resize/position the preview when returning from the settings
* in case of a resolution change.
*/
ui->videoView->resetPreview();
setFocus();
} else { } else {
QObject::disconnect(smartlistSelectionConnection_); QObject::disconnect(smartlistSelectionConnection_);
smartListModel_.reset(nullptr); smartListModel_.reset(nullptr);
...@@ -263,17 +315,10 @@ CallWidget::navigated(bool to) ...@@ -263,17 +315,10 @@ CallWidget::navigated(bool to)
void void
CallWidget::updateCustomUI() CallWidget::updateCustomUI()
{ {
auto scalingRatio = MainWindow::instance().getCurrentScalingRatio();
if (scalingRatio > 1.0) {
ui->messageView->setZoomFactor(1.15);
} else {
ui->messageView->setZoomFactor(1.0);
}
} }
void void
CallWidget::slotAccountOnBoarded() CallWidget::slotAccountListChanged()
{} {}
int int
...@@ -283,33 +328,32 @@ CallWidget::getLeftPanelWidth() ...@@ -283,33 +328,32 @@ CallWidget::getLeftPanelWidth()
} }
void void
CallWidget::onIncomingMessage(const std::string& convUid, CallWidget::onNewInteraction(const QString& accountId, const QString& convUid,
uint64_t interactionId, uint64_t interactionId, const interaction::Info& interaction)
const lrc::api::interaction::Info& interaction)
{ {
Q_UNUSED(interactionId); Q_UNUSED(interactionId);
if (!QApplication::focusWidget()) { try {
auto convModel = LRCInstance::getCurrentConversationModel(); auto& accountInfo = LRCInstance::getAccountInfo(accountId);
auto conversation = Utils::getConversationFromUid(convUid, *convModel); auto& convModel = accountInfo.conversationModel;
if (conversation == convModel->allFilteredConversations().end()) { auto& conversation = LRCInstance::getConversationFromConvUid(convUid, accountId);
if (conversation.uid.isEmpty()) {
return; return;
} }
auto bestName = Utils::bestNameForConversation(*conversation, *convModel); if (!interaction.authorUri.isEmpty() &&
Utils::showSystemNotification(this, (!QApplication::focusWidget() || LRCInstance::getCurrAccId() != accountId)) {
QString::fromStdString(bestName), auto bestName = Utils::bestNameForConversation(conversation, *convModel);
QString::fromStdString(interaction.body)); Utils::showSystemNotification(this, bestName,interaction.body, 5000, accountId);
} }
updateConversationsFilterWidget(); updateConversationsFilterWidget();
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
return; return;
} }
auto convModel = LRCInstance::getCurrentConversationModel();
convModel->clearUnreadInteractions(convUid); convModel->clearUnreadInteractions(convUid);
auto convInfo = Utils::getSelectedConversation();
if (!convInfo.uid.empty()) {
ui->messageView->printNewInteraction(*convModel, interactionId, interaction); ui->messageView->printNewInteraction(*convModel, interactionId, interaction);
if (interaction.type != interaction::Type::CALL) {
ui->videoView->simulateShowChatview(true);
} }
} catch (...) {}
} }
void void
...@@ -322,11 +366,10 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos) ...@@ -322,11 +366,10 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos)
} }
auto convModel = LRCInstance::getCurrentConversationModel(); auto convModel = LRCInstance::getCurrentConversationModel();
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)) auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>();
.value<QString>() auto& conversation = LRCInstance::getConversationFromConvUid(convUid);
.toStdString(); if (conversation.uid.isEmpty()) return;
auto conversation = Utils::getConversationFromUid(convUid, *convModel); auto contactUid = conversation.participants.at(0);
auto contactUid = (*conversation).participants.at(0);
auto contact = LRCInstance::getCurrentAccountInfo().contactModel.get()->getContact(contactUid); auto contact = LRCInstance::getCurrentAccountInfo().contactModel.get()->getContact(contactUid);
if (!Utils::isContactValid(contactUid, *convModel)) { if (!Utils::isContactValid(contactUid, *convModel)) {
...@@ -340,22 +383,26 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos) ...@@ -340,22 +383,26 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos)
menu.addAction(videoCallAction); menu.addAction(videoCallAction);
connect(videoCallAction, &QAction::triggered, connect(videoCallAction, &QAction::triggered,
[this, convUid, conversation, convModel]() { [this, convUid, conversation, convModel]() {
convModel->placeCall(convUid); if (!ui->messageView->isVisible())
showChatView(LRCInstance::getCurrAccId(), conversation);
ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid))); ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid)));
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
selectConversation(*conversation, *convModel); selectConversation(conversation);
} }
convModel->placeCall(convUid);
}); });
// audio call // audio call
auto audioCallAction = new QAction(tr("Start audio call"), this); auto audioCallAction = new QAction(tr("Start audio call"), this);
menu.addAction(audioCallAction); menu.addAction(audioCallAction);
connect(audioCallAction, &QAction::triggered, connect(audioCallAction, &QAction::triggered,
[this, convUid, conversation, convModel]() { [this, convUid, conversation, convModel]() {
convModel->placeAudioOnlyCall(convUid); if (!ui->messageView->isVisible())
showChatView(LRCInstance::getCurrAccId(), conversation);
ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid))); ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid)));
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
selectConversation(*conversation, *convModel); selectConversation(conversation);
} }
convModel->placeAudioOnlyCall(convUid);
}); });
// clear conversation // clear conversation
auto clearConversationAction = new QAction(tr("Clear conversation"), this); auto clearConversationAction = new QAction(tr("Clear conversation"), this);
...@@ -387,14 +434,13 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos) ...@@ -387,14 +434,13 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos)
// separator // separator
menu.addSeparator(); menu.addSeparator();
// copy number(infohash) // show user profile
auto copyNumberAction = new QAction(tr("Copy number"), this); auto profileShowingAction = new QAction(tr("Profile"), this);
menu.addAction(copyNumberAction); menu.addAction(profileShowingAction);
connect(copyNumberAction, &QAction::triggered, connect(profileShowingAction, &QAction::triggered,
[contact]() { [conversation, this]() {
QApplication::clipboard()->setText( UserProfile userProfile(conversation, qobject_cast<MainWindow*>(this->parent()->parent()->parent()));
QString::fromStdString(contact.profileInfo.uri) userProfile.getContainer().toStrongRef()->exec();
);
}); });
} }
smartListModel_->isContextMenuOpen = true; smartListModel_->isContextMenuOpen = true;
...@@ -402,45 +448,6 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos) ...@@ -402,45 +448,6 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos)
smartListModel_->isContextMenuOpen = false; smartListModel_->isContextMenuOpen = false;
} }
void
CallWidget::setupQRCode(QString ringID)
{
auto rcode = QRcode_encodeString(ringID.toStdString().c_str(),
0, //Let the version be decided by libqrencode
QR_ECLEVEL_L, // Lowest level of error correction
QR_MODE_8, // 8-bit data mode
1);
if (not rcode) {
qWarning() << "Failed to generate QR code: " << strerror(errno);
return;
}
auto margin = 5;
int qrwidth = rcode->width + margin * 2;
QImage result(QSize(qrwidth, qrwidth), QImage::Format_Mono);
QPainter painter;
painter.begin(&result);
painter.setClipRect(QRect(0, 0, qrwidth, qrwidth));
painter.setPen(QPen(Qt::black, 0.1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
painter.setBrush(Qt::black);
painter.fillRect(QRect(0, 0, qrwidth, qrwidth), Qt::white);
unsigned char* p;
p = rcode->data;
for(int y = 0; y < rcode->width; y++) {
unsigned char* row = (p + (y * rcode->width));
for(int x = 0; x < rcode->width; x++) {
if(*(row + x) & 0x1) {
painter.drawRect(margin + x, margin + y, 1, 1);
}
}
}
painter.end();
QRcode_free(rcode);
ui->qrLabel->setPixmap(QPixmap::fromImage(result.scaled(QSize(qrSize_, qrSize_),
Qt::KeepAspectRatio)));
}
void void
CallWidget::on_smartList_clicked(const QModelIndex& index) CallWidget::on_smartList_clicked(const QModelIndex& index)
{ {
...@@ -450,8 +457,8 @@ CallWidget::on_smartList_clicked(const QModelIndex& index) ...@@ -450,8 +457,8 @@ CallWidget::on_smartList_clicked(const QModelIndex& index)
void void
CallWidget::on_acceptButton_clicked() CallWidget::on_acceptButton_clicked()
{ {
auto convInfo = Utils::getSelectedConversation(); auto convInfo = LRCInstance::getCurrentConversation();
if (!convInfo.uid.empty()) { if (!convInfo.uid.isEmpty()) {
LRCInstance::getCurrentCallModel()->accept(convInfo.callId); LRCInstance::getCurrentCallModel()->accept(convInfo.callId);
} }
} }
...@@ -459,8 +466,8 @@ CallWidget::on_acceptButton_clicked() ...@@ -459,8 +466,8 @@ CallWidget::on_acceptButton_clicked()
void void
CallWidget::on_refuseButton_clicked() CallWidget::on_refuseButton_clicked()
{ {
auto convInfo = Utils::getSelectedConversation(); auto convInfo = LRCInstance::getCurrentConversation();
if (!convInfo.uid.empty()) { if (!convInfo.uid.isEmpty()) {
LRCInstance::getCurrentCallModel()->refuse(convInfo.callId); LRCInstance::getCurrentCallModel()->refuse(convInfo.callId);
showConversationView(); showConversationView();
} }
...@@ -469,8 +476,8 @@ CallWidget::on_refuseButton_clicked() ...@@ -469,8 +476,8 @@ CallWidget::on_refuseButton_clicked()
void void
CallWidget::on_cancelButton_clicked() CallWidget::on_cancelButton_clicked()
{ {
auto convInfo = Utils::getSelectedConversation(); auto convInfo = LRCInstance::getCurrentConversation();
if (!convInfo.uid.empty()) { if (!convInfo.uid.isEmpty()) {
LRCInstance::getCurrentCallModel()->hangUp(convInfo.callId); LRCInstance::getCurrentCallModel()->hangUp(convInfo.callId);
showConversationView(); showConversationView();
} }
...@@ -479,7 +486,7 @@ CallWidget::on_cancelButton_clicked() ...@@ -479,7 +486,7 @@ CallWidget::on_cancelButton_clicked()
void void
CallWidget::showConversationView() CallWidget::showConversationView()
{ {
if (LRCInstance::getSelectedConvUid().empty()) { if (LRCInstance::getCurrentConvUid().isEmpty()) {
backToWelcomePage(); backToWelcomePage();
return; return;
} }
...@@ -488,22 +495,23 @@ CallWidget::showConversationView() ...@@ -488,22 +495,23 @@ CallWidget::showConversationView()
if (ui->messagesWidget->isHidden()) { if (ui->messagesWidget->isHidden()) {
ui->messagesWidget->show(); ui->messagesWidget->show();
} }
updateChatviewFrame();
} }
bool bool
CallWidget::selectSmartlistItem(const std::string & convUid) CallWidget::selectSmartlistItem(const QString& convUid)
{ {
if (convUid.empty() || !ui->smartList->selectionModel()) if (convUid.isEmpty() || !ui->smartList->selectionModel())
return false; return false;
ui->smartList->selectionModel()->setCurrentIndex(QModelIndex(), QItemSelectionModel::Deselect); ui->smartList->selectionModel()->setCurrentIndex(QModelIndex(), QItemSelectionModel::Deselect);
auto convModel = LRCInstance::getCurrentConversationModel(); auto convModel = LRCInstance::getCurrentConversationModel();
auto conversation = Utils::getConversationFromUid(convUid, *convModel); auto& conversation = LRCInstance::getConversationFromConvUid(convUid);
if (conversation == convModel->allFilteredConversations().end()) { if (conversation.uid.isEmpty()) {
return false; return false;
} }
auto contactURI = QString::fromStdString((*conversation).participants[0]); auto contactURI = conversation.participants[0];
if (contactURI.isEmpty() || if (contactURI.isEmpty() ||
convModel->owner.contactModel->getContact(contactURI.toStdString()).profileInfo.type == lrc::api::profile::Type::TEMPORARY) { convModel->owner.contactModel->getContact(contactURI).profileInfo.type == lrc::api::profile::Type::TEMPORARY) {
return false; return false;
} }
for (int row = 0; row < smartListModel_->rowCount(); row++) { for (int row = 0; row < smartListModel_->rowCount(); row++) {
...@@ -525,13 +533,13 @@ CallWidget::on_smartList_doubleClicked(const QModelIndex& index) ...@@ -525,13 +533,13 @@ CallWidget::on_smartList_doubleClicked(const QModelIndex& index)
selectConversation(index); selectConversation(index);
LRCInstance::getCurrentConversationModel()->placeCall(LRCInstance::getSelectedConvUid()); LRCInstance::getCurrentConversationModel()->placeCall(LRCInstance::getCurrentConvUid());
ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(LRCInstance::getSelectedConvUid()))); ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(LRCInstance::getCurrentConvUid())));
} }
QImage QImage
CallWidget::imageForConv(const std::string& convUid) CallWidget::imageForConv(const QString& convUid)
{ {
return Utils::conversationPhoto(convUid, LRCInstance::getCurrentAccountInfo()); return Utils::conversationPhoto(convUid, LRCInstance::getCurrentAccountInfo());
} }
...@@ -555,6 +563,19 @@ CallWidget::smartListSelectionChanged(const QItemSelection &selected, const QIt ...@@ -555,6 +563,19 @@ CallWidget::smartListSelectionChanged(const QItemSelection &selected, const QIt
selectConversation(selectedIndex); selectConversation(selectedIndex);
} }
void CallWidget::slotSetChatVisibility(bool visible)
{
ui->messagesWidget->setVisible(visible);
}
void
CallWidget::slotVideoDeviceListChanged()
{
if (LRCInstance::hasVideoCall()) {
LRCInstance::renderer()->startPreviewing();
}
}
void void
CallWidget::conversationsButtonClicked() CallWidget::conversationsButtonClicked()
{ {
...@@ -598,101 +619,107 @@ CallWidget::on_ringContactLineEdit_returnPressed() ...@@ -598,101 +619,107 @@ CallWidget::on_ringContactLineEdit_returnPressed()
} }
} }
void CallWidget::slotAcceptInviteClicked(const QModelIndex & index) void
CallWidget::slotAcceptInviteClicked(const QModelIndex & index)
{ {
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString(); auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>();
LRCInstance::getCurrentConversationModel()->makePermanent(convUid); LRCInstance::getCurrentConversationModel()->makePermanent(convUid);
ui->messageView->setInvitation(false); ui->messageView->setInvitation(false);
ui->sendContactRequestButton->hide();
} }
void CallWidget::slotBlockInviteClicked(const QModelIndex & index) void
CallWidget::slotBlockInviteClicked(const QModelIndex & index)
{ {
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString(); auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>();
if (!convUid.empty() && convUid == LRCInstance::getSelectedConvUid()) { if (!convUid.isEmpty() && convUid == LRCInstance::getCurrentConvUid()) {
backToWelcomePage(); backToWelcomePage();
} }
LRCInstance::getCurrentConversationModel()->removeConversation(convUid, true); LRCInstance::getCurrentConversationModel()->removeConversation(convUid, true);
} }
void CallWidget::slotIgnoreInviteClicked(const QModelIndex & index) void
CallWidget::slotIgnoreInviteClicked(const QModelIndex & index)
{ {
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString(); auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>();
if (!convUid.empty() && convUid == LRCInstance::getSelectedConvUid()) { if (!convUid.isEmpty() && convUid == LRCInstance::getCurrentConvUid()) {
backToWelcomePage(); backToWelcomePage();
} }
LRCInstance::getCurrentConversationModel()->removeConversation(convUid, false); LRCInstance::getCurrentConversationModel()->removeConversation(convUid, false);
} }
void CallWidget::slotCustomContextMenuRequested(const QPoint& pos) void
CallWidget::slotCustomContextMenuRequested(const QPoint& pos)
{ {
setupSmartListContextMenu(pos); setupSmartListContextMenu(pos);
} }
void CallWidget::slotAccountChanged(int index) void
CallWidget::slotAccountChanged(int index)
{ {
try {
auto accountList = LRCInstance::accountModel().getAccountList(); auto accountList = LRCInstance::accountModel().getAccountList();
if(accountList.size() > index)
setSelectedAccount(accountList.at(index)); setSelectedAccount(accountList.at(index));
} catch (...) {
qWarning() << "CallWidget::slotAccountChanged exception";
}
} }
void CallWidget::slotShowCallView(const std::string& accountId, void
CallWidget::slotShowCallView(const QString& accountId,
const lrc::api::conversation::Info& convInfo) const lrc::api::conversation::Info& convInfo)
{ {
Q_UNUSED(accountId); Q_UNUSED(accountId);
qDebug() << "slotShowCallView"; qDebug() << "slotShowCallView";
// find out the best name for current callee, remove the search result from smart list
auto callModel = LRCInstance::getCurrentCallModel();
auto convModel = LRCInstance::getCurrentConversationModel();
auto bestName = QString::fromStdString(Utils::bestNameForConversation(convInfo, *convModel));
ui->videoWidget->setCurrentCalleeName(bestName);
setCallPanelVisibility(true);
if (callModel->hasCall(convInfo.callId)) { if (!convInfo.callId.isEmpty()) {
auto call = callModel->getCall(convInfo.callId); auto & accInfo = LRCInstance::getAccountInfo(convInfo.accountId);
ui->videoWidget->resetVideoOverlay(call.audioMuted && (call.status != lrc::api::call::Status::PAUSED), accInfo.callModel->setCurrentCall(convInfo.callId);
call.videoMuted && (call.status != lrc::api::call::Status::PAUSED) && (!call.isAudioOnly),
callModel->isRecording(convInfo.callId),
call.status == lrc::api::call::Status::PAUSED);
} else {
ui->videoWidget->resetVideoOverlay(false, false, false, false);
} }
// control visible callwidget buttons
setCallPanelVisibility(true);
ui->callStackWidget->setCurrentWidget(ui->videoPage); ui->callStackWidget->setCurrentWidget(ui->videoPage);
hideMiniSpinner(); hideMiniSpinner();
ui->videoWidget->pushRenderer(convInfo.callId, LRCInstance::accountModel().getAccountInfo(accountId).profileInfo.type == lrc::api::profile::Type::SIP);
ui->videoView->updateCall(convInfo.uid, accountId);
ui->videoView->show();
ui->videoView->setFocus();
} }
void CallWidget::slotShowIncomingCallView(const std::string& accountId, void
const lrc::api::conversation::Info& convInfo) CallWidget::slotShowIncomingCallView(const QString& accountId,
const conversation::Info& convInfo)
{ {
Q_UNUSED(accountId);
qDebug() << "slotShowIncomingCallView"; qDebug() << "slotShowIncomingCallView";
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
if (!callModel->hasCall(convInfo.callId)) { if (!callModel->hasCall(convInfo.callId)) {
auto convModel = LRCInstance::getAccountInfo(accountId).conversationModel.get();
auto formattedName = Utils::bestNameForConversation(convInfo, *convModel);
if (GlobalSystemTray::instance().getTriggeredAccountId() != accountId) {
GlobalSystemTray::instance().setPossibleOnGoingConversationInfo(convInfo);
Utils::showSystemNotification(
this,
QString(tr("Call incoming from %1 to %2"))
.arg(formattedName)
.arg(Utils::bestNameForAccount(LRCInstance::getAccountInfo(accountId))),
5000,
accountId
);
}
return; return;
} }
auto convModel = LRCInstance::getCurrentConversationModel(); auto convModel = LRCInstance::getCurrentConversationModel();
ui->callerPhoto->setPixmap(QPixmap::fromImage(imageForConv(convInfo.uid))); ui->callerPhoto->setPixmap(QPixmap::fromImage(imageForConv(convInfo.uid)));
auto bestName = QString::fromStdString(Utils::bestNameForConversation(convInfo, *convModel)); auto bestName = Utils::bestNameForConversation(convInfo, *convModel);
auto bestId = QString::fromStdString(Utils::bestIdForConversation(convInfo, *convModel)); auto bestId = Utils::bestIdForConversation(convInfo, *convModel);
auto finalBestId = (bestName != bestId) ? bestId : ""; auto finalBestId = (bestName != bestId) ? bestId : "";
auto call = callModel->getCall(convInfo.callId); auto call = callModel->getCall(convInfo.callId);
auto isCallSelected = LRCInstance::getSelectedConvUid() == convInfo.uid; auto isCallSelected = LRCInstance::getCurrentConvUid() == convInfo.uid;
ui->callingStatusLabel->setText(QString::fromStdString(lrc::api::call::to_string(call.status))); ui->callingStatusLabel->setText(lrc::api::call::to_string(call.status));
ui->videoWidget->setCurrentCalleeName(bestName);
connect(callModel, &lrc::api::NewCallModel::callStatusChanged, ui->incomingCallPage,
[this, accountId](const std::string& callId) {
auto callModel = LRCInstance::accountModel().getAccountInfo(accountId).callModel.get();
auto call = callModel->getCall(callId);
ui->callingStatusLabel->setText(QString::fromStdString(lrc::api::call::to_string(call.status)));
});
auto itemInCurrentFilter = false; auto itemInCurrentFilter = false;
if (call.isOutgoing) { if (call.isOutgoing) {
...@@ -703,10 +730,9 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId, ...@@ -703,10 +730,9 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId,
setCallPanelVisibility(true); setCallPanelVisibility(true);
} }
} else { } else {
if (!QApplication::focusWidget()) { if (!QApplication::focusWidget() && GlobalSystemTray::instance().getTriggeredAccountId().isEmpty()) {
auto formattedName = Utils::bestNameForConversation(convInfo, *convModel); auto formattedName = Utils::bestNameForConversation(convInfo, *convModel);
Utils::showSystemNotification(this, Utils::showSystemNotification(this, QString(tr("Call incoming from %1")).arg(formattedName));
QString(tr("Call incoming from %1")).arg(QString::fromStdString(formattedName)));
} }
auto selectedAccountId = LRCInstance::getCurrentAccountInfo().id; auto selectedAccountId = LRCInstance::getCurrentAccountInfo().id;
auto accountProperties = LRCInstance::accountModel().getAccountConfig(selectedAccountId); auto accountProperties = LRCInstance::accountModel().getAccountConfig(selectedAccountId);
...@@ -729,8 +755,6 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId, ...@@ -729,8 +755,6 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId,
ui->messagesWidget->show(); ui->messagesWidget->show();
} }
ui->videoWidget->pushRenderer(convInfo.callId, LRCInstance::accountModel().getAccountInfo(accountId).profileInfo.type == lrc::api::profile::Type::SIP);
QFontMetrics primaryCallLabelFontMetrics(ui->callingBestNameLabel->font()); QFontMetrics primaryCallLabelFontMetrics(ui->callingBestNameLabel->font());
QFontMetrics sencondaryCallLabelFontMetrics(ui->callingBestIdLabel->font()); QFontMetrics sencondaryCallLabelFontMetrics(ui->callingBestIdLabel->font());
...@@ -742,11 +766,18 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId, ...@@ -742,11 +766,18 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId,
elidedLabel = sencondaryCallLabelFontMetrics.elidedText(finalBestId, Qt::ElideRight, ui->callingBestIdLabel->width()); elidedLabel = sencondaryCallLabelFontMetrics.elidedText(finalBestId, Qt::ElideRight, ui->callingBestIdLabel->width());
ui->callingBestIdLabel->setText(elidedLabel); ui->callingBestIdLabel->setText(elidedLabel);
ui->sipCallerBestIdLabel->setText(elidedLabel);
if(finalBestId.isEmpty())
ui->sipCallerBestIdLabel->setVisible(false);
else
ui->sipCallerBestIdLabel->setVisible(true);
ui->smartList->update(); ui->smartList->update();
} }
void CallWidget::slotShowChatView(const std::string& accountId, void
CallWidget::slotShowChatView(const QString& accountId,
const lrc::api::conversation::Info& convInfo) const lrc::api::conversation::Info& convInfo)
{ {
Q_UNUSED(accountId); Q_UNUSED(accountId);
...@@ -756,6 +787,27 @@ void CallWidget::slotShowChatView(const std::string& accountId, ...@@ -756,6 +787,27 @@ void CallWidget::slotShowChatView(const std::string& accountId,
showConversationView(); showConversationView();
} }
void
CallWidget::slotNewTrustRequest(const QString& accountId, const QString& contactUri)
{
try {
auto& accountInfo = LRCInstance::getAccountInfo(accountId);
auto& contactModel = accountInfo.contactModel;
if (!QApplication::focusWidget() || LRCInstance::getCurrAccId() != accountId) {
try {
auto contactInfo = contactModel->getContact(contactUri);
auto bestName = Utils::bestNameForContact(contactInfo);
Utils::showSystemNotification(this, bestName, QObject::tr("Contact request"), 5000, accountId);
} catch (...) {
qDebug() << "Can't get contact: ", contactUri;
return;
}
}
} catch (...) {
qDebug() << "Can't get account:" << accountId;
}
}
void void
CallWidget::slotToggleFullScreenClicked() CallWidget::slotToggleFullScreenClicked()
{ {
...@@ -775,10 +827,12 @@ CallWidget::slotToggleFullScreenClicked() ...@@ -775,10 +827,12 @@ CallWidget::slotToggleFullScreenClicked()
} }
void void
CallWidget::slotVideoViewDestroyed(const std::string& callid) CallWidget::callTerminating(const QString& id)
{ {
auto conversation = Utils::getSelectedConversation(); auto conversation = LRCInstance::getCurrentConversation();
if (conversation.uid.empty() || callid != conversation.callId) { if ( conversation.uid.isEmpty() &&
conversation.callId != id &&
conversation.confId != id) {
return; return;
} }
if (ui->mainActivityWidget->isFullScreen()) { if (ui->mainActivityWidget->isFullScreen()) {
...@@ -791,23 +845,24 @@ CallWidget::slotVideoViewDestroyed(const std::string& callid) ...@@ -791,23 +845,24 @@ CallWidget::slotVideoViewDestroyed(const std::string& callid)
} }
void void
CallWidget::setSelectedAccount(const std::string& accountId) CallWidget::setSelectedAccount(const QString& accountId)
{ {
LRCInstance::setSelectedAccountId(accountId); LRCInstance::setSelectedAccountId(accountId);
// First, we get back to the welcome view (except if in call) // First, we get back to the welcome view (except if in call)
if (ui->stackedWidget->currentWidget() != ui->videoPage && if (ui->stackedWidget->currentWidget() != ui->videoPage &&
ui->stackedWidget->currentWidget() != ui->welcomePage) { ui->stackedWidget->currentWidget() != ui->welcomePage) {
Utils::setStackWidget(ui->stackedWidget, ui->welcomePage); backToWelcomePage();
} }
// We setup the ringIdLabel and the QRCode // We setup the ringIdLabel and the QRCode
auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountId); auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountId);
auto id = accountInfo.registeredName.empty() ? accountInfo.profileInfo.uri : accountInfo.registeredName; auto id = accountInfo.registeredName.isEmpty() ? accountInfo.profileInfo.uri : accountInfo.registeredName;
auto isRingAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING; auto isRingAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING;
if (isRingAccount) { if (isRingAccount) {
ui->ringIdLabel->setText(QString::fromStdString(id)); ui->ringIdLabel->setText(id);
setupQRCode(QString::fromStdString(accountInfo.profileInfo.uri)); ui->qrLabel->setPixmap(QPixmap::fromImage(Utils::setupQRCode(accountInfo.profileInfo.uri, 5).scaled(QSize(qrSize_, qrSize_),
Qt::KeepAspectRatio)));
} }
updateSmartList(); updateSmartList();
...@@ -816,6 +871,7 @@ CallWidget::setSelectedAccount(const std::string& accountId) ...@@ -816,6 +871,7 @@ CallWidget::setSelectedAccount(const std::string& accountId)
updateConversationsFilterWidget(); updateConversationsFilterWidget();
connectConversationModel(); connectConversationModel();
connectAccount(accountId); connectAccount(accountId);
emit slotAccountChangedFinished();
} }
void CallWidget::setConversationFilter(lrc::api::profile::Type filter) void CallWidget::setConversationFilter(lrc::api::profile::Type filter)
...@@ -835,6 +891,10 @@ void CallWidget::updateConversationsFilterWidget() ...@@ -835,6 +891,10 @@ void CallWidget::updateConversationsFilterWidget()
LRCInstance::getCurrentConversationModel()->setFilter(currentTypeFilter_); LRCInstance::getCurrentConversationModel()->setFilter(currentTypeFilter_);
} }
ui->conversationsFilterWidget->setVisible(invites); ui->conversationsFilterWidget->setVisible(invites);
if (!invites) {
Utils::whileBlocking<QPushButton>(ui->btnConversations)->setChecked(true);
Utils::whileBlocking<QPushButton>(ui->btnInvites)->setChecked(false);
}
ui->searchTopLeftWidget->setVisible(invites); ui->searchTopLeftWidget->setVisible(invites);
ui->searchTopRightWidget->setVisible(invites); ui->searchTopRightWidget->setVisible(invites);
ui->conversationsFilterWidget->update(); ui->conversationsFilterWidget->update();
...@@ -843,63 +903,93 @@ void CallWidget::updateConversationsFilterWidget() ...@@ -843,63 +903,93 @@ void CallWidget::updateConversationsFilterWidget()
void CallWidget::setConversationFilter(const QString & filter) void CallWidget::setConversationFilter(const QString & filter)
{ {
LRCInstance::getCurrentConversationModel()->setFilter(filter.toStdString()); LRCInstance::getCurrentConversationModel()->setFilter(filter);
} }
void void
CallWidget::showChatView(const QModelIndex& nodeIdx) CallWidget::showChatView(const QModelIndex& nodeIdx)
{ {
auto convUid = nodeIdx.data(static_cast<int>(SmartListModel::Role::UID)).toString().toStdString(); auto convUid = nodeIdx.data(static_cast<int>(SmartListModel::Role::UID)).toString();
auto convModel = LRCInstance::getCurrentConversationModel(); auto& conversation = LRCInstance::getConversationFromConvUid(convUid);
auto convInfo = Utils::getConversationFromUid(convUid, *convModel); if (!conversation.uid.isEmpty()) {
if (convInfo != convModel->allFilteredConversations().end()) setupChatView(conversation);
setupChatView(*convInfo); }
} }
void void
CallWidget::showChatView(const std::string& accountId, const lrc::api::conversation::Info& convInfo) CallWidget::showChatView(const QString& accountId, const lrc::api::conversation::Info& convInfo)
{ {
Q_UNUSED(accountId); Q_UNUSED(accountId);
setupChatView(convInfo); setupChatView(convInfo);
} }
void
CallWidget::setConversationProfileData(const lrc::api::conversation::Info& convInfo)
{
auto convModel = LRCInstance::getCurrentConversationModel();
auto accInfo = &LRCInstance::getCurrentAccountInfo();
auto contactUri = convInfo.participants.front();
if (contactUri.isEmpty()) {
return;
}
try {
auto& contact = accInfo->contactModel->getContact(contactUri);
auto bestName = Utils::bestNameForConversation(convInfo, *convModel);
ui->messageView->setInvitation(
(contact.profileInfo.type == lrc::api::profile::Type::PENDING),
bestName,
contactUri
);
if (!contact.profileInfo.avatar.isEmpty()) {
ui->messageView->setSenderImage(contactUri, contact.profileInfo.avatar);
} else {
auto avatar = Utils::conversationPhoto(convInfo.uid, *accInfo);
QByteArray ba;
QBuffer bu(&ba);
avatar.save(&bu, "PNG");
ui->messageView->setSenderImage(contactUri, QString::fromLocal8Bit(ba.toBase64()));
}
} catch (...) {}
}
void void
CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo) CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo)
{ {
auto& accInfo = LRCInstance::getCurrentAccountInfo(); auto& accInfo = LRCInstance::getCurrentAccountInfo();
auto& contact = accInfo.contactModel->getContact(convInfo.participants.at(0)); auto& contact = accInfo.contactModel->getContact(convInfo.participants.at(0));
QString displayName = QString::fromStdString(Utils::bestNameForContact(contact)); QString displayName = Utils::bestNameForContact(contact);
QString displayId = QString::fromStdString(Utils::bestIdForContact(contact)); QString displayId = Utils::bestIdForContact(contact);
QString contactURI = QString::fromStdString(convInfo.participants.at(0)); QString contactURI = convInfo.participants.at(0);
bool isContact = false; bool isContact = false;
auto selectedAccountId = LRCInstance::getCurrAccId(); auto selectedAccountId = LRCInstance::getCurrAccId();
auto& accountInfo = LRCInstance::accountModel().getAccountInfo(selectedAccountId); auto& accountInfo = LRCInstance::accountModel().getAccountInfo(selectedAccountId);
bool isRINGAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING; bool isRINGAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING;
lrc::api::profile::Type contactType;
try { try {
auto contactInfo = accountInfo.contactModel->getContact(contactURI.toStdString()); auto contactInfo = accountInfo.contactModel->getContact(contactURI);
if (contactInfo.isTrusted) { if (contactInfo.isTrusted) {
isContact = true; isContact = true;
} }
contactType = contactInfo.profileInfo.type;
} catch (...) {} } catch (...) {}
ui->imNameLabel->setText(QString(tr("%1", "%1 is the contact username")) ui->imNameLabel->setText(displayName);
.arg(displayName)); ui->imIdLabel->setText(displayId);
ui->imIdLabel->setVisible(isRINGAccount && displayName != displayId);
if (isRINGAccount && displayName != displayId) {
ui->imIdLabel->show();
ui->imIdLabel->setText(QString(tr("%1", "%1 is the contact unique identifier"))
.arg(displayId));
} else {
ui->imIdLabel->hide();
}
bool shouldShowSendContactRequestBtn = !isContact && isRINGAccount; bool shouldShowSendContactRequestBtn = !isContact && contactType != lrc::api::profile::Type::SIP;
ui->sendContactRequestButton->setVisible(shouldShowSendContactRequestBtn); ui->sendContactRequestButton->setVisible(shouldShowSendContactRequestBtn);
ui->messageView->setMessagesVisibility(false); ui->messageView->setMessagesVisibility(false);
ui->messageView->clear(); ui->messageView->contactIsComposing(convInfo.uid, "", false);
ui->messageView->setInvitation(false); connect(LRCInstance::getCurrentConversationModel(), &ConversationModel::composingStatusChanged, ui->messageView, &MessageWebView::contactIsComposing);
Utils::oneShotConnect(ui->messageView, &MessageWebView::sendMessageContentSaved,
[this, convInfo, accountId = accountInfo.id, lastConvUid = lastConvUid_](const QString& content) {
if (!lastConvUid.isEmpty()) {
LRCInstance::setContentDraft(lastConvUid, accountId, content);
}
Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesCleared, Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesCleared,
[this, convInfo] { [this, convInfo] {
auto convModel = LRCInstance::getCurrentConversationModel(); auto convModel = LRCInstance::getCurrentConversationModel();
...@@ -908,33 +998,15 @@ CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo) ...@@ -908,33 +998,15 @@ CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo)
[this] { [this] {
ui->messageView->setMessagesVisibility(true); ui->messageView->setMessagesVisibility(true);
}); });
// Contact Avatars setConversationProfileData(convInfo);
auto accInfo = &LRCInstance::getCurrentAccountInfo(); });
auto contactUri = convInfo.participants.front(); ui->messageView->setInvitation(false);
try { ui->messageView->clear();
auto& contact = accInfo->contactModel->getContact(contactUri); auto restoredContent = LRCInstance::getContentDraft(convInfo.uid, accountId);
auto bestName = Utils::bestNameForConversation(convInfo, *convModel); ui->messageView->setSendMessageContent(restoredContent);
ui->messageView->setInvitation( ui->smartList->update();
(contact.profileInfo.type == lrc::api::profile::Type::PENDING),
bestName,
accInfo->contactModel->getContactProfileId(contact.profileInfo.uri)
);
if (!contact.profileInfo.avatar.empty()) {
ui->messageView->setSenderImage(
accInfo->contactModel->getContactProfileId(contactUri),
contact.profileInfo.avatar);
} else {
auto avatar = Utils::conversationPhoto(convInfo.uid, *accInfo);
QByteArray ba;
QBuffer bu(&ba);
avatar.save(&bu, "PNG");
std::string avatarString = ba.toBase64().toStdString();
ui->messageView->setSenderImage(
accInfo->contactModel->getContactProfileId(contactUri),
avatarString);
}
} catch (...) {}
}); });
ui->messageView->requestSendMessageContent();
} }
void void
...@@ -985,8 +1057,8 @@ CallWidget::on_shareButton_clicked() ...@@ -985,8 +1057,8 @@ CallWidget::on_shareButton_clicked()
void void
CallWidget::on_sendContactRequestButton_clicked() CallWidget::on_sendContactRequestButton_clicked()
{ {
auto convInfo = Utils::getSelectedConversation(); auto convInfo = LRCInstance::getCurrentConversation();
if (!convInfo.uid.empty()) { if (!convInfo.uid.isEmpty()) {
LRCInstance::getCurrentConversationModel()->makePermanent(convInfo.uid); LRCInstance::getCurrentConversationModel()->makePermanent(convInfo.uid);
ui->sendContactRequestButton->hide(); ui->sendContactRequestButton->hide();
} }
...@@ -995,8 +1067,8 @@ CallWidget::on_sendContactRequestButton_clicked() ...@@ -995,8 +1067,8 @@ CallWidget::on_sendContactRequestButton_clicked()
void void
CallWidget::on_btnAudioCall_clicked() CallWidget::on_btnAudioCall_clicked()
{ {
auto convInfo = Utils::getSelectedConversation(); auto convInfo = LRCInstance::getCurrentConversation();
if (!convInfo.uid.empty()) { if (!convInfo.uid.isEmpty()) {
LRCInstance::getCurrentConversationModel()->placeAudioOnlyCall(convInfo.uid); LRCInstance::getCurrentConversationModel()->placeAudioOnlyCall(convInfo.uid);
ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convInfo.uid))); ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convInfo.uid)));
} }
...@@ -1005,8 +1077,8 @@ CallWidget::on_btnAudioCall_clicked() ...@@ -1005,8 +1077,8 @@ CallWidget::on_btnAudioCall_clicked()
void void
CallWidget::on_btnVideoCall_clicked() CallWidget::on_btnVideoCall_clicked()
{ {
auto convInfo = Utils::getSelectedConversation(); auto convInfo = LRCInstance::getCurrentConversation();
if (!convInfo.uid.empty()) { if (!convInfo.uid.isEmpty()) {
LRCInstance::getCurrentConversationModel()->placeCall(convInfo.uid); LRCInstance::getCurrentConversationModel()->placeCall(convInfo.uid);
ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convInfo.uid))); ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convInfo.uid)));
} }
...@@ -1035,13 +1107,13 @@ CallWidget::connectConversationModel() ...@@ -1035,13 +1107,13 @@ CallWidget::connectConversationModel()
currentConversationModel, &lrc::api::ConversationModel::modelSorted, currentConversationModel, &lrc::api::ConversationModel::modelSorted,
[this]() { [this]() {
updateConversationsFilterWidget(); updateConversationsFilterWidget();
selectSmartlistItem(Utils::getSelectedConversation().uid); selectSmartlistItem(LRCInstance::getCurrentConversation().uid);
ui->smartList->update(); ui->smartList->update();
} }
); );
modelUpdatedConnection_ = QObject::connect( modelUpdatedConnection_ = QObject::connect(
currentConversationModel, &lrc::api::ConversationModel::conversationUpdated, currentConversationModel, &lrc::api::ConversationModel::conversationUpdated,
[this](const std::string& convUid) { [this](const QString& convUid) {
Q_UNUSED(convUid); Q_UNUSED(convUid);
ui->smartList->update(); ui->smartList->update();
} }
...@@ -1056,10 +1128,11 @@ CallWidget::connectConversationModel() ...@@ -1056,10 +1128,11 @@ CallWidget::connectConversationModel()
); );
newConversationConnection_ = QObject::connect( newConversationConnection_ = QObject::connect(
currentConversationModel, &lrc::api::ConversationModel::newConversation, currentConversationModel, &lrc::api::ConversationModel::newConversation,
[this](const std::string& convUid) { [this](const QString& convUid) {
updateSmartList(); updateSmartList();
updateConversationForNewContact(convUid); updateConversationForNewContact(convUid);
ui->conversationsFilterWidget->update(); ui->conversationsFilterWidget->update();
ui->currentAccountComboBox->canPlaceAudioOnlyCall(convUid);
} }
); );
conversationRemovedConnection_ = QObject::connect( conversationRemovedConnection_ = QObject::connect(
...@@ -1070,11 +1143,11 @@ CallWidget::connectConversationModel() ...@@ -1070,11 +1143,11 @@ CallWidget::connectConversationModel()
); );
conversationClearedConnection = QObject::connect( conversationClearedConnection = QObject::connect(
currentConversationModel, &lrc::api::ConversationModel::conversationCleared, currentConversationModel, &lrc::api::ConversationModel::conversationCleared,
[this](const std::string& convUid) { [this](const QString& convUid) {
ui->messageView->clear(); ui->messageView->clear();
// if currently selected, // if currently selected,
// switch to welcome screen (deselecting current smartlist item ) // switch to welcome screen (deselecting current smartlist item )
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
return; return;
} }
backToWelcomePage(); backToWelcomePage();
...@@ -1082,8 +1155,8 @@ CallWidget::connectConversationModel() ...@@ -1082,8 +1155,8 @@ CallWidget::connectConversationModel()
); );
interactionStatusUpdatedConnection_ = QObject::connect( interactionStatusUpdatedConnection_ = QObject::connect(
currentConversationModel, &lrc::api::ConversationModel::interactionStatusUpdated, currentConversationModel, &lrc::api::ConversationModel::interactionStatusUpdated,
[this](const std::string& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction) { [this](const QString& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction) {
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
return; return;
} }
auto& currentAccountInfo = LRCInstance::getCurrentAccountInfo(); auto& currentAccountInfo = LRCInstance::getCurrentAccountInfo();
...@@ -1095,19 +1168,15 @@ CallWidget::connectConversationModel() ...@@ -1095,19 +1168,15 @@ CallWidget::connectConversationModel()
); );
newInteractionConnection_ = QObject::connect( newInteractionConnection_ = QObject::connect(
currentConversationModel, &lrc::api::ConversationModel::newInteraction, currentConversationModel, &lrc::api::ConversationModel::newInteraction,
[this](const std::string& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction) { [this](const QString& convUid, uint64_t interactionId,
onIncomingMessage(convUid, interactionId, interaction); const lrc::api::interaction::Info& interaction) {
if (interaction.type == lrc::api::interaction::Type::CALL) { auto accountId = LRCInstance::getCurrAccId();
return; onNewInteraction(accountId, convUid, interactionId, interaction);
}
if (convUid == LRCInstance::getSelectedConvUid()) {
ui->videoWidget->simulateShowChatview(true);
}
} }
); );
interactionRemovedConnection_ = QObject::connect( interactionRemovedConnection_ = QObject::connect(
currentConversationModel, &lrc::api::ConversationModel::interactionRemoved, currentConversationModel, &lrc::api::ConversationModel::interactionRemoved,
[this](const std::string& convUid, uint64_t interactionId) { [this](const QString& convUid, uint64_t interactionId) {
Q_UNUSED(convUid); Q_UNUSED(convUid);
ui->messageView->removeInteraction(interactionId); ui->messageView->removeInteraction(interactionId);
} }
...@@ -1119,9 +1188,9 @@ CallWidget::connectConversationModel() ...@@ -1119,9 +1188,9 @@ CallWidget::connectConversationModel()
} }
void void
CallWidget::updateConversationView(const std::string& convUid) CallWidget::updateConversationView(const QString& convUid)
{ {
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
return; return;
} }
} }
...@@ -1129,43 +1198,44 @@ CallWidget::updateConversationView(const std::string& convUid) ...@@ -1129,43 +1198,44 @@ CallWidget::updateConversationView(const std::string& convUid)
void void
CallWidget::selectConversation(const QModelIndex& index) CallWidget::selectConversation(const QModelIndex& index)
{ {
auto currentConversationModel = LRCInstance::getCurrentConversationModel(); auto convModel = LRCInstance::getCurrentConversationModel();
if (currentConversationModel == nullptr || !index.isValid()) { if (convModel == nullptr || !index.isValid()) {
return; return;
} }
const auto item = currentConversationModel->filteredConversation(index.row()); const auto item = convModel->filteredConversation(index.row());
if (selectConversation(item, *currentConversationModel)) { if (selectConversation(item)) {
showChatView(index); showChatView(index);
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
if (!lastConvUid_.compare(convUid)) { if (!lastConvUid_.compare(convUid)) {
return; return;
} }
lastConvUid_.assign(convUid); lastConvUid_ = convUid;
auto currentConversationModel = LRCInstance::getCurrentConversationModel();
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
auto conversation = Utils::getConversationFromUid(convUid, *currentConversationModel); auto& conversation = LRCInstance::getConversationFromConvUid(convUid);
const auto item = currentConversationModel->filteredConversation(index.row()); if (!conversation.uid.isEmpty()) {
if (callModel->hasCall(conversation->callId) && item.callId == conversation->callId) { if (callModel->hasCall(conversation.callId) && item.callId == conversation.callId) {
setCallPanelVisibility(true); setCallPanelVisibility(true);
return; return;
} }
setCallPanelVisibility(false); setCallPanelVisibility(false);
} }
} }
}
bool bool
CallWidget::selectConversation( const lrc::api::conversation::Info& item, CallWidget::selectConversation(const lrc::api::conversation::Info& item)
lrc::api::ConversationModel& convModel)
{ {
if (LRCInstance::getSelectedConvUid() == item.uid) { if (LRCInstance::getCurrentConvUid() == item.uid) {
return false; return false;
} else if (item.participants.size() > 0) { } else if (item.participants.size() > 0) {
auto& accInfo = LRCInstance::getAccountInfo(item.accountId);
LRCInstance::setSelectedConvId(item.uid); LRCInstance::setSelectedConvId(item.uid);
convModel.selectConversation(item.uid); accInfo.conversationModel->selectConversation(item.uid);
convModel.clearUnreadInteractions(item.uid); accInfo.conversationModel->clearUnreadInteractions(item.uid);
ui->conversationsFilterWidget->update(); ui->conversationsFilterWidget->update();
return true; return true;
} }
...@@ -1174,6 +1244,10 @@ CallWidget::selectConversation( const lrc::api::conversation::Info& item, ...@@ -1174,6 +1244,10 @@ CallWidget::selectConversation( const lrc::api::conversation::Info& item,
void void
CallWidget::deselectConversation() CallWidget::deselectConversation()
{ {
if (LRCInstance::getCurrentConvUid().isEmpty()) {
return;
}
auto currentConversationModel = LRCInstance::getCurrentConversationModel(); auto currentConversationModel = LRCInstance::getCurrentConversationModel();
if (currentConversationModel == nullptr) { if (currentConversationModel == nullptr) {
...@@ -1181,26 +1255,29 @@ CallWidget::deselectConversation() ...@@ -1181,26 +1255,29 @@ CallWidget::deselectConversation()
} }
currentConversationModel->selectConversation(""); currentConversationModel->selectConversation("");
LRCInstance::setSelectedConvId(""); LRCInstance::setSelectedConvId();
if (auto smartListSelectionModel = ui->smartList->selectionModel()) {
smartListSelectionModel->clear();
}
ui->smartList->selectionModel()->clear();
disconnect(imConnection_); disconnect(imConnection_);
} }
void void
CallWidget::updateConversationForNewContact(const std::string& convUid) CallWidget::updateConversationForNewContact(const QString& convUid)
{ {
auto convModel = LRCInstance::getCurrentConversationModel(); auto convModel = LRCInstance::getCurrentConversationModel();
if (convModel == nullptr) { if (convModel == nullptr) {
return; return;
} }
ui->ringContactLineEdit->setText(""); ui->ringContactLineEdit->setText("");
auto selectedUid = LRCInstance::getSelectedConvUid(); auto selectedUid = LRCInstance::getCurrentConvUid();
auto it = Utils::getConversationFromUid(convUid, *convModel); auto& conversation = LRCInstance::getConversationFromConvUid(convUid, {}, true);
if (it != convModel->allFilteredConversations().end()) { if (!conversation.uid.isEmpty()) {
try { try {
auto contact = convModel->owner.contactModel->getContact(it->participants[0]); auto contact = convModel->owner.contactModel->getContact(conversation.participants[0]);
if (!contact.profileInfo.uri.empty() && contact.profileInfo.uri.compare(selectedUid) == 0) { if (!contact.profileInfo.uri.isEmpty() && contact.profileInfo.uri == selectedUid) {
LRCInstance::setSelectedConvId(convUid); LRCInstance::setSelectedConvId(convUid);
convModel->selectConversation(convUid); convModel->selectConversation(convUid);
} }
...@@ -1213,6 +1290,8 @@ CallWidget::updateConversationForNewContact(const std::string& convUid) ...@@ -1213,6 +1290,8 @@ CallWidget::updateConversationForNewContact(const std::string& convUid)
void void
CallWidget::updateSmartList() CallWidget::updateSmartList()
{ {
try {
if (!ui->smartList->model()) { if (!ui->smartList->model()) {
smartListModel_.reset(new SmartListModel(LRCInstance::getCurrAccId(), this)); smartListModel_.reset(new SmartListModel(LRCInstance::getCurrAccId(), this));
ui->smartList->setModel(smartListModel_.get()); ui->smartList->setModel(smartListModel_.get());
...@@ -1227,6 +1306,10 @@ CallWidget::updateSmartList() ...@@ -1227,6 +1306,10 @@ CallWidget::updateSmartList()
SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
this, this,
SLOT(smartListSelectionChanged(QItemSelection, QItemSelection))); SLOT(smartListSelectionChanged(QItemSelection, QItemSelection)));
} catch (...) {
qWarning() << "No account selected!";
return;
}
} }
void void
...@@ -1245,45 +1328,117 @@ CallWidget::update() ...@@ -1245,45 +1328,117 @@ CallWidget::update()
} }
void void
CallWidget::connectAccount(const std::string& accId) CallWidget::connectAccount(const QString& accountId)
{ {
auto callModel = LRCInstance::accountModel().getAccountInfo(accId).callModel.get(); try {
disconnect(callStatusChangedConnection_); auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
callStatusChangedConnection_ = QObject::connect(callModel, &lrc::api::NewCallModel::callStatusChanged, QObject::disconnect(callStatusChangedConnection_);
[this, accId](const std::string& callId) { callStatusChangedConnection_ = QObject::connect(
auto callModel = LRCInstance::accountModel().getAccountInfo(accId).callModel.get(); accInfo.callModel.get(),
&lrc::api::NewCallModel::callStatusChanged,
[this, accountId](const QString& callId) {
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
auto& callModel = accInfo.callModel;
auto call = callModel->getCall(callId); auto call = callModel->getCall(callId);
// change status label text
ui->callingStatusLabel->setText(lrc::api::call::to_string(call.status));
switch (call.status) { switch (call.status) {
case lrc::api::call::Status::INVALID: case lrc::api::call::Status::INVALID:
case lrc::api::call::Status::INACTIVE: case lrc::api::call::Status::INACTIVE:
case lrc::api::call::Status::ENDED: case lrc::api::call::Status::ENDED:
case lrc::api::call::Status::PEER_BUSY: case lrc::api::call::Status::PEER_BUSY:
case lrc::api::call::Status::TIMEOUT: case lrc::api::call::Status::TIMEOUT:
case lrc::api::call::Status::TERMINATING: case lrc::api::call::Status::TERMINATING: {
{ LRCInstance::renderer()->removeDistantRenderer(callId);
auto convInfo = LRCInstance::getConversationFromCallId(callId);
if (convInfo.uid.isEmpty()) {
break;
}
// If it's a conference, change the smartlist index
// to the next remaining participant.
bool forceCallOnly{ false };
if (!convInfo.confId.isEmpty()) {
auto callList = LRCInstance::getAPI().getConferenceSubcalls(convInfo.confId);
if (callList.empty()) {
auto lastConferencee = LRCInstance::instance().popLastConferencee(convInfo.confId);
callList.append(lastConferencee);
forceCallOnly = true;
}
for (const auto& callId : callList) {
if (!callModel->hasCall(callId)) {
continue;
}
auto otherConv = LRCInstance::getConversationFromCallId(callId);
if (!otherConv.uid.isEmpty() && otherConv.uid != convInfo.uid) {
LRCInstance::setSelectedConvId(otherConv.uid);
selectSmartlistItem(otherConv.uid);
ui->videoView->updateCall(otherConv.uid, otherConv.accountId, forceCallOnly);
}
}
} else {
ui->videoView->updateCall();
setCallPanelVisibility(false); setCallPanelVisibility(false);
showConversationView(); showConversationView();
callTerminating(callId);
}
break; break;
} }
case lrc::api::call::Status::CONNECTED:
case lrc::api::call::Status::IN_PROGRESS: {
auto convInfo = LRCInstance::getConversationFromCallId(callId, accountId);
if (!convInfo.uid.isEmpty() && convInfo.uid == LRCInstance::getCurrentConvUid()) {
accInfo.conversationModel->selectConversation(convInfo.uid);
}
LRCInstance::renderer()->addDistantRenderer(callId);
ui->videoView->updateCall();
break;
}
case lrc::api::call::Status::PAUSED:
ui->videoView->resetPreview();
ui->videoView->updateCall();
default: default:
break; break;
} }
ui->smartList->update();
}); });
auto& contactModel = LRCInstance::getCurrentAccountInfo().contactModel; QObject::disconnect(contactAddedConnection_);
disconnect(contactAddedConnection_); contactAddedConnection_ = QObject::connect(
contactAddedConnection_ = connect(contactModel.get(), &lrc::api::ContactModel::contactAdded, accInfo.contactModel.get(),
[this, &contactModel](const std::string & contactId) { &lrc::api::ContactModel::contactAdded,
[this, accountId](const QString& contactUri) {
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
auto convModel = LRCInstance::getCurrentConversationModel(); auto convModel = LRCInstance::getCurrentConversationModel();
auto currentConversation = Utils::getConversationFromUid(LRCInstance::getSelectedConvUid(), auto conversation = LRCInstance::getCurrentConversation();
*convModel); if (conversation.uid.isEmpty()) {
if (currentConversation == convModel->allFilteredConversations().end()) {
return; return;
} }
if (contactId == contactModel.get()->getContact((*currentConversation).participants.at(0)).profileInfo.uri) { if (contactUri == accInfo.contactModel->getContact(conversation.participants.at(0)).profileInfo.uri) {
// update call screen
auto avatarImg = QPixmap::fromImage(imageForConv(conversation.uid));
ui->callingPhoto->setPixmap(avatarImg);
ui->callerPhoto->setPixmap(avatarImg);
// update conversation
ui->messageView->clear(); ui->messageView->clear();
ui->messageView->printHistory(*convModel, currentConversation->interactions); setConversationProfileData(conversation);
ui->messageView->printHistory(*convModel, conversation.interactions);
} }
}); });
QObject::disconnect(addedToConferenceConnection_);
addedToConferenceConnection_ = QObject::connect(
accInfo.callModel.get(),
&NewCallModel::callAddedToConference,
[this](const QString& callId, const QString& confId) {
Q_UNUSED(callId);
LRCInstance::renderer()->addDistantRenderer(confId);
ui->videoView->updateCall();
});
} catch (...) {
qWarning() << "Couldn't get account: " << accountId;
}
} }
void void
...@@ -1294,6 +1449,210 @@ CallWidget::setCallPanelVisibility(bool visible) ...@@ -1294,6 +1449,210 @@ CallWidget::setCallPanelVisibility(bool visible)
ui->btnAudioCall->setVisible(!visible); ui->btnAudioCall->setVisible(!visible);
ui->btnVideoCall->setVisible(!visible); ui->btnVideoCall->setVisible(!visible);
ui->callStackWidget->setVisible(visible); ui->callStackWidget->setVisible(visible);
ui->messageView->setRecordButtonsVisibility(!visible);
}
void
CallWidget::updateChatviewFrame()
{
// TODO: remove this to start using webview navbar
// instead of native qt
if (1) {
ui->messageView->displayNavbar(false);
return;
}
auto& accInfo = LRCInstance::getCurrentAccountInfo();
auto& convInfo = LRCInstance::getCurrentConversation();
if (convInfo.uid.isEmpty()) {
return;
}
auto contactUri = convInfo.participants.front();
lrc::api::contact::Info contactInfo;
try {
contactInfo = accInfo.contactModel->getContact(contactUri);
} catch (const std::out_of_range&) {
qDebug() << "updateChatviewFrame: failed to retrieve contactInfo";
return;
}
bool temp = contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY ||
contactInfo.profileInfo.type == lrc::api::profile::Type::PENDING;
auto bestName = Utils::bestNameForContact(contactInfo);
auto bestId = Utils::bestIdForContact(contactInfo);
ui->messageView->updateChatviewFrame(accInfo.enabled, contactInfo.isBanned, temp, bestName, bestId);
}
void
CallWidget::registerShortCuts()
{
//shortcuts
auto startAudioCallSC = new QShortcut(QKeySequence(tr("Shift+Ctrl+C", "Start an audio call")), this);
auto startVideoCallSC = new QShortcut(QKeySequence(tr("Shift+Ctrl+X", "Start an video call")), this);
auto clearConvHistorySC = new QShortcut(QKeySequence(tr("Shift+Ctrl+L", "Clear history")), this);
auto blockContactSC = new QShortcut(QKeySequence(tr("Shift+Ctrl+B", "Block contact")), this);
auto copyContactNameSC = new QShortcut(QKeySequence(tr("Shift+Ctrl+J", "Copy contact name")), this);
auto openAccountListSC = new QShortcut(QKeySequence(tr("Ctrl+J", "Open account list")), this);
auto focusOnSmartListSC = new QShortcut(QKeySequence(tr("Ctrl+L", "Focus on smart list")), this);
auto focusOnSmartListNextElementSC = new QShortcut(QKeySequence(tr("Ctrl+Down", "Focus on the next element on smart list")), this);
auto focusOnSmartListPrevElementSC = new QShortcut(QKeySequence(tr("Ctrl+Up", "Focus on the previous element on smart list")), this);
auto focusOnContactSearchBarSC = new QShortcut(QKeySequence(tr("Ctrl+F", "Focus on contact search bar")), this);
auto answerCallSC = new QShortcut(QKeySequence(tr("Ctrl+Y", "Answer an incoming call")), this);
auto declineCallSC = new QShortcut(QKeySequence(tr("Ctrl+D", "Decline the call")), this);
auto shortcutsTableSC = new QShortcut(QKeySequence(tr("F10", "Show keyboard shortcuts table")), this);
auto maximizeScreenSC = new QShortcut(QKeySequence(tr("F11", "Maximize Screen")), this);
auto navigateToMediaSettingsSC = new QShortcut(QKeySequence(tr("Ctrl+M", "Navigate to media setting")), this);
auto navigateToGeneralSettingsSC = new QShortcut(QKeySequence(tr("Ctrl+G", "Navigate to general setting")), this);
auto navigateToAccountSettingsSC = new QShortcut(QKeySequence(tr("Ctrl+I", "Navigate to account setting")), this);
// connections
connect(startAudioCallSC, &QShortcut::activated,
[this] {
auto convModel = LRCInstance::getCurrentConversationModel();
auto convUid = LRCInstance::getCurrentConvUid();
if (convModel && !convUid.isEmpty())
convModel->placeAudioOnlyCall(convUid);
});
connect(startVideoCallSC, &QShortcut::activated,
[this] {
auto convModel = LRCInstance::getCurrentConversationModel();
auto convUid = LRCInstance::getCurrentConvUid();
if (convModel && !convUid.isEmpty())
convModel->placeCall(convUid);
});
connect(clearConvHistorySC, &QShortcut::activated,
[this] {
auto convModel = LRCInstance::getCurrentConversationModel();
auto convUid = LRCInstance::getCurrentConvUid();
if (convModel && !convUid.isEmpty()) {
auto reply = Utils::getReplyMessageBox(this,
QString("Clear Conversation History"),
QString("Do you really want to clear the conversation history with this contact ?"));
if (reply)
convModel->clearHistory(convUid);
}
});
connect(blockContactSC, &QShortcut::activated,
[this] {
auto convModel = LRCInstance::getCurrentConversationModel();
auto convUid = LRCInstance::getCurrentConvUid();
if (convModel && !convUid.isEmpty()) {
auto reply = Utils::getReplyMessageBox(this,
QString("Block Contact"),
QString("Do you really want to block this contact ?"));
if (reply)
convModel->removeConversation(convUid, true);
}
});
connect(copyContactNameSC, &QShortcut::activated,
[this] {
QPointer<QClipboard> clipboard = QApplication::clipboard();
clipboard->setText(
Utils::bestIdForContact(LRCInstance::getCurrentAccountInfo().contactModel->getContact(LRCInstance::getCurrentConversation().participants.front())
));
});
connect(openAccountListSC, &QShortcut::activated,
[this] {
ui->currentAccountComboBox->activateComboBox();
});
connect(focusOnSmartListSC, &QShortcut::activated,
[this] {
ui->smartList->setCurrentIndex(ui->smartList->model()->index(0, 0));
});
connect(focusOnSmartListNextElementSC, &QShortcut::activated,
[this] {
if (ui->smartList->currentIndex().row() == ui->smartList->model()->rowCount() - 1) {
return;
} else {
ui->smartList->setCurrentIndex(ui->smartList->model()->index(ui->smartList->currentIndex().row() + 1, 0));
}
});
connect(focusOnSmartListPrevElementSC, &QShortcut::activated,
[this] {
if (ui->smartList->currentIndex().row() == 0) {
return;
} else {
ui->smartList->setCurrentIndex(ui->smartList->model()->index(ui->smartList->currentIndex().row() - 1, 0));
}
});
connect(focusOnContactSearchBarSC, &QShortcut::activated,
[this] {
ui->ringContactLineEdit->setFocus();
});
connect(answerCallSC, &QShortcut::activated,
[this] {
auto& convInfo = LRCInstance::getCurrentConversation();
if (!convInfo.callId.isEmpty())
LRCInstance::getCurrentCallModel()->accept(convInfo.callId);
});
connect(declineCallSC, &QShortcut::activated,
[this] {
auto& convInfo = LRCInstance::getCurrentConversation();
auto status = LRCInstance::getCallInfoForConversation(convInfo)->status;
if (!convInfo.callId.isEmpty()) {
if (status == lrc::api::call::Status::IN_PROGRESS || status == lrc::api::call::Status::OUTGOING_RINGING) {
LRCInstance::getCurrentCallModel()->hangUp(convInfo.callId);
} else if (status == lrc::api::call::Status::INCOMING_RINGING) {
LRCInstance::getCurrentCallModel()->refuse(convInfo.callId);
}
}
});
connect(maximizeScreenSC, &QShortcut::activated,
[this] {
if (MainWindow::instance().windowState().testFlag(Qt::WindowFullScreen) == true) {
MainWindow::instance().showNormal();
}
else {
MainWindow::instance().showFullScreen();
}
});
connect(shortcutsTableSC, &QShortcut::activated,
[this] {
QUrl qmlSource{ QStringLiteral("qrc:/src/KeyBoardShortcutTable.qml") };
QmlPopupWidget qmlKeyboardShortcuts(qmlSource, qobject_cast<MainWindow*>(parent()->parent()->parent()));
qmlKeyboardShortcuts.setWindowFlags(Qt::Widget | Qt::FramelessWindowHint);
qmlKeyboardShortcuts.setAttribute(Qt::WA_AlwaysStackOnTop);
qmlKeyboardShortcuts.setClearColor(Qt::transparent);
qmlKeyboardShortcuts.setMinimumWidth(qmlKeyboardShortcuts.rootObject()->property("minWidth").toInt());
qmlKeyboardShortcuts.setMinimumHeight(qmlKeyboardShortcuts.rootObject()->property("minHeight").toInt());
qmlKeyboardShortcuts.getContainer().toStrongRef()->exec();
});
connect(navigateToMediaSettingsSC, &QShortcut::activated,
[this] {
emit NavigationSettingsPageRequested(SettingsMenu::Media);
});
connect(navigateToGeneralSettingsSC, &QShortcut::activated,
[this] {
emit NavigationSettingsPageRequested(SettingsMenu::General);
});
connect(navigateToAccountSettingsSC, &QShortcut::activated,
[this] {
emit NavigationSettingsPageRequested(SettingsMenu::Account);
});
} }
void void
...@@ -1338,7 +1697,7 @@ CallWidget::Paste() ...@@ -1338,7 +1697,7 @@ CallWidget::Paste()
QBuffer bu(&ba); QBuffer bu(&ba);
bu.open(QIODevice::WriteOnly); bu.open(QIODevice::WriteOnly);
pixmap.save(&bu, "PNG"); pixmap.save(&bu, "PNG");
auto str = QString::fromStdString(ba.toBase64().toStdString()); auto str = QString::fromLocal8Bit(ba.toBase64());
ui->messageView->setMessagesImageContent(str, true); ui->messageView->setMessagesImageContent(str, true);
} }
......
...@@ -22,18 +22,10 @@ ...@@ -22,18 +22,10 @@
#pragma once #pragma once
#include <QClipboard>
#include <QItemSelection>
#include <QMenu>
#include <QMovie>
#include <QString>
#include <QVector>
#include <QWidget>
#include "navwidget.h" #include "navwidget.h"
#include "smartlistmodel.h" #include "smartlistmodel.h"
#include "videoview.h"
// new LRC
#include "api/account.h" #include "api/account.h"
#include "api/contact.h" #include "api/contact.h"
#include "api/contactmodel.h" #include "api/contactmodel.h"
...@@ -42,6 +34,14 @@ ...@@ -42,6 +34,14 @@
#include "api/newcallmodel.h" #include "api/newcallmodel.h"
#include "globalinstances.h" #include "globalinstances.h"
#include <QClipboard>
#include <QItemSelection>
#include <QMenu>
#include <QMovie>
#include <QString>
#include <QVector>
#include <QWidget>
class ConversationItemDelegate; class ConversationItemDelegate;
class QPropertyAnimation; class QPropertyAnimation;
...@@ -62,34 +62,35 @@ public: ...@@ -62,34 +62,35 @@ public:
// NavWidget // NavWidget
virtual void navigated(bool to); virtual void navigated(bool to);
virtual void updateCustomUI(); virtual void updateCustomUI();
public slots:
virtual void slotAccountOnBoarded();
public slots: signals:
void on_ringContactLineEdit_returnPressed(); void slotAccountChangedFinished();
public slots: public slots:
virtual void slotAccountListChanged();
private slots:
void on_ringContactLineEdit_returnPressed();
void settingsButtonClicked(); void settingsButtonClicked();
void showChatView(const QModelIndex& nodeIdx); void showChatView(const QModelIndex& nodeIdx);
void showChatView(const std::string & accountId, const lrc::api::conversation::Info & convInfo); void showChatView(const QString& accountId, const lrc::api::conversation::Info & convInfo);
void setConversationProfileData(const lrc::api::conversation::Info & convInfo);
void setupChatView(const lrc::api::conversation::Info& convInfo); void setupChatView(const lrc::api::conversation::Info& convInfo);
void slotAcceptInviteClicked(const QModelIndex& index); void slotAcceptInviteClicked(const QModelIndex& index);
void slotBlockInviteClicked(const QModelIndex& index); void slotBlockInviteClicked(const QModelIndex& index);
void slotIgnoreInviteClicked(const QModelIndex& index); void slotIgnoreInviteClicked(const QModelIndex& index);
void slotCustomContextMenuRequested(const QPoint & pos); void slotCustomContextMenuRequested(const QPoint & pos);
void slotAccountChanged(int index); void slotAccountChanged(int index);
void slotShowCallView(const std::string & accountId, const lrc::api::conversation::Info & convInfo); void slotShowCallView(const QString & accountId, const lrc::api::conversation::Info & convInfo);
void slotShowIncomingCallView(const std::string & accountId, const lrc::api::conversation::Info & convInfo); void slotShowIncomingCallView(const QString & accountId, const lrc::api::conversation::Info & convInfo);
void slotShowChatView(const std::string & accountId, const lrc::api::conversation::Info & convInfo); void slotShowChatView(const QString & accountId, const lrc::api::conversation::Info & convInfo);
void slotNewTrustRequest(const QString& accountId, const QString& contactUri);
void slotToggleFullScreenClicked(); void slotToggleFullScreenClicked();
void slotVideoViewDestroyed(const std::string& callid);
void update(); void update();
void ShowContextMenu(const QPoint& pos); void ShowContextMenu(const QPoint& pos);
void Paste(); void Paste();
void Copy(); void Copy();
void CreateCopyPasteContextMenu(); void CreateCopyPasteContextMenu();
private slots:
void on_acceptButton_clicked(); void on_acceptButton_clicked();
void on_refuseButton_clicked(); void on_refuseButton_clicked();
void on_cancelButton_clicked(); void on_cancelButton_clicked();
...@@ -102,39 +103,40 @@ private slots: ...@@ -102,39 +103,40 @@ private slots:
void on_shareButton_clicked(); void on_shareButton_clicked();
void on_btnAudioCall_clicked(); void on_btnAudioCall_clicked();
void on_btnVideoCall_clicked(); void on_btnVideoCall_clicked();
private slots:
void smartListSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void smartListSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void onIncomingMessage(const std::string & convUid, uint64_t interactionId, const lrc::api::interaction::Info & interaction); void slotSetChatVisibility(bool visible);
void slotVideoDeviceListChanged();
private: private:
void placeCall(); void callTerminating(const QString& callid);
void onNewInteraction(const QString& accountId, const QString& convUid,
uint64_t interactionId, const lrc::api::interaction::Info& interaction);
void conversationsButtonClicked(); void conversationsButtonClicked();
void invitationsButtonClicked(); void invitationsButtonClicked();
void setupSmartListContextMenu(const QPoint &pos); void setupSmartListContextMenu(const QPoint &pos);
void setupQRCode(QString ringID);
void backToWelcomePage(); void backToWelcomePage();
void selectConversation(const QModelIndex& index); void selectConversation(const QModelIndex& index);
bool selectConversation(const lrc::api::conversation::Info& item, bool selectConversation(const lrc::api::conversation::Info& item);
lrc::api::ConversationModel& convModel);
void deselectConversation(); void deselectConversation();
bool connectConversationModel(); bool connectConversationModel();
void updateConversationView(const std::string& convUid); void updateConversationView(const QString& convUid);
void showConversationView(); void showConversationView();
bool selectSmartlistItem(const std::string& convUid); bool selectSmartlistItem(const QString& convUid);
QImage imageForConv(const std::string & convUid); QImage imageForConv(const QString & convUid);
void processContactLineEdit(); void processContactLineEdit();
void hideMiniSpinner(); void hideMiniSpinner();
void updateConversationForNewContact(const std::string& convUid); void updateConversationForNewContact(const QString& convUid);
void updateSmartList(); void updateSmartList();
void setSelectedAccount(const std::string & accountId); void setSelectedAccount(const QString & accountId);
void setConversationFilter(const QString& filter); void setConversationFilter(const QString& filter);
void setConversationFilter(lrc::api::profile::Type filter); void setConversationFilter(lrc::api::profile::Type filter);
void updateConversationsFilterWidget(); void updateConversationsFilterWidget();
void updateComboBox(); void updateComboBox();
void connectAccount(const std::string& accId); void connectAccount(const QString& accId);
void setCallPanelVisibility(bool visible); void setCallPanelVisibility(bool visible);
void updateChatviewFrame();
void registerShortCuts();
QMenu* menu_; QMenu* menu_;
QClipboard* clipboard_; QClipboard* clipboard_;
...@@ -144,9 +146,7 @@ private: ...@@ -144,9 +146,7 @@ private:
constexpr static int qrSize_ = 200; constexpr static int qrSize_ = 200;
// lrc QString lastConvUid_ {};
Video::Renderer* videoRenderer_;
std::string lastConvUid_ {};
lrc::api::profile::Type currentTypeFilter_{}; lrc::api::profile::Type currentTypeFilter_{};
std::unique_ptr<SmartListModel> smartListModel_; std::unique_ptr<SmartListModel> smartListModel_;
...@@ -168,5 +168,6 @@ private: ...@@ -168,5 +168,6 @@ private:
QMetaObject::Connection interactionRemovedConnection_; QMetaObject::Connection interactionRemovedConnection_;
QMetaObject::Connection contactAddedConnection_; QMetaObject::Connection contactAddedConnection_;
QMetaObject::Connection callStatusChangedConnection_; QMetaObject::Connection callStatusChangedConnection_;
QMetaObject::Connection addedToConferenceConnection_;
}; };
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CallWidget</class>
<widget class="QWidget" name="CallWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>925</width>
<height>656</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<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="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="handleWidth">
<number>1</number>
</property>
<widget class="QWidget" name="sidePanelLayoutWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<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>502</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12" stretch="0,0">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="CurrentAccountComboBox" name="currentAccountComboBox" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>60</height>
</size>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="smartListWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13" stretch="0,0">
<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="ConversationsFilterWidget" name="conversationsFilterWidget" native="true">
<layout class="QHBoxLayout" name="conversationFilterLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>15</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>15</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="btnConversations">
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="toolTip">
<string>Show conversations</string>
</property>
<property name="text">
<string>Conversations</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnInvites">
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="toolTip">
<string>Show invites</string>
</property>
<property name="text">
<string>Invites</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="smartListOuterWidget" native="true">
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="smartListOuterWidgetLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="searchBarLayoutWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>60</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="BezierConnectorWidget" name="searchTopRightWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>16</width>
<height>15</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background:purple;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="RingContactLineEdit" name="ringContactLineEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>266</width>
<height>30</height>
</size>
</property>
<property name="baseSize">
<size>
<width>244</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="toolTip">
<string>Search contact text input</string>
</property>
<property name="maxLength">
<number>100</number>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="placeholderText">
<string>Find a new or existing contact</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="BezierConnectorWidget" name="searchTopLeftWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>16</width>
<height>15</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background:purple;</string>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="SmartListView" name="smartList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoScrollMargin">
<number>16</number>
</property>
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<attribute name="headerMinimumSectionSize">
<number>0</number>
</attribute>
<attribute name="headerDefaultSectionSize">
<number>42</number>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QStackedWidget" name="stackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string/>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="welcomePage">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<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>
<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>13</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="ringLogo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_14">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="descLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>Jami is free software for universal communication which respects the freedoms and privacy of its users.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_15">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="thisIsYourLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>50</height>
</size>
</property>
<property name="font">
<font>
<underline>false</underline>
<strikeout>false</strikeout>
<kerning>true</kerning>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: #aeaeae</string>
</property>
<property name="text">
<string>This is your ID.
Copy and share it with your friends!</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="topMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="IdLabel" name="ringIdLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="text">
<string notr="true">id</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="margin">
<number>5</number>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="qrButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" 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>Show ring ID QR code</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../ressources.qrc">
<normaloff>:/images/qrcode.png</normaloff>:/images/qrcode.png</iconset>
</property>
<property name="iconSize">
<size>
<width>18</width>
<height>18</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="shareButton">
<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>Share ring ID button</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../ressources.qrc">
<normaloff>:/images/icons/ic_share_black_48dp_2x.png</normaloff>:/images/icons/ic_share_black_48dp_2x.png</iconset>
</property>
<property name="iconSize">
<size>
<width>18</width>
<height>18</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="copyLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: #aeaeae</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="text">
<string>Double-click to copy</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="qrLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: #aeaeae</string>
</property>
<property name="text">
<string>Error while generating QR Code</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_11">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<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="QPushButton" name="changelogButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>About</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<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>
</layout>
</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>17</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="mainActivityWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QSplitter" name="mainActivitySplitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="handleWidth">
<number>2</number>
</property>
<property name="childrenCollapsible">
<bool>true</bool>
</property>
<widget class="QStackedWidget" name="callStackWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>2</number>
</property>
<widget class="QWidget" name="videoPage">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="VideoView" name="videoView" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="outgoingCallPage">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
<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>
<spacer name="verticalSpacer_20">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_15">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="callingPhoto">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>133</width>
<height>133</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>133</width>
<height>133</height>
</size>
</property>
<property name="baseSize">
<size>
<width>166</width>
<height>166</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_19">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>30</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="callingBestNameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Segoe UI Emoji</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(128, 128, 128);</string>
</property>
<property name="text">
<string>best name</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_9">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>17</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="callingBestIdLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(174, 174, 174);</string>
</property>
<property name="text">
<string>best Id</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_10">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="spinnerLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_18">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="callingStatusLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(174, 174, 174);</string>
</property>
<property name="text">
<string> Incoming...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_22">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="spacing">
<number>5</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>56</width>
<height>56</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>56</width>
<height>56</height>
</size>
</property>
<property name="baseSize">
<size>
<width>56</width>
<height>56</height>
</size>
</property>
<property name="toolTip">
<string>Cancel outgoing call</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</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>
</layout>
</item>
<item>
<widget class="QLabel" name="cancelCallLabel">
<property name="styleSheet">
<string notr="true">color: rgb(174, 174, 174);</string>
</property>
<property name="text">
<string>Cancel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_21">
<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>
<widget class="QWidget" name="incomingCallPage">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_18">
<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>
<spacer name="verticalSpacer_16">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="callerPhoto">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>133</width>
<height>133</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>133</width>
<height>133</height>
</size>
</property>
<property name="baseSize">
<size>
<width>166</width>
<height>166</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>179</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="callerBestNameLabel">
<property name="font">
<font>
<family>Segoe UI Emoji</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(128, 128, 128);</string>
</property>
<property name="text">
<string>best name</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_13">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>179</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="sipCallerBestIdLabel">
<property name="font">
<font>
<family>Segoe UI Emoji</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(128, 128, 128);</string>
</property>
<property name="text">
<string>best id</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_12">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>179</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="wantToTalkLabel">
<property name="styleSheet">
<string notr="true">color: rgb(174, 174, 174);</string>
</property>
<property name="text">
<string>Wants to talk to you!</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>179</width>
<height>35</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="acceptButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>56</width>
<height>56</height>
</size>
</property>
<property name="toolTip">
<string>Answer incoming call button</string>
</property>
<property name="icon">
<iconset resource="../ressources.qrc">
<normaloff>:/images/icons/ic_done_white_24dp.png</normaloff>:/images/icons/ic_done_white_24dp.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="acceptLabel">
<property name="styleSheet">
<string notr="true">color: rgb(174, 174, 174);</string>
</property>
<property name="text">
<string>Answer</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_21">
<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>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="refuseButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>56</width>
<height>56</height>
</size>
</property>
<property name="toolTip">
<string>Ignore incoming call button</string>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</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>
</layout>
</item>
<item>
<widget class="QLabel" name="refuseLabel">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(174, 174, 174);</string>
</property>
<property name="text">
<string>Ignore</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_17">
<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>
</widget>
<widget class="QWidget" name="messagesWidget" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<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="styleSheet">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="messagingHeaderWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>60</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>60</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>14</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>14</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="imBackButton">
<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>Back to homepage button</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../ressources.qrc">
<normaloff>:/images/icons/ic_arrow_back_24px.svg</normaloff>:/images/icons/ic_arrow_back_24px.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>18</width>
<height>18</height>
</size>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_15">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_17">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="imNameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Segoe UI Emoji</family>
<pointsize>11</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
<kerning>true</kerning>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(63,63,63);</string>
</property>
<property name="text">
<string>namelabel</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="indent">
<number>-1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="imIdLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(192,192,192);</string>
</property>
<property name="text">
<string>idlabel</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="indent">
<number>2</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<spacer name="horizontalSpacer_13">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnAudioCall">
<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="text">
<string/>
</property>
<property name="icon">
<iconset resource="../ressources.qrc">
<normaloff>:/images/icons/ic_phone_24px.svg</normaloff>:/images/icons/ic_phone_24px.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>18</width>
<height>18</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnVideoCall">
<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="text">
<string/>
</property>
<property name="icon">
<iconset resource="../ressources.qrc">
<normaloff>:/images/icons/ic_video_call_24px.svg</normaloff>:/images/icons/ic_video_call_24px.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>18</width>
<height>18</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="sendContactRequestButton">
<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>Add to contacts</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</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>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="messageViewLayoutWidget" native="true">
<layout class="QHBoxLayout" name="messagesHBoxLayout" stretch="0,0,0">
<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>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="MessageWebView" name="messageView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">b</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_14">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QWebEngineView</class>
<extends>QWidget</extends>
<header location="global">QtWebEngineWidgets/QWebEngineView</header>
</customwidget>
<customwidget>
<class>RingContactLineEdit</class>
<extends>QLineEdit</extends>
<header>ringcontactlineedit.h</header>
</customwidget>
<customwidget>
<class>SmartListView</class>
<extends>QTreeView</extends>
<header>smartlistview.h</header>
</customwidget>
<customwidget>
<class>VideoView</class>
<extends>QWidget</extends>
<header>videoview.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>IdLabel</class>
<extends>QLabel</extends>
<header>idlabel.h</header>
</customwidget>
<customwidget>
<class>MessageWebView</class>
<extends>QWebEngineView</extends>
<header>messagewebview.h</header>
</customwidget>
<customwidget>
<class>ConversationsFilterWidget</class>
<extends>QWidget</extends>
<header>conversationsfilterwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>CurrentAccountComboBox</class>
<extends>QWidget</extends>
<header>currentaccountcombobox.h</header>
</customwidget>
<customwidget>
<class>BezierConnectorWidget</class>
<extends>QWidget</extends>
<header>bezierconnectorwidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>btnConversations</tabstop>
<tabstop>btnInvites</tabstop>
<tabstop>ringContactLineEdit</tabstop>
<tabstop>smartList</tabstop>
<tabstop>acceptButton</tabstop>
<tabstop>refuseButton</tabstop>
<tabstop>cancelButton</tabstop>
<tabstop>imBackButton</tabstop>
<tabstop>btnAudioCall</tabstop>
<tabstop>btnVideoCall</tabstop>
<tabstop>sendContactRequestButton</tabstop>
<tabstop>qrButton</tabstop>
<tabstop>shareButton</tabstop>
</tabstops>
<resources>
<include location="../ressources.qrc"/>
</resources>
<connections/>
</ui>
/************************************************************************** /**************************************************************************
* Copyright (C) 2019-2019 by Savoir-faire Linux * * Copyright (C) 2015-2019 by Savoir-faire Linux *
* Author: Isa Nanic <isa.nanic@savoirfairelinux.com> * * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -13,47 +13,38 @@ ...@@ -13,47 +13,38 @@
* GNU General Public License for more details. * * GNU General Public License for more details. *
* * * *
* You should have received a copy of the GNU General Public License * * You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/ **************************************************************************/
#include "avatargraphicsview.h" #include "collapsiblepasswordwidget.h"
#include "ui_collapsiblepasswordwidget.h"
AvatarGraphicsView::AvatarGraphicsView(QWidget* parent) CollapsiblePasswordWidget::CollapsiblePasswordWidget(QWidget *parent) :
: QGraphicsView(parent) QWidget(parent),
ui(new Ui::CollapsiblePasswordWidget)
{ {
setDragMode(QGraphicsView::ScrollHandDrag); ui->setupUi(this);
} }
void CollapsiblePasswordWidget::~CollapsiblePasswordWidget()
AvatarGraphicsView::wheelEvent(QWheelEvent* event)
{ {
QPoint numSteps = event->angleDelta() / (8*15); delete ui;
if (!numSteps.isNull()) {
zoomImage(numSteps);
}
event->accept();
} }
void QLineEdit*
AvatarGraphicsView::zoomImage(const QPoint& steps) CollapsiblePasswordWidget::getPasswordEdit()
{ {
steps.y() == 1 ? scale(zoomIncrement_, zoomIncrement_) : scale(1 / zoomIncrement_, 1 / zoomIncrement_); return ui->passwordEdit;
} }
void QLineEdit*
AvatarGraphicsView::paintEvent(QPaintEvent* e) CollapsiblePasswordWidget::getConfirmPasswordEdit()
{ {
QGraphicsView::paintEvent(e); return ui->confirmPasswordEdit;
QPainter painter(viewport()); }
QPainterPath square;
QPainterPath circle;
square.addRect(0, 0, width(), height());
circle.addEllipse(QPoint(width() / 2 - 0.5, height() / 2 - 0.5), circleSize_ + 1, circleSize_ + 1);
painter.setOpacity(0.3);
painter.fillPath(square.subtracted(circle), QBrush(QColor(Qt::black))); QLabel*
CollapsiblePasswordWidget::getPasswordStatusLabel()
{
return ui->passwordStatusLabel;
} }
/************************************************************************** /**************************************************************************
* Copyright (C) 2019-2019 by Savoir-faire Linux * * Copyright (C) 2015-2019 by Savoir-faire Linux *
* Author: Isa Nanic <isa.nanic@savoirfairelinux.com> * * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -13,29 +13,33 @@ ...@@ -13,29 +13,33 @@
* GNU General Public License for more details. * * GNU General Public License for more details. *
* * * *
* You should have received a copy of the GNU General Public License * * You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/ **************************************************************************/
#pragma once #pragma once
#include <QGraphicsView> // qt
#include <QWheelEvent> #include <QWidget>
#include <QDragMoveEvent> #include <QLineEdit>
#include <QLabel>
namespace Ui
{
class CollapsiblePasswordWidget;
}
class AvatarGraphicsView : public QGraphicsView class CollapsiblePasswordWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
AvatarGraphicsView(const AvatarGraphicsView& cpy);
public: public:
AvatarGraphicsView(QWidget* parent = nullptr); explicit CollapsiblePasswordWidget(QWidget *parent = nullptr);
inline void setAvatarSize(int size) { circleSize_ = size; }; ~CollapsiblePasswordWidget();
private: QLineEdit* getPasswordEdit();
void wheelEvent(QWheelEvent* event); QLineEdit* getConfirmPasswordEdit();
void zoomImage(const QPoint& steps); QLabel* getPasswordStatusLabel();
void paintEvent(QPaintEvent* e);
const qreal zoomIncrement_ = 1.03; private:
int circleSize_ = 130; Ui::CollapsiblePasswordWidget *ui;
}; };
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CollapsiblePasswordWidget</class>
<widget class="QWidget" name="CollapsiblePasswordWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>316</width>
<height>71</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>316</width>
<height>71</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLineEdit" name="confirmPasswordEdit">
<property name="minimumSize">
<size>
<width>261</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>Password confirmation text input</string>
</property>
<property name="accessibleName">
<string/>
</property>
<property name="accessibleDescription">
<string>Password confirmation text input</string>
</property>
<property name="echoMode">
<enum>QLineEdit::PasswordEchoOnEdit</enum>
</property>
<property name="placeholderText">
<string>Confirm password</string>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLineEdit" name="passwordEdit">
<property name="minimumSize">
<size>
<width>261</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>Password text input</string>
</property>
<property name="accessibleName">
<string/>
</property>
<property name="accessibleDescription">
<string>Password text entry</string>
</property>
<property name="echoMode">
<enum>QLineEdit::PasswordEchoOnEdit</enum>
</property>
<property name="placeholderText">
<string>Password</string>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_14">
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>7</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="passwordStatusLabel">
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
/***************************************************************************
* Copyright (C) 2019 by Savoir-faire Linux *
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "connectivitymonitor.h"
#include <QDebug>
#ifdef Q_OS_WIN
#include <atlbase.h>
#include <netlistmgr.h>
class NetworkEventHandler : public INetworkListManagerEvents
{
public:
NetworkEventHandler() : m_lRefCnt(1) {};
virtual ~NetworkEventHandler() {};
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) {
HRESULT hr = S_OK;
if (IsEqualIID(riid, IID_IUnknown)) {
*ppvObject = (IUnknown *) this;
} else if (IsEqualIID(riid, IID_INetworkListManagerEvents)) {
*ppvObject = (INetworkListManagerEvents *) this;
} else {
hr = E_NOINTERFACE;
}
return hr;
};
ULONG STDMETHODCALLTYPE AddRef() {
return (ULONG) InterlockedIncrement(&m_lRefCnt);
};
ULONG STDMETHODCALLTYPE Release() {
LONG res = InterlockedDecrement(&m_lRefCnt);
if (res == 0) {
delete this;
}
return (ULONG) res;
};
virtual HRESULT STDMETHODCALLTYPE
ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) {
qDebug() << "connectivity changed: " << newConnectivity;
if (connectivityChangedCb_) {
connectivityChangedCb_();
}
return S_OK;
};
void setOnConnectivityChangedCallBack(std::function<void()>&& cb) {
connectivityChangedCb_ = cb;
};
private:
LONG m_lRefCnt;
std::function<void()> connectivityChangedCb_;
};
ConnectivityMonitor::ConnectivityMonitor(QObject* parent)
: QObject(parent)
{
CoInitialize(NULL);
IUnknown *pUnknown = NULL;
HRESULT hr = CoCreateInstance(CLSID_NetworkListManager,
NULL, CLSCTX_ALL, IID_IUnknown, (void **) &pUnknown);
if (FAILED(hr)) {
return;
}
pNetworkListManager_ = NULL;
hr = pUnknown->QueryInterface(IID_INetworkListManager,
(void **) &pNetworkListManager_);
if (FAILED(hr)) {
destroy();
pUnknown->Release();
return;
}
pCPContainer_ = NULL;
hr = pNetworkListManager_->QueryInterface(IID_IConnectionPointContainer,
(void **) &pCPContainer_);
if (FAILED(hr)) {
destroy();
pUnknown->Release();
return;
}
pConnectPoint_ = NULL;
hr = pCPContainer_->FindConnectionPoint(IID_INetworkListManagerEvents,
&pConnectPoint_);
if (SUCCEEDED(hr)) {
cookie_ = NULL;
netEventHandler_ = new NetworkEventHandler;
netEventHandler_->setOnConnectivityChangedCallBack(
[this] {
emit connectivityChanged();
});
hr = pConnectPoint_->Advise((IUnknown *) netEventHandler_, &cookie_);
} else {
destroy();
}
pUnknown->Release();
}
bool
ConnectivityMonitor::isOnline()
{
if (!pNetworkListManager_) {
return false;
}
VARIANT_BOOL IsConnect = VARIANT_FALSE;
HRESULT hr = pNetworkListManager_->get_IsConnectedToInternet(&IsConnect);
if (SUCCEEDED(hr)) {
return IsConnect == VARIANT_TRUE;
}
return false;
}
void
ConnectivityMonitor::destroy()
{
if (pConnectPoint_) {
pConnectPoint_->Unadvise(cookie_);
pConnectPoint_->Release();
}
if (pCPContainer_) {
pCPContainer_->Release();
}
if (pNetworkListManager_) {
pNetworkListManager_->Release();
pNetworkListManager_ = NULL;
}
}
ConnectivityMonitor::~ConnectivityMonitor()
{
destroy();
CoUninitialize();
}
#endif // Q_OS_WIN
\ No newline at end of file
...@@ -16,31 +16,31 @@ ...@@ -16,31 +16,31 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/ **************************************************************************/
#include "ui_invitebuttonswidget.h" #pragma once
#include "invitebuttonswidget.h" #include <QObject>
InviteButtonsWidget::InviteButtonsWidget(QWidget* parent) : #ifdef Q_OS_WIN
QWidget(parent), class ConnectivityMonitor : public QObject
ui(new Ui::InviteButtonsWidget)
{ {
ui->setupUi(this); Q_OBJECT
connect(ui->btnAcceptInvite, &QPushButton::clicked, this,
[=]() { public:
emit btnAcceptInviteClicked(); explicit ConnectivityMonitor(QObject* parent = 0);
}); ~ConnectivityMonitor();
connect(ui->btnIgnoreInvite, &QPushButton::clicked, this,
[=]() { bool isOnline();
emit btnIgnoreInviteClicked();
}); signals:
connect(ui->btnBlockInvite, &QPushButton::clicked, this, void connectivityChanged();
[=]() {
emit btnBlockInviteClicked(); private:
}); void destroy();
}
struct INetworkListManager* pNetworkListManager_;
InviteButtonsWidget::~InviteButtonsWidget() struct IConnectionPointContainer* pCPContainer_;
{ struct IConnectionPoint* pConnectPoint_;
disconnect(this); class NetworkEventHandler* netEventHandler_;
delete ui; unsigned long cookie_;
} };
#endif // Q_OS_WIN
\ No newline at end of file
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Copyright (C) 2015-2019 by Savoir-faire Linux * * Copyright (C) 2015-2019 by Savoir-faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> * * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> *
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -23,24 +24,19 @@ ...@@ -23,24 +24,19 @@
#include <QMouseEvent> #include <QMouseEvent>
#include "contactpickeritemdelegate.h" #include "contactpickeritemdelegate.h"
#include "popupdialog.h"
ContactPicker::ContactPicker(QWidget *parent) : ContactPicker::ContactPicker(QWidget *parent) :
QDialog(parent), PopupWidget(parent),
ui(new Ui::ContactPicker), ui(new Ui::ContactPicker),
type_(Type::CONFERENCE) listModeltype_(SmartListModel::Type::CONFERENCE)
{ {
ui->setupUi(this); ui->setupUi(this);
setWindowFlags(Qt::CustomizeWindowHint);
setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint);
setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_TranslucentBackground, true);
ui->smartList->setItemDelegate(new ContactPickerItemDelegate()); ui->smartList->setItemDelegate(new ContactPickerItemDelegate());
selectableProxyModel_ = new SelectableProxyModel(smartListModel_.get()); selectableProxyModel_ = new SelectableProxyModel(smartListModel_.get());
ui->smartList->setModel(selectableProxyModel_); ui->smartList->setModel(selectableProxyModel_);
} }
ContactPicker::~ContactPicker() ContactPicker::~ContactPicker()
...@@ -58,45 +54,50 @@ ContactPicker::on_smartList_clicked(const QModelIndex &index) ...@@ -58,45 +54,50 @@ ContactPicker::on_smartList_clicked(const QModelIndex &index)
void void
ContactPicker::accept() ContactPicker::accept()
{ {
auto idx = ui->smartList->currentIndex(); auto index = ui->smartList->currentIndex();
if (idx.isValid()) {
// get current call id and peer uri
auto selectedConvUid = LRCInstance::getSelectedConvUid();
auto convModel = LRCInstance::getCurrentConversationModel();
auto conversation = Utils::getConversationFromUid(selectedConvUid, *convModel);
auto thisCallId = conversation->callId;
auto contactUri = idx.data(static_cast<int>(SmartListModel::Role::URI)).value<QString>().toStdString();
if (index.isValid()) {
// let parent deal with this as this dialog will be destroyed // let parent deal with this as this dialog will be destroyed
switch (type_) { switch (listModeltype_) {
case Type::CONFERENCE: case SmartListModel::Type::CONFERENCE:
emit contactWillJoinConference(thisCallId, contactUri); {
auto sectionName = index.data(SmartListModel::Role::SectionName).value<QString>();
if (!sectionName.isEmpty()) {
smartListModel_->toggleSection(sectionName);
return;
}
auto convUid = index.data(SmartListModel::Role::UID).value<QString>();
auto accId = index.data(SmartListModel::Role::AccountId).value<QString>();
auto callId = LRCInstance::getCallIdForConversationUid(convUid, accId);
if (!callId.isEmpty()) {
emit callWillJoinConference(callId);
} else {
auto contactUri = index.data(SmartListModel::Role::URI).value<QString>();
emit contactWillJoinConference(contactUri);
}
}
break; break;
case Type::TRANSFER: case SmartListModel::Type::TRANSFER:
emit contactWillDoTransfer(thisCallId, contactUri); {
auto contactUri = index.data(SmartListModel::Role::URI).value<QString>();
emit contactWillDoTransfer(contactUri);
}
break; break;
default: default:
break; break;
} }
} }
QDialog::accept(); widgetContainer_->accept();
} }
void void
ContactPicker::on_ringContactLineEdit_textChanged(const QString &arg1) ContactPicker::on_ringContactLineEdit_textChanged(const QString &arg1)
{ {
selectableProxyModel_->setFilterRegExp(QRegExp(arg1, Qt::CaseInsensitive, QRegExp::FixedString)); if (listModeltype_ == SmartListModel::Type::CONFERENCE) {
} smartListModel_->setConferenceableFilter(arg1);
void
ContactPicker::mousePressEvent(QMouseEvent *event)
{
auto contactPickerWidgetRect = ui->contactPickerWidget->rect();
if (!contactPickerWidgetRect.contains(event->pos())) {
emit willClose(event);
} }
selectableProxyModel_->setFilterRegExp(QRegExp(arg1, Qt::CaseInsensitive, QRegExp::FixedString));
} }
void void
...@@ -106,30 +107,20 @@ ContactPicker::setTitle(const QString& title) ...@@ -106,30 +107,20 @@ ContactPicker::setTitle(const QString& title)
} }
void void
ContactPicker::setType(const Type& type) ContactPicker::setType(const SmartListModel::Type& type)
{ {
type_ = type; listModeltype_ = type;
smartListModel_.reset(new SmartListModel(LRCInstance::getCurrAccId(), this, true)); smartListModel_.reset(new SmartListModel(LRCInstance::getCurrAccId(), this, type, LRCInstance::getCurrentConvUid()));
selectableProxyModel_->setSourceModel(smartListModel_.get()); selectableProxyModel_->setSourceModel(smartListModel_.get());
// adjust filter // adjust filter
switch (type_) { switch (listModeltype_) {
case Type::CONFERENCE: case SmartListModel::Type::CONFERENCE:
selectableProxyModel_->setPredicate( selectableProxyModel_->setPredicate(
[this](const QModelIndex& index, const QRegExp& regexp) { [this](const QModelIndex&, const QRegExp&) {
bool match = regexp.indexIn(index.data(Qt::DisplayRole).toString()) != -1; return true;
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString();
auto convModel = LRCInstance::getCurrentConversationModel();
auto conversation = Utils::getConversationFromUid(convUid, *convModel);
if (conversation == convModel->allFilteredConversations().end()) {
return false;
}
auto callModel = LRCInstance::getCurrentCallModel();
return match &&
!(callModel->hasCall(conversation->callId) || callModel->hasCall(conversation->confId)) &&
!index.parent().isValid();
}); });
break; break;
case Type::TRANSFER: case SmartListModel::Type::TRANSFER:
selectableProxyModel_->setPredicate( selectableProxyModel_->setPredicate(
[this](const QModelIndex& index, const QRegExp& regexp) { [this](const QModelIndex& index, const QRegExp& regexp) {
// Regex to remove current callee // Regex to remove current callee
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Copyright (C) 2015-2019 by Savoir-faire Linux * * Copyright (C) 2015-2019 by Savoir-faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> * * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> *
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -19,12 +20,13 @@ ...@@ -19,12 +20,13 @@
#pragma once #pragma once
#include <QDialog>
#include <QSortFilterProxyModel>
#include "smartlistmodel.h" #include "smartlistmodel.h"
#include "utils.h" #include "utils.h"
#include "lrcinstance.h" #include "lrcinstance.h"
#include "widgethelpers.h"
#include <QDialog>
#include <QSortFilterProxyModel>
namespace Ui { namespace Ui {
class ContactPicker; class ContactPicker;
...@@ -56,30 +58,21 @@ private: ...@@ -56,30 +58,21 @@ private:
}; };
class ContactPicker : public QDialog class ContactPicker : public PopupWidget
{ {
Q_OBJECT; Q_OBJECT;
public: public:
enum class Type {
CONFERENCE,
TRANSFER,
COUNT__
};
explicit ContactPicker(QWidget *parent = 0); explicit ContactPicker(QWidget *parent = 0);
~ContactPicker(); ~ContactPicker();
void setTitle(const QString& title); void setTitle(const QString& title);
void setType(const Type& type); void setType(const SmartListModel::Type& type);
void setCurrentCalleeDisplayName(const QString& CalleeDisplayName); void setCurrentCalleeDisplayName(const QString& CalleeDisplayName);
protected:
void mousePressEvent(QMouseEvent *event);
signals: signals:
void contactWillJoinConference(const std::string& callId, const std::string& contactUri); void contactWillJoinConference(const QString& contactUri);
void contactWillDoTransfer(const std::string& callId, const std::string& contactUri); void callWillJoinConference(const QString& callId);
void willClose(QMouseEvent *event); void contactWillDoTransfer(const QString& contactUri);
protected slots: protected slots:
void accept(); void accept();
...@@ -93,7 +86,7 @@ private: ...@@ -93,7 +86,7 @@ private:
std::unique_ptr<SmartListModel> smartListModel_; std::unique_ptr<SmartListModel> smartListModel_;
SelectableProxyModel* selectableProxyModel_; SelectableProxyModel* selectableProxyModel_;
Type type_;
QString CalleeDisplayName_; QString CalleeDisplayName_;
SmartListModel::Type listModeltype_;
}; };
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ContactPicker</class>
<widget class="QWidget" name="ContactPicker">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>256</width>
<height>330</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>320</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="title">
<property name="font">
<font>
<family>Microsoft Tai Le</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Add contact to conference</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QWidget" name="smartListOuterWidget" native="true">
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="smartListOuterWidgetLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="searchBarLayoutWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>60</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="2" column="1">
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="RingContactLineEdit" name="ringContactLineEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>30</height>
</size>
</property>
<property name="baseSize">
<size>
<width>244</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="toolTip">
<string>Search contact</string>
</property>
<property name="maxLength">
<number>100</number>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="placeholderText">
<string>Search contacts</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="SmartListView" name="smartList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoScrollMargin">
<number>16</number>
</property>
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<attribute name="headerMinimumSectionSize">
<number>0</number>
</attribute>
<attribute name="headerDefaultSectionSize">
<number>0</number>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>RingContactLineEdit</class>
<extends>QLineEdit</extends>
<header>ringcontactlineedit.h</header>
</customwidget>
<customwidget>
<class>SmartListView</class>
<extends>QTreeView</extends>
<header>smartlistview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "ringthemeutils.h" #include "ringthemeutils.h"
#include "utils.h" #include "utils.h"
#include "lrcinstance.h" #include "lrcinstance.h"
#include "mainwindow.h"
#include <ciso646> #include <ciso646>
...@@ -57,6 +56,29 @@ ContactPickerItemDelegate::paint(QPainter* painter ...@@ -57,6 +56,29 @@ ContactPickerItemDelegate::paint(QPainter* painter
highlightMap_[index.row()] = option.state & QStyle::State_MouseOver; highlightMap_[index.row()] = option.state & QStyle::State_MouseOver;
} }
QRect &rect = opt.rect;
QString sectionName = index.data(static_cast<int>(SmartListModel::Role::SectionName)).value<QString>();
if (!sectionName.isEmpty()) {
painter->fillRect(option.rect, RingTheme::lightGrey_);
QFont font(painter->font());
QPen pen(painter->pen());
auto scalingRatio = Utils::getCurrentScalingRatio();
if (scalingRatio > 1.0) {
font.setPointSize(fontSize_ - 2);
} else {
font.setPointSize(fontSize_);
}
font.setItalic(false);
font.setBold(false);
pen.setColor(RingTheme::lightBlack_);
painter->setPen(pen);
painter->setFont(font);
QMargins padding(4, 0, 0, 0);
painter->drawText(rect - padding, Qt::AlignVCenter | Qt::AlignLeft, sectionName);
return;
}
QColor presenceBorderColor = Qt::white; QColor presenceBorderColor = Qt::white;
auto rowHighlight = highlightMap_.find(index.row()); auto rowHighlight = highlightMap_.find(index.row());
if (selected) { if (selected) {
...@@ -67,8 +89,6 @@ ContactPickerItemDelegate::paint(QPainter* painter ...@@ -67,8 +89,6 @@ ContactPickerItemDelegate::paint(QPainter* painter
presenceBorderColor = RingTheme::smartlistHighlight_; presenceBorderColor = RingTheme::smartlistHighlight_;
} }
QRect &rect = opt.rect;
// Avatar drawing // Avatar drawing
opt.decorationSize = QSize(sizeImage_, sizeImage_); opt.decorationSize = QSize(sizeImage_, sizeImage_);
opt.decorationPosition = QStyleOptionViewItem::Left; opt.decorationPosition = QStyleOptionViewItem::Left;
...@@ -117,7 +137,11 @@ ContactPickerItemDelegate::sizeHint(const QStyleOptionViewItem& option, ...@@ -117,7 +137,11 @@ ContactPickerItemDelegate::sizeHint(const QStyleOptionViewItem& option,
const QModelIndex& index) const const QModelIndex& index) const
{ {
Q_UNUSED(option); Q_UNUSED(option);
Q_UNUSED(index); if (!index.data(static_cast<int>(SmartListModel::Role::SectionName))
.value<QString>()
.isEmpty()) {
return QSize(0, sectionCellHeight_);
}
return QSize(0, cellHeight_); return QSize(0, cellHeight_);
} }
...@@ -130,9 +154,8 @@ ContactPickerItemDelegate::paintRingContactItem(QPainter* painter, ...@@ -130,9 +154,8 @@ ContactPickerItemDelegate::paintRingContactItem(QPainter* painter,
Q_UNUSED(option); Q_UNUSED(option);
QFont font(painter->font()); QFont font(painter->font());
QPen pen(painter->pen()); QPen pen(painter->pen());
painter->setPen(pen);
auto scalingRatio = MainWindow::instance().getCurrentScalingRatio(); auto scalingRatio = Utils::getCurrentScalingRatio();
if (scalingRatio > 1.0) { if (scalingRatio > 1.0) {
font.setPointSize(fontSize_ - 2); font.setPointSize(fontSize_ - 2);
} else { } else {
...@@ -140,7 +163,6 @@ ContactPickerItemDelegate::paintRingContactItem(QPainter* painter, ...@@ -140,7 +163,6 @@ ContactPickerItemDelegate::paintRingContactItem(QPainter* painter,
} }
auto leftMargin = dx_ + sizeImage_ + dx_; auto leftMargin = dx_ + sizeImage_ + dx_;
auto rightMargin = dx_;
auto topMargin = 4; auto topMargin = 4;
auto bottomMargin = 8; auto bottomMargin = 8;
...@@ -194,7 +216,7 @@ ContactPickerItemDelegate::paintSIPContactItem(QPainter* painter, ...@@ -194,7 +216,7 @@ ContactPickerItemDelegate::paintSIPContactItem(QPainter* painter,
QPen pen(painter->pen()); QPen pen(painter->pen());
painter->setPen(pen); painter->setPen(pen);
auto scalingRatio = MainWindow::instance().getCurrentScalingRatio(); auto scalingRatio = Utils::getCurrentScalingRatio();
if (scalingRatio > 1.0) { if (scalingRatio > 1.0) {
font.setPointSize(fontSize_ - 2); font.setPointSize(fontSize_ - 2);
} else { } else {
...@@ -202,7 +224,6 @@ ContactPickerItemDelegate::paintSIPContactItem(QPainter* painter, ...@@ -202,7 +224,6 @@ ContactPickerItemDelegate::paintSIPContactItem(QPainter* painter,
} }
auto leftMargin = dx_ + sizeImage_ + dx_; auto leftMargin = dx_ + sizeImage_ + dx_;
auto rightMargin = dx_;
auto topMargin = 4; auto topMargin = 4;
auto bottomMargin = 8; auto bottomMargin = 8;
......
...@@ -39,6 +39,7 @@ private: ...@@ -39,6 +39,7 @@ private:
constexpr static int sizeImage_ = 48; constexpr static int sizeImage_ = 48;
constexpr static int cellHeight_ = 60; constexpr static int cellHeight_ = 60;
constexpr static int sectionCellHeight_ = 24;
constexpr static int dy_ = 6; constexpr static int dy_ = 6;
constexpr static int dx_ = 12; constexpr static int dx_ = 12;
constexpr static int fontSize_ = 11; constexpr static int fontSize_ = 11;
......
...@@ -22,19 +22,24 @@ ...@@ -22,19 +22,24 @@
#include <QApplication> #include <QApplication>
#include <QPainter> #include <QPainter>
#include <QPixmap> #include <QPixmap>
#include <QSvgRenderer>
// Client // Client
#include "smartlistmodel.h" #include "smartlistmodel.h"
#include "ringthemeutils.h" #include "ringthemeutils.h"
#include "utils.h" #include "utils.h"
#include "lrcinstance.h" #include "lrcinstance.h"
#include "mainwindow.h"
#include <ciso646> #include <ciso646>
ConversationItemDelegate::ConversationItemDelegate(QObject* parent) ConversationItemDelegate::ConversationItemDelegate(QObject* parent)
: QItemDelegate(parent) : QItemDelegate(parent)
{ {
QSvgRenderer svgRenderer(QString(":/images/icons/ic_baseline-search-24px.svg"));
searchIcon_ = new QPixmap(QSize(sizeImage_, sizeImage_));
searchIcon_->fill(Qt::transparent);
QPainter pixPainter(searchIcon_);
svgRenderer.render(&pixPainter);
} }
void void
...@@ -59,40 +64,50 @@ ConversationItemDelegate::paint(QPainter* painter ...@@ -59,40 +64,50 @@ ConversationItemDelegate::paint(QPainter* painter
highlightMap_[index.row()] = option.state & QStyle::State_MouseOver; highlightMap_[index.row()] = option.state & QStyle::State_MouseOver;
} }
using namespace lrc::api;
auto type = Utils::toEnum<profile::Type>(
index.data(static_cast<int>(SmartListModel::Role::ContactType)).value<int>()
);
// One does not simply keep the highlighted state drawn when the context // One does not simply keep the highlighted state drawn when the context
// menu is open // menu is open
QColor presenceBorderColor = Qt::white; QString uriStr = index.data(static_cast<int>(SmartListModel::Role::URI)).value<QString>();
if (not (type == profile::Type::TEMPORARY and uriStr.isEmpty())) {
auto rowHighlight = highlightMap_.find(index.row()); auto rowHighlight = highlightMap_.find(index.row());
if (selected) { if (selected) {
painter->fillRect(option.rect, RingTheme::smartlistSelection_); painter->fillRect(option.rect, RingTheme::smartlistSelection_);
presenceBorderColor = RingTheme::smartlistSelection_;
} else if (rowHighlight != highlightMap_.end() && (*rowHighlight).second) { } else if (rowHighlight != highlightMap_.end() && (*rowHighlight).second) {
painter->fillRect(option.rect, RingTheme::smartlistHighlight_); painter->fillRect(option.rect, RingTheme::smartlistHighlight_);
presenceBorderColor = RingTheme::smartlistHighlight_;
} }
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString(); auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>();
auto conversation = Utils::getConversationFromUid(convUid, *LRCInstance::getCurrentConversationModel()); auto conversation = LRCInstance::getConversationFromConvUid(convUid);
if (LRCInstance::getCurrentCallModel()->hasCall(conversation->callId)) { if (conversation.uid.isEmpty()) return;
if (LRCInstance::getCurrentCallModel()->hasCall(conversation.callId)) {
auto color = QColor(RingTheme::blue_.lighter(180)); auto color = QColor(RingTheme::blue_.lighter(180));
presenceBorderColor = color;
color.setAlpha(128); color.setAlpha(128);
painter->fillRect(option.rect, color); painter->fillRect(option.rect, color);
} }
}
QRect &rect = opt.rect; QRect &rect = opt.rect;
// Avatar drawing
opt.decorationSize = QSize(sizeImage_, sizeImage_); opt.decorationSize = QSize(sizeImage_, sizeImage_);
opt.decorationPosition = QStyleOptionViewItem::Left; opt.decorationPosition = QStyleOptionViewItem::Left;
opt.decorationAlignment = Qt::AlignCenter; opt.decorationAlignment = Qt::AlignCenter;
QRect rectAvatar(dx_ + rect.left(), rect.top() + dy_, sizeImage_, sizeImage_); QRect rectAvatar(dx_ + rect.left(), rect.top() + dy_, sizeImage_, sizeImage_);
if (type == profile::Type::TEMPORARY and uriStr.isEmpty()) {
// Search icon
drawDecoration(painter, opt, rectAvatar, *searchIcon_);
} else {
// Avatar drawing
drawDecoration(painter, opt, rectAvatar, drawDecoration(painter, opt, rectAvatar,
QPixmap::fromImage(index.data(Qt::DecorationRole).value<QImage>()) QPixmap::fromImage(index.data(Qt::DecorationRole).value<QImage>())
.scaled(sizeImage_, sizeImage_, Qt::KeepAspectRatio, Qt::SmoothTransformation)); .scaled(sizeImage_, sizeImage_, Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
QFont font(painter->font()); QFont font(painter->font());
if (type != profile::Type::TEMPORARY) {
// If there's unread messages, a message count is displayed // If there's unread messages, a message count is displayed
if (auto messageCount = index.data(static_cast<int>(SmartListModel::Role::UnreadMessagesCount)).toInt()) { if (auto messageCount = index.data(static_cast<int>(SmartListModel::Role::UnreadMessagesCount)).toInt()) {
QString messageCountText = (messageCount > 9) ? "9+" : QString::number(messageCount); QString messageCountText = (messageCount > 9) ? "9+" : QString::number(messageCount);
...@@ -126,25 +141,23 @@ ConversationItemDelegate::paint(QPainter* painter ...@@ -126,25 +141,23 @@ ConversationItemDelegate::paint(QPainter* painter
qreal innerCRadius = outerCRadius * 0.75; qreal innerCRadius = outerCRadius * 0.75;
outerCircle.addEllipse(center, outerCRadius, outerCRadius); outerCircle.addEllipse(center, outerCRadius, outerCRadius);
innerCircle.addEllipse(center, innerCRadius, innerCRadius); innerCircle.addEllipse(center, innerCRadius, innerCRadius);
painter->fillPath(outerCircle, presenceBorderColor); painter->fillPath(outerCircle, Qt::white);
painter->fillPath(innerCircle, RingTheme::presenceGreen_); 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) { switch (type) {
case profile::Type::TEMPORARY:
case profile::Type::RING: case profile::Type::RING:
case profile::Type::SIP: case profile::Type::SIP:
case profile::Type::TEMPORARY: paintConversationItem(painter, option, rect, index,
paintConversationItem(painter, option, rect, index); type == profile::Type::TEMPORARY);
break; break;
case profile::Type::PENDING: case profile::Type::PENDING:
paintRingInviteConversationItem(painter, option, rect, index); paintInvitationItem(painter, option, rect, index);
break; break;
default: default:
paintConversationItem(painter, option, rect, index); paintConversationItem(painter, option, rect, index, true);
break; break;
} }
} }
...@@ -162,7 +175,8 @@ void ...@@ -162,7 +175,8 @@ void
ConversationItemDelegate::paintConversationItem(QPainter* painter, ConversationItemDelegate::paintConversationItem(QPainter* painter,
const QStyleOptionViewItem& option, const QStyleOptionViewItem& option,
const QRect& rect, const QRect& rect,
const QModelIndex& index) const const QModelIndex& index,
const bool isTemporary) const
{ {
Q_UNUSED(option); Q_UNUSED(option);
QFont font(painter->font()); QFont font(painter->font());
...@@ -171,7 +185,7 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter, ...@@ -171,7 +185,7 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
int infoTextWidthModifier = 0; int infoTextWidthModifier = 0;
int infoText2HeightModifier = 0; int infoText2HeightModifier = 0;
auto scalingRatio = MainWindow::instance().getCurrentScalingRatio(); auto scalingRatio = Utils::getCurrentScalingRatio();
if (scalingRatio > 1.0) { if (scalingRatio > 1.0) {
font.setPointSize(fontSize_ - 2); font.setPointSize(fontSize_ - 2);
infoTextWidthModifier = 12; infoTextWidthModifier = 12;
...@@ -186,9 +200,16 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter, ...@@ -186,9 +200,16 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
auto topMargin = 4; auto topMargin = 4;
auto bottomMargin = 8; auto bottomMargin = 8;
int rect1Width;
if (!isTemporary) {
rect1Width = rect.width() - leftMargin - infoTextWidth_ - infoTextWidthModifier - 8;
} else {
rect1Width = rect.width() - leftMargin - rightMargin;
}
QRect rectName1(rect.left() + leftMargin, QRect rectName1(rect.left() + leftMargin,
rect.top() + topMargin, rect.top() + topMargin,
rect.width() - leftMargin - infoTextWidth_ - infoTextWidthModifier - 8, rect1Width,
rect.height() / 2 - 2); rect.height() / 2 - 2);
QRect rectName2(rectName1.left(), QRect rectName2(rectName1.left(),
...@@ -196,28 +217,19 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter, ...@@ -196,28 +217,19 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
rectName1.width(), rectName1.width(),
rectName1.height() - bottomMargin + infoText2HeightModifier); rectName1.height() - bottomMargin + infoText2HeightModifier);
QRect rectInfo1(rectName1.left() + rectName1.width(),
rect.top() + topMargin,
infoTextWidth_ - rightMargin + infoTextWidthModifier + 2,
rect.height() / 2 - 2);
QRect rectInfo2(rectInfo1.left(),
rectInfo1.top() + rectInfo1.height() - infoText2HeightModifier,
rectInfo1.width(),
rectInfo1.height() - bottomMargin + infoText2HeightModifier + 4);
QFontMetrics fontMetrics(font); QFontMetrics fontMetrics(font);
// The name is displayed at the avatar's right // The name is displayed at the avatar's right
QString nameStr = index.data(static_cast<int>(SmartListModel::Role::DisplayName)).value<QString>(); QString nameStr = index.data(static_cast<int>(SmartListModel::Role::DisplayName)).value<QString>();
if (!nameStr.isNull()) { if (!nameStr.isNull()) {
font.setItalic(false);
font.setBold(false);
pen.setColor(RingTheme::lightBlack_); pen.setColor(RingTheme::lightBlack_);
painter->setPen(pen); painter->setPen(pen);
painter->setFont(font); QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
QString elidedNameStr = fontMetrics.elidedText(nameStr, Qt::ElideRight, rectName1.width()); emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
QString elidedNameStr = QFontMetrics(emojiMsgFont).elidedText(nameStr, Qt::ElideRight, rectName1.width());
painter->setFont(emojiMsgFont);
painter->drawText(rectName1, Qt::AlignVCenter | Qt::AlignLeft, elidedNameStr); painter->drawText(rectName1, Qt::AlignVCenter | Qt::AlignLeft, elidedNameStr);
painter->setFont(font);
} }
// Display the ID under the name // Display the ID under the name
...@@ -232,6 +244,20 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter, ...@@ -232,6 +244,20 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
painter->drawText(rectName2, Qt::AlignVCenter | Qt::AlignLeft, idStr); painter->drawText(rectName2, Qt::AlignVCenter | Qt::AlignLeft, idStr);
} }
if (isTemporary) {
return;
}
QRect rectInfo1(rectName1.left() + rectName1.width(),
rect.top() + topMargin,
infoTextWidth_ - rightMargin + infoTextWidthModifier + 2,
rect.height() / 2 - 2);
QRect rectInfo2(rectInfo1.left(),
rectInfo1.top() + rectInfo1.height() - infoText2HeightModifier,
rectInfo1.width(),
rectInfo1.height() - bottomMargin + infoText2HeightModifier + 4);
// top-right: last interaction date/time // top-right: last interaction date/time
QString lastUsedStr = index.data(static_cast<int>(SmartListModel::Role::LastInteractionDate)).value<QString>(); QString lastUsedStr = index.data(static_cast<int>(SmartListModel::Role::LastInteractionDate)).value<QString>();
if (!lastUsedStr.isNull()) { if (!lastUsedStr.isNull()) {
...@@ -244,7 +270,46 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter, ...@@ -244,7 +270,46 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
painter->drawText(rectInfo1, Qt::AlignVCenter | Qt::AlignRight, lastUsedStr); painter->drawText(rectInfo1, Qt::AlignVCenter | Qt::AlignRight, lastUsedStr);
} }
// bottom-right: last interaction snippet // bottom-right: last interaction snippet or call state (if in call)
auto draft = index.data(static_cast<int>(SmartListModel::Role::Draft)).value<QString>();
if (!draft.isEmpty()) {
painter->save();
uint cp = 0x270F;
auto emojiString = QString::fromUcs4(&cp, 1);
QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
QString text{ tr("Draft") };
int widthText{ QFontMetrics(font).width(text) };
int widthEmoji{ QFontMetrics(emojiMsgFont).width(emojiString) };
int margin { 4 };
painter->setFont(font);
painter->setPen(QColor(207, 83, 0));
painter->drawText(rectInfo2, Qt::AlignVCenter | Qt::AlignRight, text);
rectInfo2.moveTop(rectInfo2.top() - 2);
painter->setOpacity(0.7);
painter->setFont(emojiMsgFont);
painter->drawText(rectInfo2.right() - widthText - widthEmoji - margin, rectInfo2.y(),
widthEmoji, rectInfo2.height(), Qt::AlignVCenter, emojiString);
painter->restore();
return;
}
if (index.data(static_cast<int>(SmartListModel::Role::InCall)).value<bool>()) {
QString callStateStr = index.data(static_cast<int>(SmartListModel::Role::CallStateStr)).value<QString>();
if (!callStateStr.isNull()) {
painter->save();
font.setWeight(QFont::DemiBold);
pen.setColor(RingTheme::grey_.darker(140));
painter->setPen(pen);
painter->setFont(font);
callStateStr = fontMetrics.elidedText(callStateStr, Qt::ElideRight, rectInfo2.width());
painter->drawText(rectInfo2, Qt::AlignVCenter | Qt::AlignRight, callStateStr);
painter->restore();
}
} else {
QString interactionStr = index.data(static_cast<int>(SmartListModel::Role::LastInteraction)).value<QString>(); QString interactionStr = index.data(static_cast<int>(SmartListModel::Role::LastInteraction)).value<QString>();
if (!interactionStr.isNull()) { if (!interactionStr.isNull()) {
painter->save(); painter->save();
...@@ -268,15 +333,8 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter, ...@@ -268,15 +333,8 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
} }
} }
interactionStr = QString::fromUcs4(&emojiless.at(0), emojiless.size()); interactionStr = QString::fromUcs4(&emojiless.at(0), emojiless.size());
// remove everythin after 'call'
auto indexOfCallStr = interactionStr.lastIndexOf(QString("call"), -1, Qt::CaseInsensitive);
if (indexOfCallStr != -1) {
interactionStr = interactionStr.left(indexOfCallStr + 4);
}
} else { } else {
QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji")); QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
emojiMsgFont.setItalic(false);
emojiMsgFont.setBold(false);
emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_); emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
rectInfo2.setTop(rectInfo2.top() - 6); rectInfo2.setTop(rectInfo2.top() - 6);
painter->setOpacity(0.7); painter->setOpacity(0.7);
...@@ -287,9 +345,10 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter, ...@@ -287,9 +345,10 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
painter->restore(); painter->restore();
} }
} }
}
void void
ConversationItemDelegate::paintRingInviteConversationItem(QPainter* painter, ConversationItemDelegate::paintInvitationItem(QPainter* painter,
const QStyleOptionViewItem& option, const QStyleOptionViewItem& option,
const QRect& rect, const QRect& rect,
const QModelIndex& index) const const QModelIndex& index) const
...@@ -301,17 +360,9 @@ ConversationItemDelegate::paintRingInviteConversationItem(QPainter* painter, ...@@ -301,17 +360,9 @@ ConversationItemDelegate::paintRingInviteConversationItem(QPainter* painter,
auto leftMargin = dx_ + sizeImage_ + dx_; auto leftMargin = dx_ + sizeImage_ + dx_;
auto rightMargin = dx_; auto rightMargin = dx_;
auto scalingRatio = MainWindow::instance().getCurrentScalingRatio(); auto scalingRatio = Utils::getCurrentScalingRatio();
font.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_); font.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
if (option.state & QStyle::State_MouseOver) {
if (scalingRatio > 1.0) {
rightMargin = infoTextWidth_ + 12 - dx_ * 2;
} else {
rightMargin = infoTextWidth_ - dx_ * 2;
}
}
auto topMargin = 4; auto topMargin = 4;
auto bottomMargin = 8; auto bottomMargin = 8;
...@@ -330,12 +381,12 @@ ConversationItemDelegate::paintRingInviteConversationItem(QPainter* painter, ...@@ -330,12 +381,12 @@ ConversationItemDelegate::paintRingInviteConversationItem(QPainter* painter,
// The name is displayed at the avatar's right // The name is displayed at the avatar's right
QString nameStr = index.data(static_cast<int>(SmartListModel::Role::DisplayName)).value<QString>(); QString nameStr = index.data(static_cast<int>(SmartListModel::Role::DisplayName)).value<QString>();
if (!nameStr.isNull()) { if (!nameStr.isNull()) {
font.setItalic(false);
font.setBold(false);
pen.setColor(RingTheme::lightBlack_); pen.setColor(RingTheme::lightBlack_);
painter->setPen(pen); painter->setPen(pen);
painter->setFont(font); QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
QString elidedNameStr = fontMetrics.elidedText(nameStr, Qt::ElideRight, rectName1.width()); emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
QString elidedNameStr = QFontMetrics(emojiMsgFont).elidedText(nameStr, Qt::ElideRight, rectName1.width());
painter->setFont(emojiMsgFont);
painter->drawText(rectName1, Qt::AlignVCenter | Qt::AlignLeft, elidedNameStr); painter->drawText(rectName1, Qt::AlignVCenter | Qt::AlignLeft, elidedNameStr);
} }
......
...@@ -34,8 +34,15 @@ protected: ...@@ -34,8 +34,15 @@ protected:
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
private: private:
void paintConversationItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const; void paintConversationItem(QPainter* painter,
void paintRingInviteConversationItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const; const QStyleOptionViewItem& option,
const QRect& rect,
const QModelIndex& index,
const bool isTemporary) const;
void paintInvitationItem( QPainter* painter,
const QStyleOptionViewItem& option,
const QRect& rect,
const QModelIndex& index) const;
constexpr static int sizeImage_ = 48; constexpr static int sizeImage_ = 48;
constexpr static int cellHeight_ = 60; constexpr static int cellHeight_ = 60;
...@@ -44,5 +51,7 @@ private: ...@@ -44,5 +51,7 @@ private:
constexpr static int fontSize_ = 11; constexpr static int fontSize_ = 11;
constexpr static int infoTextWidth_ = 176; constexpr static int infoTextWidth_ = 176;
QPixmap* searchIcon_;
mutable std::map<int, bool> highlightMap_; mutable std::map<int, bool> highlightMap_;
}; };