diff --git a/Linphone/model/call/CallModel.cpp b/Linphone/model/call/CallModel.cpp index ce87c1b2..58c6aeb8 100644 --- a/Linphone/model/call/CallModel.cpp +++ b/Linphone/model/call/CallModel.cpp @@ -49,6 +49,7 @@ void CallModel::accept(bool withVideo) { auto core = CoreModel::getInstance()->getCore(); auto params = core->createCallParams(mMonitor); params->enableVideo(withVideo); + mMonitor->enableCamera(withVideo); // Answer with local call address. auto localAddress = mMonitor->getCallLog()->getLocalAddress(); for (auto account : core->getAccountList()) { @@ -109,6 +110,9 @@ void CallModel::setSpeakerMuted(bool isMuted) { void CallModel::setCameraEnabled(bool enabled) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mMonitor->enableCamera(enabled); + auto core = CoreModel::getInstance()->getCore(); + auto params = core->createCallParams(mMonitor); + params->enableVideo(enabled); emit cameraEnabledChanged(enabled); } diff --git a/Linphone/view/App/CallsWindow.qml b/Linphone/view/App/CallsWindow.qml index 7c1be498..47df562d 100644 --- a/Linphone/view/App/CallsWindow.qml +++ b/Linphone/view/App/CallsWindow.qml @@ -15,15 +15,17 @@ Window { property CallGui call + Connections { + target: call.core + onRemoteVideoEnabledChanged: console.log("remote video enabled", call.core.remoteVideoEnabled) + } + onCallChanged: { waitingTime.seconds = 0 waitingTimer.restart() console.log("call changed", call, waitingTime.seconds) } - property var peerName: UtilsCpp.getDisplayName(call.core.peerAddress) - property string peerNameText: peerName ? peerName.value : "" - property var callState: call.core.state onCallStateChanged: { console.log("State:", callState) @@ -296,7 +298,6 @@ Window { } RowLayout { Control.Control { - id: centerItem Layout.fillWidth: true Layout.preferredWidth: 1059 * DefaultStyle.dp Layout.fillHeight: true @@ -309,23 +310,26 @@ Window { radius: 15 * DefaultStyle.dp } contentItem: Item { + id: centerItem anchors.fill: parent StackLayout { id: centerLayout + currentIndex: 0 anchors.fill: parent Connections { target: mainWindow onCallStateChanged: { if (mainWindow.call.core.state === LinphoneEnums.CallState.Error) { - centerLayout.currentIndex = 2 + centerLayout.currentIndex = 1 } } } - Item { - id: audioCallItem - Layout.alignment: Qt.AlignHCenter - Layout.preferredWidth: parent.width - Layout.preferredHeight: parent.height + Sticker { + visible: false + call: mainWindow.call + Layout.fillWidth: true + Layout.fillHeight: true + Timer { id: waitingTimer interval: 1000 @@ -361,44 +365,6 @@ Window { } } } - ColumnLayout { - anchors.centerIn: parent - spacing: 2 * DefaultStyle.dp - Avatar { - Layout.alignment: Qt.AlignCenter - // TODO : remove username when friend list ready - call: mainWindow.call - // address: mainWindow.peerNameText - Layout.preferredWidth: 120 * DefaultStyle.dp - Layout.preferredHeight: 120 * DefaultStyle.dp - } - Text { - Layout.alignment: Qt.AlignCenter - Layout.topMargin: 15 * DefaultStyle.dp - visible: mainWindow.peerNameText.length > 0 - text: mainWindow.peerNameText - color: DefaultStyle.grey_0 - font { - pixelSize: 22 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp - capitalization: Font.Capitalize - } - } - Text { - Layout.alignment: Qt.AlignCenter - text: mainWindow.call.core.peerAddress - color: DefaultStyle.grey_0 - font { - pixelSize: 14 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp - } - } - } - } - Image { - id: videoCallItem - Layout.preferredWidth: parent.width - Layout.preferredHeight: parent.height } ColumnLayout { id: userNotFoundLayout @@ -413,17 +379,36 @@ Window { } } } - Text { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.leftMargin: 10 * DefaultStyle.dp + Sticker { + id: preview + height: 180 * DefaultStyle.dp + width: 300 * DefaultStyle.dp + anchors.right: centerItem.right + anchors.bottom: centerItem.bottom + anchors.rightMargin: 10 * DefaultStyle.dp anchors.bottomMargin: 10 * DefaultStyle.dp - text: mainWindow.peerNameText - color: DefaultStyle.grey_0 - font { - pixelSize: 14 * DefaultStyle.dp - weight: 500 * DefaultStyle.dp + AccountProxy{ + id: accounts + } + account: accounts.defaultAccount + enablePersonalCamera: mainWindow.call.core.cameraEnabled + + MovableMouseArea{ + anchors.fill: parent + // visible: mainItem.participantCount <= 2 + function resetPosition(){ + preview.anchors.right = centerItem.right + preview.anchors.bottom = centerItem.bottom + } + onVisibleChanged: if(!visible){ + resetPosition() + } + drag.target: preview + onDraggingChanged: if(dragging){ + preview.anchors.right = undefined + preview.anchors.bottom = undefined + } + onRequestResetPosition: resetPosition() } } } @@ -552,7 +537,8 @@ Window { } Text { id: delegateName - text: UtilsCpp.getDisplayName(modelData.core.peerAddress).value + property var remoteAddress: UtilsCpp.getDisplayName(modelData.core.peerAddress) + text: remoteAddress ? remoteAddress.value : "" Connections { target: modelData.core } @@ -863,15 +849,4 @@ Window { } } } - Sticker{ - height: 100 * DefaultStyle.dp - width: 100 * DefaultStyle.dp - anchors.right: parent.right - anchors.bottom: parent.bottom - visible: mainWindow.call.core.cameraEnabled - AccountProxy{ - id: accounts - } - account: accounts.defaultAccount - } } diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index d01350af..ce6fbea4 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -30,6 +30,7 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Item/DigitInput.qml view/Item/EffectImage.qml view/Item/ErrorText.qml + view/Item/MovableMouseArea.qml view/Item/NumericPad.qml view/Item/PhoneNumberComboBox.qml view/Item/PhoneNumberInput.qml diff --git a/Linphone/view/Item/Contact/Sticker.qml b/Linphone/view/Item/Contact/Sticker.qml index 68ec1d2b..e85bf9b8 100644 --- a/Linphone/view/Item/Contact/Sticker.qml +++ b/Linphone/view/Item/Contact/Sticker.qml @@ -1,4 +1,5 @@ import QtQuick +import QtQuick.Effects import QtQuick.Layouts import QtQuick.Controls as Control import Linphone @@ -9,49 +10,118 @@ import UtilsCpp 1.0 // The loader restart in case of resetting the renderer. This allow to display the avatar while loading. // TODO: sizes, colors, decorations -Rectangle{ +Item { id: mainItem height: 300 width: 200 property CallGui call: null property AccountGui account: null - color: 'gray' - Avatar{ - anchors.centerIn: parent - height: 100 - width: height - account: mainItem.account - call: mainItem.call - visible: !cameraLoader.active || cameraLoader.status != Loader.Ready || !cameraLoader.item.isReady - } - Loader{ - id: cameraLoader + property bool enablePersonalCamera: false + onEnablePersonalCameraChanged: console.log ("enable camera", enablePersonalCamera) + property color color: DefaultStyle.grey_600 + property int radius: 15 * DefaultStyle.dp + property var peerAddress: call ? UtilsCpp.getDisplayName(call.core.peerAddress) : null + property var identityAddress: account ? UtilsCpp.getDisplayName(account.core.identityAddress) : null + + Rectangle { + id: background + color: mainItem.color + radius: mainItem.radius anchors.fill: parent - Timer{ - id: resetTimer - interval: 1 - onTriggered: {cameraLoader.active=false; cameraLoader.active=true;} - } - active: mainItem.visible && (!call || call.core.remoteVideoEnabled) - sourceComponent: cameraComponent - } - Component{ - id: cameraComponent - Item{ - height: cameraLoader.height - width: cameraLoader.width - property bool isReady: cameraItem.visible - CameraGui{ - id: cameraItem - anchors.fill: parent - visible: isReady + ColumnLayout { + anchors.centerIn: parent + visible: !cameraLoader.active || cameraLoader.status != Loader.Ready || !cameraLoader.item.isReady + Avatar{ + Layout.alignment: Qt.AlignHCenter + height: 100 + width: height + account: mainItem.account call: mainItem.call - - onRequestNewRenderer: { - console.log("Request new renderer") - resetTimer.restart() + } + Text { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: 15 * DefaultStyle.dp + visible: mainItem.call && mainItem.call != undefined + text: mainItem.peerAddress ? mainItem.peerAddress.value : "" + color: DefaultStyle.grey_0 + font { + pixelSize: 22 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + capitalization: Font.Capitalize + } + } + Text { + Layout.alignment: Qt.AlignHCenter + visible: mainItem.call && mainItem.call != undefined + text: mainItem.call && mainItem.call.core.peerAddress + color: DefaultStyle.grey_0 + font { + pixelSize: 14 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp } } } + Loader{ + id: cameraLoader + anchors.fill: parent + Timer{ + id: resetTimer + interval: 1 + onTriggered: {cameraLoader.active=false; cameraLoader.active=true;} + } + active: mainItem.visible && call ? call.core.remoteVideoEnabled : mainItem.enablePersonalCamera + onActiveChanged: console.log("camera active", active) + sourceComponent: cameraComponent + } + Component{ + id: cameraComponent + Item { + height: cameraLoader.height + width: cameraLoader.width + property bool isReady: cameraItem.visible + CameraGui{ + id: cameraItem + anchors.fill: parent + visible: isReady + call: mainItem.call + + onRequestNewRenderer: { + console.log("Request new renderer") + resetTimer.restart() + } + } + } + } + Text { + id: bottomAddress + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.leftMargin: 10 * DefaultStyle.dp + anchors.bottomMargin: 10 * DefaultStyle.dp + width: txtMeter.width + text: mainItem.call && mainItem.peerAddress + ? mainItem.peerAddress.value + : mainItem.account && mainItem.identityAddress + ? mainItem.identityAddress.value + : "" + color: DefaultStyle.grey_0 + font { + pixelSize: 14 * DefaultStyle.dp + weight: 500 * DefaultStyle.dp + } + } + TextMetrics { + id: txtMeter + text: bottomAddress.text + } + } + MultiEffect { + id: shadow + source: background + anchors.fill: background + shadowEnabled: true + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 1 + shadowOpacity: 0.4 } } diff --git a/Linphone/view/Item/MovableMouseArea.qml b/Linphone/view/Item/MovableMouseArea.qml new file mode 100644 index 00000000..d1821d1a --- /dev/null +++ b/Linphone/view/Item/MovableMouseArea.qml @@ -0,0 +1,80 @@ +import QtQuick 2.7 + +MouseArea{ + id: mainItem + property var movableArea: mainItem.Window.contentItem + + signal requestResetPosition() + + property bool dragging: drag.active + onDraggingChanged: { + if(dragging){ + xClicked = mouseX + yClicked = mouseY + } + + } +// Position buffer + property int xClicked : 0 + property int yClicked : 0 +// Scaling buffer + property int heightOrigin + property int widthOrigin + property double startTime: 0 // For acceleration computation to avoid excessive wheel scrolling + property double mScale: 1.0 // Using scale reduce quality. Apply our factor. + property bool scaled : false // Zoom state : -for storing origin state ; -for resetting scale on right click. In this case, second click lead to emit reset signal instead of first.. + + acceptedButtons: Qt.LeftButton | Qt.RightButton // Left is for Dragging. Right is for resetting. Wheel will scale. + cursorShape: dragging ? Qt.DragMoveCursor : undefined + preventStealing: true + propagateComposedEvents: true + hoverEnabled: true + + function updateScale(){// Avoid scaling if leading outside movableArea. + drag.target.height = Math.max(0, Math.min(movableArea.height, heightOrigin * mScale)) + drag.target.width = Math.max(0, Math.min(movableArea.width, widthOrigin * mScale)) + updatePosition(0,0) + } + function updatePosition(x, y){// Avoid moving outside movableArea. + var parentTLBounds = drag.target.parent.mapFromItem(movableArea, 0, 0); + var parentBRBounds = drag.target.parent.mapFromItem(movableArea, movableArea.width, movableArea.height); + drag.target.x = Math.max(parentTLBounds.x, Math.min(parentBRBounds.x - drag.target.width, drag.target.x + x)) + drag.target.y = Math.max(parentTLBounds.y, Math.min(parentBRBounds.y - drag.target.height, drag.target.y + y)) + } + onMScaleChanged: updateScale() + onPositionChanged: { + if(dragging){ + updatePosition(mouse.x - xClicked, mouse.y - yClicked) + } + mouse.accepted = false + } + onWheel: { + if(!scaled){ + scaled = true + heightOrigin = drag.target.height + widthOrigin = drag.target.width + } + var acceleration = 0.01; // Try to make smoother the scaling from wheel + if(startTime == 0){ + startTime = new Date().getTime(); + }else{ + var delay = new Date().getTime() - startTime; + if(delay > 0) + acceleration = Math.max(0.01, Math.min(1, 4/delay)); + else + acceleration = 1 + } + mScale = Math.max(0.5 , mScale * ( 1 + acceleration*(wheel.angleDelta.y >0 ? 1 : -1) )); + startTime = new Date().getTime(); + } + onClicked: { + if(mouse.button == Qt.RightButton){ + if(scaled) { + scaled = false + mScale = 1.0 + }else + requestResetPosition() + } + mouse.accepted = false + } +}