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