Commit 029b95a8 authored by Edric Milaret's avatar Edric Milaret

video: add video overlay and video view

- Display name and time on top of the video
- Display the call control on the bottom of the video
- Overlay fade (after 2 sec) when mouse exit the widget
- Overlay appear as soon as the mouse enter the widget
- Move logic into VideoView (screen share / fullscreen)
- Remove mute and slider button on callWidget
- Remove call control on callWidget
- Lay the ground work for the move of the im UI

Refs #74270

Change-Id: I024f1f80f18165c23480ef1e68aa970081732bda
parent 5ceea8c7
......@@ -44,8 +44,9 @@ SOURCES += main.cpp\
selectareadialog.cpp \
accountserializationadapter.cpp \
instantmessagingwidget.cpp \
accountstatedelegate.cpp
accountstatedelegate.cpp \
videoview.cpp \
videooverlay.cpp
HEADERS += mainwindow.h \
callwidget.h \
......@@ -65,7 +66,9 @@ HEADERS += mainwindow.h \
selectareadialog.h \
accountserializationadapter.h \
instantmessagingwidget.h \
accountstatedelegate.h
accountstatedelegate.h \
videoview.h \
videooverlay.h
FORMS += mainwindow.ui \
callwidget.ui \
......@@ -76,7 +79,9 @@ FORMS += mainwindow.ui \
aboutdialog.ui \
pivotviewwidget.ui \
wizarddialog.ui \
instantmessagingwidget.ui
instantmessagingwidget.ui \
videoview.ui \
videooverlay.ui
win32: LIBS += -lole32 -luuid -lshlwapi
......
......@@ -42,9 +42,6 @@ CallWidget::CallWidget(QWidget *parent) :
{
ui->setupUi(this);
ui->holdButton->setCheckable(true);
ui->muteMicButton->setCheckable(true);
ui->muteSpeakerButton->setCheckable(true);
ui->callInvite->setVisible(false);
ui->videoWidget->setVisible(false);
......@@ -72,6 +69,7 @@ CallWidget::CallWidget(QWidget *parent) :
, SLOT(findRingAccount(QModelIndex, QModelIndex, QVector<int>)));
ui->callList->setModel(callModel_);
ui->callList->setSelectionModel(callModel_->selectionModel());
CategorizedHistoryModel::instance()->
addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
......@@ -96,9 +94,6 @@ CallWidget::CallWidget(QWidget *parent) :
ui->contactView->setModel(CategorizedContactModel::instance());
ui->contactView->setItemDelegate(new ContactDelegate());
ui->speakerSlider->setValue(Audio::Settings::instance()->playbackVolume());
ui->micSlider->setValue(Audio::Settings::instance()->captureVolume());
findRingAccount();
} catch (...) {
......@@ -229,23 +224,6 @@ CallWidget::on_refuseButton_clicked()
ui->callInvite->setVisible(false);
}
void
CallWidget::on_holdButton_toggled(bool checked)
{
Q_UNUSED(checked)
if (actualCall_ == nullptr)
return;
actualCall_->performAction(Call::Action::HOLD);
}
void
CallWidget::on_hangupButton_clicked()
{
if (actualCall_ == nullptr)
return;
actualCall_->performAction(Call::Action::REFUSE);
}
void
CallWidget::addedCall(Call* call, Call* parent) {
Q_UNUSED(parent);
......@@ -264,8 +242,6 @@ CallWidget::callStateChanged(Call* call, Call::State previousState)
if (call->state() == Call::State::OVER || call->state() == Call::State::ERROR) {
setActualCall(nullptr);
ui->videoWidget->hide();
} else if (call->state() == Call::State::HOLD) {
ui->videoWidget->hide();
} else if (call->state() == Call::State::CURRENT) {
ui->videoWidget->show();
}
......@@ -287,42 +263,6 @@ CallWidget::on_callList_activated(const QModelIndex &index)
ui->videoWidget->show();
}
void
CallWidget::on_muteSpeakerButton_toggled(bool checked)
{
Audio::Settings::instance()->mutePlayback(checked);
}
void
CallWidget::on_muteMicButton_toggled(bool checked)
{
Audio::Settings::instance()->muteCapture(checked);
}
void
CallWidget::on_speakerSlider_sliderMoved(int position)
{
outputVolume_ = position;
}
void
CallWidget::on_speakerSlider_sliderReleased()
{
emit Audio::Settings::instance()->setPlaybackVolume(outputVolume_);
}
void
CallWidget::on_micSlider_sliderMoved(int position)
{
inputVolume_ = position;
}
void
CallWidget::on_micSlider_sliderReleased()
{
emit Audio::Settings::instance()->setCaptureVolume(inputVolume_);
}
void
CallWidget::atExit() {
......@@ -366,8 +306,6 @@ void
CallWidget::setActualCall(Call* value)
{
actualCall_ = value;
ui->holdButton->setEnabled(actualCall_ != nullptr);
ui->hangupButton->setEnabled(actualCall_ != nullptr);
ui->instantMessagingWidget->setVisible(actualCall_ != nullptr);
ui->instantMessagingWidget->setMediaText(actualCall_);
}
......
......@@ -23,6 +23,7 @@
#include <QVector>
#include <QString>
#include <QMenu>
#include <QItemSelection>
#include "navwidget.h"
#include "instantmessagingwidget.h"
......@@ -50,18 +51,10 @@ public:
private slots:
void on_acceptButton_clicked();
void on_refuseButton_clicked();
void on_holdButton_toggled(bool checked);
void on_hangupButton_clicked();
void on_callList_activated(const QModelIndex &index);
void on_muteSpeakerButton_toggled(bool checked);
void on_muteMicButton_toggled(bool checked);
void on_speakerSlider_sliderMoved(int position);
void on_speakerSlider_sliderReleased();
void on_micSlider_sliderMoved(int position);
void on_micSlider_sliderReleased();
void on_contactView_doubleClicked(const QModelIndex &index);
void on_historyList_doubleClicked(const QModelIndex &index);
void on_sortComboBox_currentIndexChanged(int index);
void on_callList_activated(const QModelIndex &index);
private slots:
void callIncoming(Call *call);
......
......@@ -29,7 +29,7 @@
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,0">
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,1">
<property name="topMargin">
<number>0</number>
</property>
......@@ -189,40 +189,6 @@
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="holdButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Hold/Unhold</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/phone-paused.png</normaloff>:/images/phone-paused.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="hangupButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Hangup</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/phone-hangup.png</normaloff>:/images/phone-hangup.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
......@@ -253,7 +219,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="VideoWidget" name="videoWidget" native="true"/>
<widget class="VideoView" name="videoWidget" native="true"/>
</item>
<item>
<widget class="QWidget" name="callInvite" native="true">
......@@ -314,70 +280,6 @@
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="horizontalWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="muteSpeakerButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/speaker-off.png</normaloff>:/images/speaker-off.png</iconset>
</property>
<property name="iconSize">
<size>
<width>25</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="speakerSlider">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="muteMicButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/microphone-off.png</normaloff>:/images/microphone-off.png</iconset>
</property>
<property name="iconSize">
<size>
<width>25</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="micSlider">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
<zorder>micSlider</zorder>
<zorder>muteMicButton</zorder>
<zorder>speakerSlider</zorder>
<zorder>muteSpeakerButton</zorder>
</widget>
</item>
<item>
<widget class="InstantMessagingWidget" name="instantMessagingWidget" native="true">
<property name="sizePolicy">
......@@ -438,9 +340,9 @@
</widget>
<customwidgets>
<customwidget>
<class>VideoWidget</class>
<class>VideoView</class>
<extends>QWidget</extends>
<header>videowidget.h</header>
<header>videoview.h</header>
<container>1</container>
</customwidget>
<customwidget>
......
......@@ -24,5 +24,6 @@
<file>images/spinner.gif</file>
<file>images/folder-download.png</file>
<file>images/arrow-right.png</file>
<file>images/message-text-outline.png</file>
</qresource>
</RCC>
/***************************************************************************
* Copyright (C) 2015 by Savoir-Faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "videooverlay.h"
#include "ui_videooverlay.h"
#include "callmodel.h"
VideoOverlay::VideoOverlay(QWidget *parent) :
QWidget(parent),
ui(new Ui::VideoOverlay)
{
ui->setupUi(this);
actionModel_ = CallModel::instance()->userActionModel();
setAttribute(Qt::WA_NoSystemBackground);
}
VideoOverlay::~VideoOverlay()
{
delete ui;
}
void
VideoOverlay::setName(const QString& name)
{
ui->nameLabel->setText(name);
}
void
VideoOverlay::setTime(const QString& time)
{
ui->timerLabel->setText(time);
}
void
VideoOverlay::on_holdButton_toggled(bool checked)
{
Q_UNUSED(checked)
actionModel_->execute(UserActionModel::Action::HOLD);
}
void
VideoOverlay::on_hangupButton_clicked()
{
actionModel_->execute(UserActionModel::Action::HANGUP);
}
void
VideoOverlay::on_chatButton_toggled(bool checked)
{
//TODO : Link this to im class once it's merged
}
/***************************************************************************
* Copyright (C) 2015 by Savoir-Faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#ifndef VIDEOOVERLAY_H
#define VIDEOOVERLAY_H
#include <QWidget>
#include "useractionmodel.h"
namespace Ui {
class VideoOverlay;
}
class VideoOverlay : public QWidget
{
Q_OBJECT
public:
explicit VideoOverlay(QWidget *parent = 0);
~VideoOverlay();
public:
void setName(const QString &name);
void setTime(const QString &time);
//UI SLOTS
private slots:
void on_holdButton_toggled(bool checked);
void on_hangupButton_clicked();
void on_chatButton_toggled(bool checked);
private:
Ui::VideoOverlay *ui;
UserActionModel* actionModel_;
};
#endif // VIDEOOVERLAY_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>VideoOverlay</class>
<widget class="QWidget" name="VideoOverlay">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>724</width>
<height>507</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QPushButton" name="hangupButton">
<property name="text">
<string>Hangup</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="holdButton">
<property name="text">
<string>Hold</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="chatButton">
<property name="text">
<string>Chat</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="4">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" alignment="Qt::AlignTop">
<widget class="QLabel" name="nameLabel">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>143</red>
<green>146</green>
<blue>147</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="4" alignment="Qt::AlignRight|Qt::AlignTop">
<widget class="QLabel" name="timerLabel">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>143</red>
<green>146</green>
<blue>147</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="text">
<string>00:00</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
/***************************************************************************
* Copyright (C) 2015 by Savoir-Faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "videoview.h"
#include "ui_videoview.h"
#include "callmodel.h"
#include "video/devicemodel.h"
#include "video/sourcemodel.h"
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
#include <QDesktopWidget>
#include <QMenu>
#include <memory>
#include "videooverlay.h"
#include "selectareadialog.h"
VideoView::VideoView(QWidget *parent) :
QWidget(parent),
ui(new Ui::VideoView)
{
ui->setupUi(this);
connect(CallModel::instance(), SIGNAL(callStateChanged(Call*, Call::State)),
this, SLOT(callStateChanged(Call*, Call::State)));
overlay_ = new VideoOverlay(this);
auto effect = new QGraphicsOpacityEffect(overlay_);
effect->setOpacity(1.0);
overlay_->setGraphicsEffect(effect);
fadeAnim_ = new QPropertyAnimation(this);
fadeAnim_->setTargetObject(effect);
fadeAnim_->setPropertyName("opacity");
fadeAnim_->setDuration(fadeOverlayTime_);
fadeAnim_->setStartValue(effect->opacity());
fadeAnim_->setEndValue(0);
fadeAnim_->setEasingCurve(QEasingCurve::OutQuad);
timerLength_ = new QTimer(this);
connect(timerLength_, SIGNAL(timeout()), this, SLOT(updateTimer()));
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(showContextMenu(const QPoint&)));
}
VideoView::~VideoView()
{
delete ui;
}
void
VideoView::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event)
overlay_->resize(this->size());
overlay_->show();
overlay_->raise();
}
void
VideoView::enterEvent(QEvent* event)
{
Q_UNUSED(event)
fadeAnim_->stop();
fadeAnim_->targetObject()->setProperty(fadeAnim_->propertyName(), fadeAnim_->startValue());
}
void
VideoView::leaveEvent(QEvent* event)
{
Q_UNUSED(event)
fadeAnim_->start(QAbstractAnimation::KeepWhenStopped);
}
void
VideoView::callStateChanged(Call* call, Call::State previousState)
{
Q_UNUSED(previousState)
if (call->state() == Call::State::CURRENT) {
ui->videoWidget->show();
timerLength_->start(1000);
overlay_->setName(call->formattedName());
}
else {
ui->videoWidget->hide();
if (isFullScreen())
toggleFullScreen();
timerLength_->stop();
}
}
void
VideoView::updateTimer()
{
overlay_->setTime(CallModel::instance()->selectedCall()->length());
}
void
VideoView::mouseDoubleClickEvent(QMouseEvent* e) {
QWidget::mouseDoubleClickEvent(e);
toggleFullScreen();
}
void
VideoView::toggleFullScreen()
{
if(isFullScreen()) {
this->setParent(oldParent_);
this->showNormal();
this->resize(oldSize_.width(), oldSize_.height());
} else {
oldSize_ = this->size();
oldParent_ = static_cast<QWidget*>(this->parent());
this->setParent(0);
this->showFullScreen();
this->show();
}
}
void
VideoView::showContextMenu(const QPoint& pos)
{
QPoint globalPos = this->mapToGlobal(pos);
QMenu menu;
for (auto device : Video::DeviceModel::instance()->devices()) {
std::unique_ptr<QAction> deviceAction(new QAction(device->name(), this));
deviceAction->setCheckable(true);
if (device == Video::DeviceModel::instance()->activeDevice())
deviceAction->setChecked(true);
auto ptr = deviceAction.release();
menu.addAction(ptr);