mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-20 21:28:07 +00:00
feat(ui/views/App/Calls/Incall): add fullscreen support
This commit is contained in:
parent
59ed757f4b
commit
370c4481ef
8 changed files with 277 additions and 28 deletions
|
|
@ -259,6 +259,7 @@
|
|||
<file>ui/views/App/Calls/Incall.qml</file>
|
||||
<file>ui/views/App/Calls/IncomingCall.qml</file>
|
||||
<file>ui/views/App/Calls/OutgoingCall.qml</file>
|
||||
<file>ui/views/App/IncallFullscreen.qml</file>
|
||||
<file>ui/views/App/MainWindow/ContactEdit.qml</file>
|
||||
<file>ui/views/App/MainWindow/Contacts.qml</file>
|
||||
<file>ui/views/App/MainWindow/Conversation.qml</file>
|
||||
|
|
|
|||
|
|
@ -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> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ private:
|
|||
|
||||
class Camera : public QQuickFramebufferObject {
|
||||
friend class CameraRenderer;
|
||||
friend void setWindowId (const Camera &camera);
|
||||
|
||||
Q_OBJECT;
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
223
linphone-desktop/ui/views/App/IncallFullscreen.qml
Normal file
223
linphone-desktop/ui/views/App/IncallFullscreen.qml
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -6,4 +6,5 @@ module App
|
|||
|
||||
# Views ------------------------------------------------------------------------
|
||||
|
||||
IncallFullscreen 1.0 IncallFullscreen.qml
|
||||
ManageAccounts 1.0 ManageAccounts.qml
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue