From a85823b68a75ff0d44d346c05fe20bc7c7977bb5 Mon Sep 17 00:00:00 2001 From: trilene Date: Tue, 12 Jan 2021 14:22:52 -0500 Subject: [PATCH 1/3] Add call invite screen for mobile --- resources/qml/TimelineView.qml | 18 +++ resources/qml/voip/CallInvite.qml | 173 +++++++++++++++++++++++++++ resources/qml/voip/CallInviteBar.qml | 2 +- resources/res.qrc | 1 + 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 resources/qml/voip/CallInvite.qml diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index e596d8e2..fd08f0ca 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -52,6 +52,13 @@ Page { } + Component { + id: mobileCallInviteDialog + + CallInvite { + } + } + Menu { id: messageContextMenu @@ -151,6 +158,16 @@ Page { } } + Connections { + target: CallManager + onNewInviteState: { + if (CallManager.haveCallInvite && Settings.mobileMode) { + var dialog = mobileCallInviteDialog.createObject(msgView); + dialog.open(); + } + } + } + Label { visible: !TimelineManager.timeline && !TimelineManager.isInitialSync anchors.centerIn: parent @@ -184,6 +201,7 @@ Page { } Rectangle { + id: msgView Layout.fillWidth: true Layout.fillHeight: true color: colors.base diff --git a/resources/qml/voip/CallInvite.qml b/resources/qml/voip/CallInvite.qml new file mode 100644 index 00000000..6931b3c9 --- /dev/null +++ b/resources/qml/voip/CallInvite.qml @@ -0,0 +1,173 @@ +import "../" +import QtQuick 2.9 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.2 +import im.nheko 1.0 + +Popup { + closePolicy: Popup.NoAutoClose + width: parent.width + height: parent.height + palette: colors + background: Rectangle { + color: colors.window + border.color: colors.windowText + } + + Component { + id: deviceError + DeviceError { + } + } + + Connections { + target: CallManager + onNewInviteState: { + if (!CallManager.haveCallInvite) { + close(); + } + } + } + + ColumnLayout { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + + spacing: 48 + + Item { + Layout.fillHeight: true + } + + Label { + Layout.alignment: Qt.AlignCenter + text: CallManager.callParty + font.pointSize: fontMetrics.font.pointSize * 2 + color: colors.windowText + } + + Avatar { + Layout.alignment: Qt.AlignCenter + width: avatarSize * 4 + height: avatarSize * 4 + url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/") + displayName: CallManager.callParty + } + + ColumnLayout { + Layout.alignment: Qt.AlignCenter + + Image { + Layout.alignment: Qt.AlignCenter + Layout.preferredWidth: avatarSize + Layout.preferredHeight: avatarSize + property string image: CallManager.isVideo ? ":/icons/icons/ui/video-call.png" : ":/icons/icons/ui/place-call.png" + source: "image://colorimage/" + image + "?" + colors.windowText + } + + Label { + Layout.alignment: Qt.AlignCenter + text: CallManager.isVideo ? qsTr("Video Call") : qsTr("Voice Call") + font.pointSize: fontMetrics.font.pointSize * 2 + color: colors.windowText + } + } + + ColumnLayout { + id: deviceCombos + Layout.alignment: Qt.AlignCenter + property int imageSize: 32 + + RowLayout { + + Layout.alignment: Qt.AlignCenter + + Image { + Layout.preferredWidth: deviceCombos.imageSize + Layout.preferredHeight: deviceCombos.imageSize + source: "image://colorimage/:/icons/icons/ui/microphone-unmute.png?" + colors.windowText + } + + ComboBox { + id: micCombo + Layout.fillWidth: true + model: CallManager.mics + } + } + + RowLayout { + + visible: CallManager.isVideo && CallManager.cameras.length > 0 + Layout.alignment: Qt.AlignCenter + + Image { + Layout.preferredWidth: deviceCombos.imageSize + Layout.preferredHeight: deviceCombos.imageSize + source: "image://colorimage/:/icons/icons/ui/video-call.png?" + colors.windowText + } + + ComboBox { + id: cameraCombo + Layout.fillWidth: true + model: CallManager.cameras + } + } + } + + RowLayout { + id: buttonLayout + + property int iconSize: 64 + Layout.alignment: Qt.AlignCenter + spacing: 160 + + function validateMic() { + if (CallManager.mics.length == 0) { + var dialog = deviceError.createObject(timelineRoot, { + "errorString": qsTr("No microphone found."), + "image": ":/icons/icons/ui/place-call.png" + }); + dialog.open(); + return false; + } + return true; + } + + RoundButton { + icon.source: "qrc:/icons/icons/ui/end-call.png" + icon.width: buttonLayout.iconSize + icon.height: buttonLayout.iconSize + icon.color: "#ffffff" + palette.button: "#ff0000" + + onClicked: { + CallManager.hangUp(); + close(); + } + } + + RoundButton { + icon.source: CallManager.isVideo ? "qrc:/icons/icons/ui/video-call.png" : "qrc:/icons/icons/ui/place-call.png" + icon.width: buttonLayout.iconSize + icon.height: buttonLayout.iconSize + icon.color: "#ffffff" + palette.button: "#00ff00" + + onClicked: { + if (buttonLayout.validateMic()) { + Settings.microphone = micCombo.currentText; + if (cameraCombo.visible) + Settings.camera = cameraCombo.currentText; + CallManager.acceptInvite(); + close(); + } + } + } + } + + Item { + Layout.fillHeight: true + } + } +} diff --git a/resources/qml/voip/CallInviteBar.qml b/resources/qml/voip/CallInviteBar.qml index 5c4b8f32..cc3f9005 100644 --- a/resources/qml/voip/CallInviteBar.qml +++ b/resources/qml/voip/CallInviteBar.qml @@ -5,7 +5,7 @@ import QtQuick.Layouts 1.2 import im.nheko 1.0 Rectangle { - visible: CallManager.haveCallInvite + visible: CallManager.haveCallInvite && !Settings.mobileMode color: "#2ECC71" implicitHeight: visible ? rowLayout.height + 8 : 0 diff --git a/resources/res.qrc b/resources/res.qrc index 71e8b997..e3998bd1 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -160,6 +160,7 @@ qml/ui/Ripple.qml qml/voip/ActiveCallBar.qml qml/voip/CallDevices.qml + qml/voip/CallInvite.qml qml/voip/CallInviteBar.qml qml/voip/DeviceError.qml qml/voip/PlaceCall.qml From ebe61701d9fee4cb21788391b4106a9efc302323 Mon Sep 17 00:00:00 2001 From: trilene Date: Tue, 12 Jan 2021 15:16:59 -0500 Subject: [PATCH 2/3] Fix spurious call invite timeout --- src/CallManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CallManager.cpp b/src/CallManager.cpp index f725d49f..0841a079 100644 --- a/src/CallManager.cpp +++ b/src/CallManager.cpp @@ -45,8 +45,9 @@ CallManager::CallManager(QObject *parent) nhlog::ui()->debug("WebRTC: call id: {} - sending offer", callid_); emit newMessage(roomid_, CallInvite{callid_, sdp, 0, timeoutms_}); emit newMessage(roomid_, CallCandidates{callid_, candidates, 0}); - QTimer::singleShot(timeoutms_, this, [this]() { - if (session_.state() == webrtc::State::OFFERSENT) { + std::string callid(callid_); + QTimer::singleShot(timeoutms_, this, [this, callid]() { + if (session_.state() == webrtc::State::OFFERSENT && callid == callid_) { hangUp(CallHangUp::Reason::InviteTimeOut); emit ChatPage::instance()->showNotification( "The remote side failed to pick up."); From dfe2f7dc57b072867e3e19661533486b2d08a57c Mon Sep 17 00:00:00 2001 From: trilene Date: Wed, 13 Jan 2021 16:00:41 -0500 Subject: [PATCH 3/3] Finesse mobile call invite screen --- resources/qml/voip/CallInvite.qml | 65 ++++++++++++++++++------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/resources/qml/voip/CallInvite.qml b/resources/qml/voip/CallInvite.qml index 6931b3c9..1e9a31c2 100644 --- a/resources/qml/voip/CallInvite.qml +++ b/resources/qml/voip/CallInvite.qml @@ -34,14 +34,9 @@ Popup { anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter - spacing: 48 - - Item { - Layout.fillHeight: true - } - Label { Layout.alignment: Qt.AlignCenter + Layout.topMargin: msgView.height / 25 text: CallManager.callParty font.pointSize: fontMetrics.font.pointSize * 2 color: colors.windowText @@ -49,20 +44,21 @@ Popup { Avatar { Layout.alignment: Qt.AlignCenter - width: avatarSize * 4 - height: avatarSize * 4 + width: msgView.height / 5 + height: msgView.height / 5 url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/") displayName: CallManager.callParty } ColumnLayout { Layout.alignment: Qt.AlignCenter + Layout.bottomMargin: msgView.height / 25 Image { - Layout.alignment: Qt.AlignCenter - Layout.preferredWidth: avatarSize - Layout.preferredHeight: avatarSize property string image: CallManager.isVideo ? ":/icons/icons/ui/video-call.png" : ":/icons/icons/ui/place-call.png" + Layout.alignment: Qt.AlignCenter + Layout.preferredWidth: msgView.height / 10 + Layout.preferredHeight: msgView.height / 10 source: "image://colorimage/" + image + "?" + colors.windowText } @@ -76,8 +72,10 @@ Popup { ColumnLayout { id: deviceCombos + + property int imageSize: msgView.height / 20 Layout.alignment: Qt.AlignCenter - property int imageSize: 32 + Layout.bottomMargin: msgView.height / 25 RowLayout { @@ -118,9 +116,9 @@ Popup { RowLayout { id: buttonLayout - property int iconSize: 64 + property int buttonSize: msgView.height / 8 Layout.alignment: Qt.AlignCenter - spacing: 160 + spacing: msgView.height / 6 function validateMic() { if (CallManager.mics.length == 0) { @@ -135,11 +133,17 @@ Popup { } RoundButton { - icon.source: "qrc:/icons/icons/ui/end-call.png" - icon.width: buttonLayout.iconSize - icon.height: buttonLayout.iconSize - icon.color: "#ffffff" - palette.button: "#ff0000" + implicitWidth: buttonLayout.buttonSize + implicitHeight: buttonLayout.buttonSize + + background: Rectangle { + radius: buttonLayout.buttonSize / 2 + color: "#ff0000" + } + + contentItem : Image { + source: "image://colorimage/:/icons/icons/ui/end-call.png?#ffffff" + } onClicked: { CallManager.hangUp(); @@ -148,11 +152,20 @@ Popup { } RoundButton { - icon.source: CallManager.isVideo ? "qrc:/icons/icons/ui/video-call.png" : "qrc:/icons/icons/ui/place-call.png" - icon.width: buttonLayout.iconSize - icon.height: buttonLayout.iconSize - icon.color: "#ffffff" - palette.button: "#00ff00" + id: acceptButton + + property string image: CallManager.isVideo ? ":/icons/icons/ui/video-call.png" : ":/icons/icons/ui/place-call.png" + implicitWidth: buttonLayout.buttonSize + implicitHeight: buttonLayout.buttonSize + + background: Rectangle { + radius: buttonLayout.buttonSize / 2 + color: "#00ff00" + } + + contentItem : Image { + source: "image://colorimage/" + acceptButton.image + "?#ffffff" + } onClicked: { if (buttonLayout.validateMic()) { @@ -165,9 +178,5 @@ Popup { } } } - - Item { - Layout.fillHeight: true - } } }