mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-25 07:38:11 +00:00
437 lines
11 KiB
QML
437 lines
11 KiB
QML
import QtQuick 2.7
|
|
import QtQuick.Layouts 1.3
|
|
import QtQuick.Window 2.2
|
|
|
|
import Common 1.0
|
|
import Common.Styles 1.0
|
|
import DesktopTools 1.0
|
|
import Linphone 1.0
|
|
import Utils 1.0
|
|
|
|
import App.Styles 1.0
|
|
|
|
import 'Incall.js' as Logic
|
|
|
|
// =============================================================================
|
|
|
|
Window {
|
|
id: window
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
property var call
|
|
property var caller
|
|
property bool hideButtons: false
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function exit (cb) {
|
|
DesktopTools.screenSaverStatus = true
|
|
|
|
// `exit` is called by `Incall.qml`.
|
|
// The `window` id can be null if the window was closed in this view.
|
|
if (!window) {
|
|
return
|
|
}
|
|
|
|
// It's necessary to call `showNormal` before close on MacOs
|
|
// because the dock will be hidden forever!
|
|
window.visible = false
|
|
window.showNormal()
|
|
window.close()
|
|
|
|
if (cb) {
|
|
cb()
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Component.onCompleted: {
|
|
window.call = caller.call
|
|
var show = function (visibility) {
|
|
if (visibility === Window.Windowed) {
|
|
window.visibilityChanged.disconnect(show)
|
|
window.showFullScreen()
|
|
}
|
|
}
|
|
|
|
window.visibilityChanged.connect(show)
|
|
}
|
|
|
|
visible: false
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Close
|
|
onActivated: window.exit()
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: '#000000' // Not a style.
|
|
focus: true
|
|
|
|
Keys.onEscapePressed: window.exit()
|
|
|
|
Loader {
|
|
anchors.fill: parent
|
|
|
|
active: {
|
|
var caller = window.caller
|
|
return caller && !caller.cameraActivated
|
|
}
|
|
|
|
sourceComponent: camera
|
|
|
|
Component {
|
|
id: camera
|
|
|
|
Camera {
|
|
call: window.call
|
|
}
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Handle mouse move / Hide buttons.
|
|
// -------------------------------------------------------------------------
|
|
|
|
MouseArea {
|
|
Timer {
|
|
id: hideButtonsTimer
|
|
|
|
interval: 5000
|
|
running: true
|
|
|
|
onTriggered: hideButtons = true
|
|
}
|
|
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.NoButton
|
|
hoverEnabled: true
|
|
propagateComposedEvents: true
|
|
|
|
onEntered: hideButtonsTimer.start()
|
|
onExited: hideButtonsTimer.stop()
|
|
|
|
onPositionChanged: {
|
|
hideButtonsTimer.stop()
|
|
hideButtons = false
|
|
hideButtonsTimer.start()
|
|
}
|
|
}
|
|
|
|
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.preferredHeight: CallStyle.header.contactDescription.height
|
|
Layout.rightMargin: CallStyle.header.rightMargin
|
|
|
|
ActionBar {
|
|
anchors.left: parent.left
|
|
iconSize: CallStyle.header.iconSize
|
|
visible: !hideButtons
|
|
|
|
Icon {
|
|
id: callQuality
|
|
|
|
icon: 'call_quality_0'
|
|
iconSize: parent.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
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
ActionButton {
|
|
icon: 'tel_keypad'
|
|
|
|
onClicked: telKeypad.visible = !telKeypad.visible
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Timer.
|
|
// ---------------------------------------------------------------------
|
|
|
|
Text {
|
|
id: elapsedTime
|
|
|
|
anchors.fill: parent
|
|
|
|
font.pointSize: CallStyle.header.elapsedTime.fullscreen.pointSize
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
visible: !window.hideButtons
|
|
|
|
// Not a customizable style.
|
|
color: 'white'
|
|
style: Text.Raised
|
|
styleColor: 'black'
|
|
|
|
Component.onCompleted: {
|
|
var updateDuration = function () {
|
|
var call = window.caller.call
|
|
text = Utils.formatElapsedTime(call.duration)
|
|
Utils.setTimeout(elapsedTime, 1000, updateDuration)
|
|
}
|
|
|
|
updateDuration()
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Video actions.
|
|
// ---------------------------------------------------------------------
|
|
|
|
ActionBar {
|
|
anchors.right: parent.right
|
|
iconSize: CallStyle.header.buttonIconSize
|
|
visible: !hideButtons
|
|
|
|
ActionButton {
|
|
icon: 'screenshot'
|
|
|
|
onClicked: call.takeSnapshot()
|
|
|
|
TooltipArea {
|
|
text: qsTr('takeSnapshotLabel')
|
|
}
|
|
}
|
|
|
|
ActionSwitch {
|
|
id: recordingSwitch
|
|
|
|
enabled: call.recording
|
|
icon: 'record'
|
|
useStates: false
|
|
visible: SettingsModel.callRecorderEnabled
|
|
|
|
onClicked: !enabled
|
|
? call.startRecording()
|
|
: call.stopRecording()
|
|
|
|
TooltipArea {
|
|
text: !recordingSwitch.enabled
|
|
? qsTr('startRecordingLabel')
|
|
: qsTr('stopRecordingLabel')
|
|
}
|
|
}
|
|
|
|
ActionButton {
|
|
icon: 'fullscreen'
|
|
|
|
onClicked: window.exit()
|
|
}
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Action Buttons.
|
|
// -----------------------------------------------------------------------
|
|
|
|
Item {
|
|
Layout.alignment: Qt.AlignBottom
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: CallStyle.actionArea.height
|
|
visible: !hideButtons
|
|
|
|
GridLayout {
|
|
anchors {
|
|
left: parent.left
|
|
leftMargin: CallStyle.actionArea.leftButtonsGroupMargin
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
rowSpacing: ActionBarStyle.spacing
|
|
|
|
Row {
|
|
spacing: CallStyle.actionArea.vu.spacing
|
|
visible: SettingsModel.muteMicrophoneEnabled
|
|
|
|
VuMeter {
|
|
Timer {
|
|
interval: 50
|
|
repeat: true
|
|
running: micro.enabled
|
|
|
|
onTriggered: parent.value = call.microVu
|
|
}
|
|
|
|
enabled: micro.enabled
|
|
}
|
|
|
|
ActionSwitch {
|
|
id: micro
|
|
|
|
enabled: !call.microMuted
|
|
icon: 'micro'
|
|
iconSize: CallStyle.actionArea.iconSize
|
|
|
|
onClicked: call.microMuted = enabled
|
|
}
|
|
}
|
|
|
|
Row {
|
|
spacing: CallStyle.actionArea.vu.spacing
|
|
|
|
VuMeter {
|
|
Timer {
|
|
interval: 50
|
|
repeat: true
|
|
running: speaker.enabled
|
|
|
|
onTriggered: parent.value = call.speakerVu
|
|
}
|
|
|
|
enabled: speaker.enabled
|
|
}
|
|
|
|
ActionSwitch {
|
|
id: speaker
|
|
|
|
enabled: true
|
|
icon: 'speaker'
|
|
iconSize: CallStyle.actionArea.iconSize
|
|
|
|
onClicked: console.log('TODO')
|
|
}
|
|
}
|
|
|
|
ActionSwitch {
|
|
enabled: true
|
|
icon: 'camera'
|
|
iconSize: CallStyle.actionArea.iconSize
|
|
updating: call.updating
|
|
|
|
onClicked: window.exit(function () { call.videoEnabled = false })
|
|
}
|
|
|
|
ActionButton {
|
|
Layout.preferredHeight: CallStyle.actionArea.iconSize
|
|
Layout.preferredWidth: CallStyle.actionArea.iconSize
|
|
|
|
icon: 'options'
|
|
iconSize: CallStyle.actionArea.iconSize
|
|
|
|
onClicked: Logic.openMediaParameters()
|
|
}
|
|
}
|
|
|
|
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
|
|
visible: SettingsModel.callPauseEnabled
|
|
|
|
onClicked: window.exit(function () { call.pausedByUser = enabled })
|
|
}
|
|
|
|
ActionButton {
|
|
icon: 'hangup'
|
|
|
|
onClicked: window.exit(call.terminate)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Preview.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Loader {
|
|
active: {
|
|
var caller = window.caller
|
|
return caller && !caller.cameraActivated
|
|
}
|
|
|
|
sourceComponent: cameraPreview
|
|
|
|
Component {
|
|
id: cameraPreview
|
|
|
|
Camera {
|
|
property bool scale: false
|
|
|
|
function xPosition () {
|
|
return window.width / 2 - width / 2
|
|
}
|
|
|
|
function yPosition () {
|
|
return window.height - height
|
|
}
|
|
|
|
call: window.call
|
|
isPreview: true
|
|
|
|
height: CallStyle.actionArea.userVideo.height * (scale ? 2 : 1)
|
|
width: CallStyle.actionArea.userVideo.width * (scale ? 2 : 1)
|
|
|
|
DragBox {
|
|
container: window
|
|
draggable: parent
|
|
|
|
xPosition: parent.xPosition
|
|
yPosition: parent.yPosition
|
|
|
|
onWheel: parent.scale = wheel.angleDelta.y > 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TelKeypad.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
TelKeypad {
|
|
id: telKeypad
|
|
|
|
call: window.call
|
|
visible: false
|
|
}
|
|
}
|