From 370c4481ef70bf1aa90ab925ae1eb16d4aa985be Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 3 Feb 2017 17:35:54 +0100 Subject: [PATCH] feat(ui/views/App/Calls/Incall): add fullscreen support --- linphone-desktop/resources.qrc | 1 + .../src/components/camera/Camera.cpp | 36 +-- .../src/components/camera/Camera.hpp | 1 + linphone-desktop/ui/scripts/Utils/utils.js | 8 +- .../ui/views/App/Calls/Incall.qml | 33 ++- .../ui/views/App/IncallFullscreen.qml | 223 ++++++++++++++++++ .../ui/views/App/Styles/Calls/CallStyle.qml | 2 +- linphone-desktop/ui/views/App/qmldir | 1 + 8 files changed, 277 insertions(+), 28 deletions(-) create mode 100644 linphone-desktop/ui/views/App/IncallFullscreen.qml diff --git a/linphone-desktop/resources.qrc b/linphone-desktop/resources.qrc index 4da6187d2..d5ca3f940 100644 --- a/linphone-desktop/resources.qrc +++ b/linphone-desktop/resources.qrc @@ -259,6 +259,7 @@ ui/views/App/Calls/Incall.qml ui/views/App/Calls/IncomingCall.qml ui/views/App/Calls/OutgoingCall.qml + ui/views/App/IncallFullscreen.qml ui/views/App/MainWindow/ContactEdit.qml ui/views/App/MainWindow/Contacts.qml ui/views/App/MainWindow/Conversation.qml diff --git a/linphone-desktop/src/components/camera/Camera.cpp b/linphone-desktop/src/components/camera/Camera.cpp index 90ce8e9d6..0f44ed7fc 100644 --- a/linphone-desktop/src/components/camera/Camera.cpp +++ b/linphone-desktop/src/components/camera/Camera.cpp @@ -62,6 +62,20 @@ struct ContextInfo { // ----------------------------------------------------------------------------- +inline void setWindowId (const Camera &camera) { + ContextInfo *context_info = camera.m_context_info; + + qInfo() << QStringLiteral("Set context info (width: %1, height: %2, is_preview: %3).") + .arg(context_info->width).arg(context_info->height).arg(camera.m_is_preview); + + if (camera.m_is_preview) + CoreManager::getInstance()->getCore()->setNativePreviewWindowId(context_info); + else + camera.m_call->getLinphoneCall()->setNativeVideoWindowId(context_info); +} + +// ----------------------------------------------------------------------------- + CameraRenderer::CameraRenderer (const Camera *camera) : m_camera(camera) {} QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize &size) { @@ -74,10 +88,7 @@ QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize & context_info->width = size.width(); context_info->height = size.height(); - if (m_camera->m_is_preview) - CoreManager::getInstance()->getCore()->setNativePreviewWindowId(context_info); - else - m_camera->m_call->getLinphoneCall()->setNativeVideoWindowId(context_info); + setWindowId(*m_camera); return new QOpenGLFramebufferObject(size, format); } @@ -148,20 +159,9 @@ CallModel *Camera::getCall () const { void Camera::setCall (CallModel *call) { if (m_call != call) { - if (call) { - shared_ptr linphone_call = call->getLinphoneCall(); - linphone::CallState state = linphone_call->getState(); + if ((m_call = call)) + setWindowId(*this); - if (state == linphone::CallStateConnected || state == linphone::CallStateStreamsRunning) { - if (m_is_preview) - CoreManager::getInstance()->getCore()->setNativePreviewWindowId(m_context_info); - else - linphone_call->setNativeVideoWindowId(m_context_info); - } - } - - m_call = call; - - emit callChanged(call); + emit callChanged(m_call); } } diff --git a/linphone-desktop/src/components/camera/Camera.hpp b/linphone-desktop/src/components/camera/Camera.hpp index 19e1dc00a..ff43ddd7f 100644 --- a/linphone-desktop/src/components/camera/Camera.hpp +++ b/linphone-desktop/src/components/camera/Camera.hpp @@ -53,6 +53,7 @@ private: class Camera : public QQuickFramebufferObject { friend class CameraRenderer; + friend void setWindowId (const Camera &camera); Q_OBJECT; diff --git a/linphone-desktop/ui/scripts/Utils/utils.js b/linphone-desktop/ui/scripts/Utils/utils.js index 6c7c7d3dd..ee3f197a7 100644 --- a/linphone-desktop/ui/scripts/Utils/utils.js +++ b/linphone-desktop/ui/scripts/Utils/utils.js @@ -4,6 +4,8 @@ .pragma library +.import QtQuick 2.0 as QtQuick + .import 'uri-tools.js' as UriTools // ============================================================================= @@ -136,15 +138,15 @@ function openWindow (window, parent, options) { 'qrc:/ui/views/App/' + window + '.qml' ) - if (component.status !== Component.Ready) { + if (component.status !== QtQuick.Component.Ready) { console.debug('Window not ready.') - if (component.status === Component.Error) { + if (component.status === QtQuick.Component.Error) { console.debug('Error:' + component.errorString()) } return // Error. } - object = component.createObject(parent) + object = component.createObject(parent, options ? options.properties : {}) } object.closing.connect(object.destroy.bind(object)) diff --git a/linphone-desktop/ui/views/App/Calls/Incall.qml b/linphone-desktop/ui/views/App/Calls/Incall.qml index 2804cf1f2..e12159caf 100644 --- a/linphone-desktop/ui/views/App/Calls/Incall.qml +++ b/linphone-desktop/ui/views/App/Calls/Incall.qml @@ -1,5 +1,4 @@ import QtQuick 2.7 -import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.3 import Common 1.0 @@ -20,6 +19,21 @@ Rectangle { property var call property var _contactObserver: SipAddressesModel.getContactObserver(sipAddress) + property var _fullscreen: null + + // --------------------------------------------------------------------------- + + function _showFullscreen () { + if (_fullscreen) { + return + } + + _fullscreen = Utils.openWindow('IncallFullscreen', incall, { + properties: { + call: incall.call + } + }) + } // --------------------------------------------------------------------------- @@ -96,6 +110,7 @@ Rectangle { anchors.left: parent.left icon: 'call_quality_0' iconSize: CallStyle.header.iconSize + visible: call.status !== CallModel.CallStatusEnded // See: http://www.linphone.org/docs/liblinphone/group__call__misc.html#ga62c7d3d08531b0cc634b797e273a0a73 Timer { @@ -158,6 +173,8 @@ Rectangle { ActionButton { icon: 'fullscreen' visible: call.videoEnabled + + onClicked: _showFullscreen() } } } @@ -246,7 +263,7 @@ Rectangle { Loader { anchors.centerIn: parent - sourceComponent: call.videoEnabled ? camera : avatar + sourceComponent: call.videoEnabled && !_fullscreen ? camera : avatar } } @@ -295,15 +312,19 @@ Rectangle { } } - Camera { + Loader { anchors.centerIn: parent height: CallStyle.actionArea.userVideo.height width: CallStyle.actionArea.userVideo.width - isPreview: true - visible: incall.width >= CallStyle.actionArea.lowWidth && call.videoEnabled + visible: incall.width >= CallStyle.actionArea.lowWidth && call.videoEnabled && !_fullscreen - Component.onCompleted: call = incall.call + Camera { + anchors.fill: parent + isPreview: true + + Component.onCompleted: call = incall.call + } } ActionBar { diff --git a/linphone-desktop/ui/views/App/IncallFullscreen.qml b/linphone-desktop/ui/views/App/IncallFullscreen.qml new file mode 100644 index 000000000..9e196a0f6 --- /dev/null +++ b/linphone-desktop/ui/views/App/IncallFullscreen.qml @@ -0,0 +1,223 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.3 +import QtQuick.Window 2.2 + +import Common 1.0 +import Common.Styles 1.0 +import Linphone 1.0 +import Utils 1.0 + +import App.Styles 1.0 + +// ============================================================================= + +Window { + id: incall + + // --------------------------------------------------------------------------- + + property var call + + // --------------------------------------------------------------------------- + + function _exit (cb) { + incall.close() + + if (cb) { + cb() + } + } + + // --------------------------------------------------------------------------- + + visible: true + visibility: Window.FullScreen + + onActiveChanged: incall.showFullScreen() + + // --------------------------------------------------------------------------- + + Rectangle { + anchors.fill: parent + color: '#000000' // Not a style. + } + + Camera { + id: camera + + anchors.fill: parent + call: incall.call + } + + ColumnLayout { + anchors { + fill: parent + topMargin: CallStyle.header.topMargin + } + + spacing: 0 + + // ------------------------------------------------------------------------- + // Call info. + // ------------------------------------------------------------------------- + + Item { + id: info + + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + Layout.leftMargin: CallStyle.header.leftMargin + Layout.rightMargin: CallStyle.header.rightMargin + Layout.preferredHeight: CallStyle.header.contactDescription.height + + Icon { + id: callQuality + + anchors.left: parent.left + icon: 'call_quality_0' + iconSize: CallStyle.header.iconSize + + // See: http://www.linphone.org/docs/liblinphone/group__call__misc.html#ga62c7d3d08531b0cc634b797e273a0a73 + Timer { + interval: 5000 + repeat: true + running: true + triggeredOnStart: true + + onTriggered: { + var quality = call.quality + callQuality.icon = 'call_quality_' + ( + // Note: `quality` is in the [0, 5] interval. + // It's necessary to map in the `call_quality_` interval. ([0, 3]) + quality >= 0 ? Math.round(quality / (5 / 3)) : 0 + ) + } + } + } + + // ----------------------------------------------------------------------- + // Video actions. + // ----------------------------------------------------------------------- + + ActionBar { + anchors.right: parent.right + iconSize: CallStyle.header.iconSize + + ActionButton { + icon: 'screenshot' + + onClicked: call.takeSnapshot() + } + + ActionSwitch { + enabled: call.recording + icon: 'record' + useStates: false + + onClicked: !enabled ? call.startRecording() : call.stopRecording() + } + + ActionButton { + icon: 'fullscreen' + + onClicked: _exit() + } + } + } + + Text { + id: elapsedTime + + Layout.fillWidth: true + color: CallStyle.header.elapsedTime.color + font.pointSize: CallStyle.header.elapsedTime.fontSize + horizontalAlignment: Text.AlignHCenter + + Component.onCompleted: { + var updateDuration = function () { + text = Utils.formatElapsedTime(call.duration) + Utils.setTimeout(elapsedTime, 1000, updateDuration) + } + + updateDuration() + } + } + + // ------------------------------------------------------------------------- + // Action Buttons. + // ------------------------------------------------------------------------- + + Item { + Layout.alignment: Qt.AlignBottom + Layout.fillWidth: true + Layout.preferredHeight: CallStyle.actionArea.height + + GridLayout { + anchors { + left: parent.left + leftMargin: CallStyle.actionArea.leftButtonsGroupMargin + verticalCenter: parent.verticalCenter + } + + rowSpacing: ActionBarStyle.spacing + + ActionSwitch { + enabled: !call.microMuted + icon: 'micro' + iconSize: CallStyle.actionArea.iconSize + + onClicked: call.microMuted = enabled + } + + ActionSwitch { + enabled: true + icon: 'camera' + iconSize: CallStyle.actionArea.iconSize + updating: call.updating + + onClicked: _exit(function () { call.videoEnabled = false }) + } + + ActionButton { + Layout.preferredHeight: CallStyle.actionArea.iconSize + Layout.preferredWidth: CallStyle.actionArea.iconSize + icon: 'options' // TODO: display options. + iconSize: CallStyle.actionArea.iconSize + } + } + + Camera { + anchors.centerIn: parent + height: CallStyle.actionArea.userVideo.height + width: CallStyle.actionArea.userVideo.width + + isPreview: true + + call: incall.call + } + + ActionBar { + anchors { + right: parent.right + rightMargin: CallStyle.actionArea.rightButtonsGroupMargin + verticalCenter: parent.verticalCenter + } + iconSize: CallStyle.actionArea.iconSize + + ActionSwitch { + enabled: !call.pausedByUser + icon: 'pause' + updating: call.updating + + onClicked: _exit(function () { call.pausedByUser = enabled }) + } + + ActionButton { + icon: 'hangup' + + onClicked: _exit(call.terminate) + } + } + } + } +} diff --git a/linphone-desktop/ui/views/App/Styles/Calls/CallStyle.qml b/linphone-desktop/ui/views/App/Styles/Calls/CallStyle.qml index 6bce6fbd4..f05e6bc66 100644 --- a/linphone-desktop/ui/views/App/Styles/Calls/CallStyle.qml +++ b/linphone-desktop/ui/views/App/Styles/Calls/CallStyle.qml @@ -12,7 +12,7 @@ QtObject { property int height: 100 property int iconSize: 40 property int leftButtonsGroupMargin: 50 - property int lowWidth: 415 + property int lowWidth: 515 property int rightButtonsGroupMargin: 50 property QtObject userVideo: QtObject { diff --git a/linphone-desktop/ui/views/App/qmldir b/linphone-desktop/ui/views/App/qmldir index 3f7cdbfdf..11184ec73 100644 --- a/linphone-desktop/ui/views/App/qmldir +++ b/linphone-desktop/ui/views/App/qmldir @@ -6,4 +6,5 @@ module App # Views ------------------------------------------------------------------------ +IncallFullscreen 1.0 IncallFullscreen.qml ManageAccounts 1.0 ManageAccounts.qml