linphone-desktop/Linphone/view/Page/Window/Call/CallsWindow.qml
2024-09-26 11:05:24 +02:00

1687 lines
57 KiB
QML

import QtQuick 2.15
import QtQuick.Layouts
import QtQuick.Effects
import QtQuick.Controls as Control
import Linphone
import EnumsToStringCpp 1.0
import UtilsCpp 1.0
import SettingsCpp 1.0
import DesktopToolsCpp 1.0
import LinphoneCallsCpp
AbstractWindow {
id: mainWindow
flags: Qt.Window
// modality: Qt.WindowModal
property CallGui call
property ConferenceGui conference: call && call.core.conference || null
property int conferenceLayout: call && call.core.conferenceVideoLayout || 0
property bool callTerminatedByUser: false
property var callState: call ? call.core.state : LinphoneEnums.CallState.Idle
property var transferState: call && call.core.transferState
onCallStateChanged: {
if (callState === LinphoneEnums.CallState.Connected) {
if (middleItemStackView.currentItem.objectName != "inCallItem") {
middleItemStackView.replace(inCallItem)
bottomButtonsLayout.visible = true
}
if(call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp && (!call.core.tokenVerified || call.core.isMismatch)) {
zrtpValidation.open()
}
}
else if (callState === LinphoneEnums.CallState.Error || callState === LinphoneEnums.CallState.End) {
zrtpValidation.close()
callEnded(call)
}
}
onTransferStateChanged: {
console.log("Transfer state:", transferState)
if (transferState === LinphoneEnums.CallState.Error) {
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Le transfert d'appel a échoué"), false, mainWindow)
}
else if (transferState === LinphoneEnums.CallState.Connected){
var mainWin = UtilsCpp.getMainWindow()
UtilsCpp.smartShowWindow(mainWin)
mainWin.transferCallSucceed()
}
}
onClosing: (close) => {
DesktopToolsCpp.screenSaverStatus = true
if (callsModel.haveCall) {
close.accepted = false
terminateAllCallsDialog.open()
}
}
function changeLayout(layoutIndex) {
if (layoutIndex == 0) {
console.log("Set Grid layout")
call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.Grid)
} else if (layoutIndex == 1) {
console.log("Set AS layout")
call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.ActiveSpeaker)
} else {
console.log("Set audio-only layout")
call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.AudioOnly)
}
}
function endCall(callToFinish) {
if (callToFinish) callToFinish.core.lTerminate()
// var mainWin = UtilsCpp.getMainWindow()
// mainWin.goToCallHistory()
}
function callEnded(call){
if (call.core.state === LinphoneEnums.CallState.Error) {
middleItemStackView.replace(inCallItem)
}
if (!callsModel.haveCall) {
if (call && call.core.isConference) UtilsCpp.closeCallsWindow()
else {
bottomButtonsLayout.setButtonsEnabled(false)
autoCloseWindow.restart()
}
} else {
mainWindow.call = callsModel.currentCall
}
}
signal setUpConferenceRequested(ConferenceInfoGui conferenceInfo)
function setupConference(conferenceInfo) {
middleItemStackView.replace(waitingRoom)
setUpConferenceRequested(conferenceInfo)
}
function joinConference(uri, options) {
if (uri.length === 0) UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence n'a pas pu démarrer en raison d'une erreur d'uri."), mainWindow)
else {
UtilsCpp.createCall(uri, options)
}
}
function cancelJoinConference() {
if (!callsModel.haveCall) {
UtilsCpp.closeCallsWindow()
} else {
mainWindow.call = callsModel.currentCall
}
middleItemStackView.replace(inCallItem)
}
Connections {
enabled: !!call
target: call && call.core
function onRemoteVideoEnabledChanged() { console.log("remote video enabled", call.core.remoteVideoEnabled)}
function onSecurityUpdated() {
if (call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) {
if (call.core.tokenVerified) {
zrtpValidation.close()
zrtpValidationToast.open()
} else {
zrtpValidation.open()
}
} else {
zrtpValidation.close()
}
}
function onTokenVerified() {
if (!zrtpValidation.isTokenVerified) {
zrtpValidation.securityError = true
} else zrtpValidation.close()
}
}
Timer {
id: autoCloseWindow
interval: 2000
onTriggered: {
UtilsCpp.closeCallsWindow()
}
}
Dialog {
id: terminateAllCallsDialog
onAccepted: call.core.lTerminateAllCalls()
width: 278 * DefaultStyle.dp
text: qsTr("La fenêtre est sur le point d'être fermée. Cela terminera tous les appels en cours. Souhaitez vous continuer ?")
}
CallProxy{
id: callsModel
onCurrentCallChanged: {
if(currentCall) {
mainWindow.call = currentCall
}
}
onHaveCallChanged: {
if (!haveCall) {
mainWindow.endCall()
}
}
}
component BottomButton : Button {
id: bottomButton
required property string enabledIcon
property string disabledIcon
enabled: call != undefined
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
checkable: true
background: Rectangle {
anchors.fill: parent
color: bottomButton.enabled
? disabledIcon
? DefaultStyle.grey_500
: bottomButton.pressed || bottomButton.checked
? DefaultStyle.main2_400
: DefaultStyle.grey_500
: DefaultStyle.grey_600
radius: 71 * DefaultStyle.dp
}
icon.source: disabledIcon && bottomButton.checked ? disabledIcon : enabledIcon
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
contentImageColor: DefaultStyle.grey_0
}
ZrtpAuthenticationDialog {
id: zrtpValidation
call: mainWindow.call
modal: true
}
Popup {
id: waitingPopup
modal: true
closePolicy: Control.Popup.NoAutoClose
anchors.centerIn: parent
padding: 20 * DefaultStyle.dp
underlineColor: DefaultStyle.main1_500_main
radius: 15 * DefaultStyle.dp
width: 278 * DefaultStyle.dp
height: 115 * DefaultStyle.dp
Connections {
target: mainWindow
function onTransferStateChanged() {
if (mainWindow.transferState === LinphoneEnums.CallState.OutgoingInit) waitingPopup.open()
else if (mainWindow.transferState === LinphoneEnums.CallState.Error
|| mainWindow.transferState === LinphoneEnums.CallState.End
|| mainWindow.transferState === LinphoneEnums.CallState.Released
|| mainWindow.transferState === LinphoneEnums.CallState.Connected)
waitingPopup.close()
}
}
contentItem: ColumnLayout {
spacing: 0
BusyIndicator{
Layout.preferredWidth: 33 * DefaultStyle.dp
Layout.preferredHeight: 33 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
}
Text {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Transfert en cours, veuillez patienter")
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
}
}
}
Timer {
id: autoCloseZrtpToast
interval: 4000
onTriggered: {
zrtpValidationToast.y = -zrtpValidationToast.height*2
}
}
Control.Control {
id: zrtpValidationToast
// width: 269 * DefaultStyle.dp
y: -height*2
z: 1
topPadding: 8 * DefaultStyle.dp
bottomPadding: 8 * DefaultStyle.dp
leftPadding: 50 * DefaultStyle.dp
rightPadding: 50 * DefaultStyle.dp
anchors.horizontalCenter: parent.horizontalCenter
clip: true
function open() {
y = headerItem.height/2
autoCloseZrtpToast.restart()
}
Behavior on y {NumberAnimation {duration: 1000}}
background: Rectangle {
anchors.fill: parent
color: DefaultStyle.grey_0
border.color: DefaultStyle.info_500_main
border.width: 1 * DefaultStyle.dp
radius: 50 * DefaultStyle.dp
}
contentItem: RowLayout {
// anchors.centerIn: parent
Image {
source: AppIcons.trusted
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
fillMode: Image.PreserveAspectFit
Layout.fillWidth: true
}
Text {
color: DefaultStyle.info_500_main
text: qsTr("Appareil vérifié")
Layout.fillWidth: true
font {
pixelSize: 14 * DefaultStyle.dp
}
}
}
}
/************************* CONTENT ********************************/
Rectangle {
anchors.fill: parent
color: DefaultStyle.grey_900
ColumnLayout {
anchors.fill: parent
spacing: 10 * DefaultStyle.dp
anchors.bottomMargin: 10 * DefaultStyle.dp
anchors.topMargin: 10 * DefaultStyle.dp
Item {
id: headerItem
Layout.margins: 10 * DefaultStyle.dp
Layout.fillWidth: true
Layout.minimumHeight: 25 * DefaultStyle.dp
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 10 * DefaultStyle.dp
ColumnLayout {
RowLayout {
spacing: 10 * DefaultStyle.dp
EffectImage {
id: callStatusIcon
Layout.preferredWidth: 30 * DefaultStyle.dp
Layout.preferredHeight: 30 * DefaultStyle.dp
// TODO : change with broadcast or meeting icon when available
imageSource: !mainWindow.call
? AppIcons.meeting
: (mainWindow.callState === LinphoneEnums.CallState.End
|| mainWindow.callState === LinphoneEnums.CallState.Released)
? AppIcons.endCall
: (mainWindow.callState === LinphoneEnums.CallState.Paused
|| mainWindow.callState === LinphoneEnums.CallState.PausedByRemote)
? AppIcons.pause
: mainWindow.conference
? AppIcons.usersThree
: mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing
? AppIcons.arrowUpRight
: AppIcons.arrowDownLeft
colorizationColor: !mainWindow.call || mainWindow.call.core.paused || mainWindow.callState === LinphoneEnums.CallState.Paused
|| mainWindow.callState === LinphoneEnums.CallState.PausedByRemote || mainWindow.callState === LinphoneEnums.CallState.End
|| mainWindow.callState === LinphoneEnums.CallState.Released || mainWindow.conference
? DefaultStyle.danger_500main
: mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing
? DefaultStyle.info_500_main
: DefaultStyle.success_500main
}
Text {
id: callStatusText
text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released)
? qsTr("End of the call")
: mainWindow.call && (mainWindow.call.core.paused
|| (mainWindow.callState === LinphoneEnums.CallState.Paused
|| mainWindow.callState === LinphoneEnums.CallState.PausedByRemote))
? (mainWindow.conference ? qsTr('Réunion mise ') : qsTr('Appel mis')) + qsTr(" en pause")
: mainWindow.conference
? mainWindow.conference.core.subject
: mainWindow.call
? EnumsToStringCpp.dirToString(mainWindow.call.core.dir) + qsTr(" call")
: ""
color: DefaultStyle.grey_0
font {
pixelSize: 22 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
Rectangle {
visible: mainWindow.call && (mainWindow.callState === LinphoneEnums.CallState.Connected
|| mainWindow.callState === LinphoneEnums.CallState.StreamsRunning)
Layout.preferredHeight: parent.height
Layout.preferredWidth: 2 * DefaultStyle.dp
color: DefaultStyle.grey_0
}
Text {
text: mainWindow.call ? UtilsCpp.formatElapsedTime(mainWindow.call.core.duration) : ""
color: DefaultStyle.grey_0
font {
pixelSize: 22 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
visible: mainWindow.callState === LinphoneEnums.CallState.Connected
|| mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
}
Text {
Layout.leftMargin: 14 * DefaultStyle.dp
id: conferenceDate
text: mainWindow.conferenceInfo ? mainWindow.conferenceInfo.core.getStartEndDateString() : ""
color: DefaultStyle.grey_0
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
}
RowLayout {
spacing: 5 * DefaultStyle.dp
visible: mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
BusyIndicator {
visible: mainWindow.call && mainWindow.callState != LinphoneEnums.CallState.Connected && mainWindow.callState != LinphoneEnums.CallState.StreamsRunning
Layout.preferredWidth: 15 * DefaultStyle.dp
Layout.preferredHeight: 15 * DefaultStyle.dp
indicatorColor: DefaultStyle.grey_0
}
EffectImage {
Layout.preferredWidth: 15 * DefaultStyle.dp
Layout.preferredHeight: 15 * DefaultStyle.dp
colorizationColor: mainWindow.call
? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp
? DefaultStyle.info_500_main
: mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified
? DefaultStyle.warning_600
: DefaultStyle.info_500_main
: DefaultStyle.grey_0
: "transparent"
visible: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
imageSource: mainWindow.call
? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp
? AppIcons.lockSimple
: mainWindow.call && mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified
? AppIcons.warningCircle
: AppIcons.lockKey
: AppIcons.lockSimpleOpen
: ""
}
Text {
text: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp
? qsTr("Appel chiffré de point à point")
: mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified
? qsTr("Vérification nécessaire")
: qsTr("Appel chiffré de bout en bout")
: qsTr("Appel non chiffré")
: qsTr("En attente de chiffrement")
color: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp
? DefaultStyle.info_500_main
: mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified
? DefaultStyle.warning_600
: DefaultStyle.info_500_main
: DefaultStyle.grey_0
: DefaultStyle.grey_0
font {
pixelSize: 12 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
rightPanel.visible = true
rightPanel.replace(encryptionPanel)
}
}
}
Item {
Layout.fillWidth: true
}
}
}
Item {
Layout.fillWidth: true
}
EffectImage {
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
Layout.rightMargin: 30 * DefaultStyle.dp
property int quality: mainWindow.call ? mainWindow.call.core.quality : 0
imageSource: quality >= 4
? AppIcons.cellSignalFull
: quality >= 3
? AppIcons.cellSignalMedium
: quality >= 2
? AppIcons.cellSignalLow
: AppIcons.cellSignalNone
colorizationColor: DefaultStyle.grey_0
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (rightPanel.visible && rightPanel.contentStackView.currentItem.objectName === "statsPanel") rightPanel.visible = false
else {
rightPanel.visible = true
rightPanel.replace(statsPanel)
}
}
}
}
}
Control.Control {
visible: mainWindow.call
? !!mainWindow.conference
? mainWindow.conference.core.isRecording
: (mainWindow.call.core.recording || mainWindow.call.core.remoteRecording)
: false
anchors.centerIn: parent
leftPadding: 14 * DefaultStyle.dp
rightPadding: 14 * DefaultStyle.dp
topPadding: 6 * DefaultStyle.dp
bottomPadding: 6 * DefaultStyle.dp
background: Rectangle {
anchors.fill: parent
color: DefaultStyle.grey_500
radius: 10 * DefaultStyle.dp
}
contentItem: RowLayout {
spacing: 85 * DefaultStyle.dp
RowLayout {
spacing: 15 * DefaultStyle.dp
EffectImage {
imageSource: AppIcons.recordFill
colorizationColor: DefaultStyle.danger_500main
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
Text {
color: DefaultStyle.danger_500main
font.pixelSize: 14 * DefaultStyle.dp
text: mainWindow.call
? mainWindow.call.core.recording
? mainWindow.conference ? qsTr("Vous enregistrez la réunion") : qsTr("Vous enregistrez l'appel")
: mainWindow.conference ? qsTr("Un participant enregistre la réunion") : qsTr("Votre correspondant enregistre l'appel")
: ""
}
}
Button {
visible: mainWindow.call && mainWindow.call.core.recording
text: qsTr("Arrêter l'enregistrement")
onPressed: mainWindow.call.core.lStopRecording()
}
}
}
}
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 23 * DefaultStyle.dp
Layout.rightMargin: 20 * DefaultStyle.dp
Control.StackView {
id: middleItemStackView
initialItem: inCallItem
Layout.fillWidth: true
Layout.fillHeight: true
}
CallSettingsPanel {
id: rightPanel
Layout.fillHeight: true
Layout.preferredWidth: 393 * DefaultStyle.dp
Layout.topMargin: 10 * DefaultStyle.dp
property int currentIndex: 0
visible: false
function replace(id) {
rightPanel.customHeaderButtons = null
contentStackView.replace(id, Control.StackView.Immediate)
}
headerStack.currentIndex: 0
contentStackView.initialItem: callsListPanel
headerValidateButtonText: qsTr("Ajouter")
}
Component {
id: contactsListPanel
Item {
Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Transfert d'appel")
Keys.onPressed: (event)=> {
if (event.key == Qt.Key_Escape) {
rightPanel.visible = false
event.accepted = true;
}
}
NewCallForm {
id: newCallForm
anchors.fill: parent
anchors.topMargin: 21 * DefaultStyle.dp
anchors.leftMargin: 16 * DefaultStyle.dp
anchors.rightMargin: 16 * DefaultStyle.dp
groupCallVisible: false
searchBarColor: DefaultStyle.grey_0
searchBarBorderColor: DefaultStyle.grey_200
onSelectedContactChanged: {
if (selectedContact) mainWindow.transferCallToContact(mainWindow.call, selectedContact, newCallForm)
}
numPadPopup: numPadPopup
Binding {
target: numPadPopup
property: "visible"
value: true
when: newCallForm.searchBar.numericPadButton.checked
restoreMode: Binding.RestoreValue
}
Item {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: 402 * DefaultStyle.dp
NumericPadPopup {
id: numPadPopup
width: parent.width
roundedBottom: true
visible: false
leftPadding: 40 * DefaultStyle.dp
rightPadding: 40 * DefaultStyle.dp
topPadding: 41 * DefaultStyle.dp
bottomPadding: 18 * DefaultStyle.dp
onLaunchCall: {
UtilsCpp.createCall(dialerTextInput.text)
}
}
}
}
}
}
Component {
id: dialerPanel
ColumnLayout {
Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Dialer")
spacing: 0
Keys.onPressed: (event)=> {
if (event.key == Qt.Key_Escape) {
rightPanel.visible = false
event.accepted = true;
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
SearchBar {
id: dialerTextInput
Layout.fillWidth: true
Layout.leftMargin: 10 * DefaultStyle.dp
Layout.rightMargin: 10 * DefaultStyle.dp
magnifierVisible: false
color: DefaultStyle.grey_0
borderColor: DefaultStyle.grey_200
placeholderText: ""
numericPadPopup: numPadPopup
numericPadButton.visible: false
}
Item {
Layout.preferredWidth: parent.width
Layout.preferredHeight: numPadPopup.height
Layout.topMargin: 10 * DefaultStyle.dp
NumericPadPopup {
id: numPadPopup
width: parent.width
closeButtonVisible: false
roundedBottom: true
visible: parent.visible
currentCall: callsModel.currentCall
leftPadding: 40 * DefaultStyle.dp
rightPadding: 40 * DefaultStyle.dp
topPadding: 41 * DefaultStyle.dp
bottomPadding: 18 * DefaultStyle.dp
onLaunchCall: {
UtilsCpp.createCall(dialerTextInput.text)
}
}
}
}
}
Component {
id: changeLayoutPanel
FocusScope {
Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Modifier la disposition")
Keys.onPressed: (event)=> {
if (event.key == Qt.Key_Escape) {
rightPanel.visible = false
event.accepted = true;
}
}
ColumnLayout {
anchors.fill: parent
anchors.topMargin: 16 * DefaultStyle.dp
anchors.bottomMargin: 16 * DefaultStyle.dp
anchors.leftMargin: 17 * DefaultStyle.dp
anchors.rightMargin: 17 * DefaultStyle.dp
spacing: 12 * DefaultStyle.dp
Text {
Layout.fillWidth: true
text: qsTr("La disposition choisie sera enregistrée pour vos prochaines réunions")
font.pixelSize: 14 * DefaultStyle.dp
color: DefaultStyle.main2_500main
}
RoundedPane {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
Repeater {
model: [
{text: qsTr("Mosaïque"), imgUrl: AppIcons.squaresFour},
{text: qsTr("Intervenant actif"), imgUrl: AppIcons.pip},
{text: qsTr("Audio seulement"), imgUrl: AppIcons.waveform}
]
RadioButton {
id: radiobutton
checkOnClick: false
color: DefaultStyle.main1_500_main
indicatorSize: 20 * DefaultStyle.dp
leftPadding: indicator.width + spacing
spacing: 8 * DefaultStyle.dp
checkable: false // Qt Documentation is wrong: It is true by default. We don't want to change the checked state if the layout change is not effective.
checked: index == 0
? mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.Grid
: index == 1
? mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.ActiveSpeaker
: mainWindow.conferenceLayout === LinphoneEnums.ConferenceLayout.AudioOnly
onClicked: mainWindow.changeLayout(index)
contentItem: RowLayout {
spacing: 5 * DefaultStyle.dp
EffectImage {
id: radioButtonImg
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
imageSource: modelData.imgUrl
colorizationColor: DefaultStyle.main2_500main
}
Text {
text: modelData.text
color: DefaultStyle.main2_500main
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14 * DefaultStyle.dp
Layout.fillWidth: true
}
}
}
}
}
}
Item {Layout.fillHeight: true}
}
}
}
Component {
id: callsListPanel
ColumnLayout {
Control.StackView.onActivated: {
rightPanel.headerTitleText = qsTr("Liste d'appel")
rightPanel.customHeaderButtons = mergeCallPopupButton.createObject(rightPanel)
}
Keys.onPressed: (event)=> {
if (event.key == Qt.Key_Escape) {
rightPanel.visible = false
event.accepted = true;
}
}
spacing: 0
Component {
id: mergeCallPopupButton
PopupButton {
visible: callsModel.count >= 2
id: popupbutton
popup.contentItem: Button {
background: Item{}
contentItem: RowLayout {
spacing: 5 * DefaultStyle.dp
EffectImage {
colorizationColor: DefaultStyle.main2_600
imageSource: AppIcons.arrowsMerge
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
}
Text {
text: qsTr("Merger tous les appels")
font.pixelSize: 14 * DefaultStyle.dp
}
}
onClicked: {
callsModel.lMergeAll()
popupbutton.close()
}
}
}
}
RoundedPane {
Layout.fillWidth: true
Layout.maximumHeight: rightPanel.height
visible: callList.contentHeight > 0
leftPadding: 16 * DefaultStyle.dp
rightPadding: 6 * DefaultStyle.dp
topPadding: 15 * DefaultStyle.dp
bottomPadding: 16 * DefaultStyle.dp
Layout.topMargin: 15 * DefaultStyle.dp
Layout.bottomMargin: 16 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
contentItem: ListView {
id: callList
model: CallProxy {
id: callProxy
}
implicitHeight: contentHeight// Math.min(contentHeight, rightPanel.height)
spacing: 15 * DefaultStyle.dp
clip: true
onCountChanged: forceLayout()
delegate: Item {
id: callDelegate
width: callList.width
height: 45 * DefaultStyle.dp
RowLayout {
id: delegateContent
anchors.fill: parent
spacing: 0
Avatar {
id: delegateAvatar
_address: modelData.core.peerAddress
Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp
}
Text {
id: delegateName
property var remoteAddress: UtilsCpp.getDisplayName(modelData.core.peerAddress)
text: modelData.core.isConference
? modelData.core.conference.core.subject
: remoteAddress ? remoteAddress.value : ""
Layout.leftMargin: 8 * DefaultStyle.dp
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
Text {
id: callStateText
Layout.rightMargin: 2 * DefaultStyle.dp
property string type: modelData.core.isConference ? qsTr('Réunion') : qsTr('Appel')
text: modelData.core.state === LinphoneEnums.CallState.Paused
|| modelData.core.state === LinphoneEnums.CallState.PausedByRemote
? type + qsTr(" en pause")
: type + qsTr(" en cours")
}
PopupButton {
id: listCallOptionsButton
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.rightMargin: 10 * DefaultStyle.dp
popup.contentItem: ColumnLayout {
spacing: 0
Button {
id: pausingButton
onClicked: modelData.core.lSetPaused(!modelData.core.paused)
KeyNavigation.up: endCallButton
KeyNavigation.down: endCallButton
background: Item {}
contentItem: RowLayout {
spacing: 5 * DefaultStyle.dp
Image {
source: modelData.core.state === LinphoneEnums.CallState.Paused
|| modelData.core.state === LinphoneEnums.CallState.PausedByRemote
? AppIcons.phone : AppIcons.pause
sourceSize.width: 32 * DefaultStyle.dp
sourceSize.height: 32 * DefaultStyle.dp
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
fillMode: Image.PreserveAspectFit
}
Text {
text: modelData.core.state === LinphoneEnums.CallState.Paused
|| modelData.core.state === LinphoneEnums.CallState.PausedByRemote
? qsTr("Reprendre l'appel") : qsTr("Mettre en pause")
color: DefaultStyle.main2_500main
font.bold: pausingButton.shadowEnabled
}
Item {
Layout.fillWidth: true
}
}
}
Button {
id: endCallButton
onClicked: mainWindow.endCall(modelData)
KeyNavigation.up: pausingButton
KeyNavigation.down: pausingButton
background: Item {}
contentItem: RowLayout {
spacing: 5 * DefaultStyle.dp
EffectImage {
imageSource: AppIcons.endCall
colorizationColor: DefaultStyle.danger_500main
width: 32 * DefaultStyle.dp
height: 32 * DefaultStyle.dp
}
Text {
color: DefaultStyle.danger_500main
text: qsTr("Terminer l'appel")
font.bold: endCallButton.shadowEnabled
}
Item {
Layout.fillWidth: true
}
}
}
}
}
}
}
}
}
Item {
Layout.fillHeight: true
}
}
}
Component {
id: settingsPanel
Item {
Control.StackView.onActivated: {
rightPanel.headerTitleText = qsTr("Paramètres")
}
Keys.onPressed: (event)=> {
if (event.key == Qt.Key_Escape) {
rightPanel.visible = false
event.accepted = true;
}
}
MultimediaSettings {
id: inSettingsPanel
call: mainWindow.call
anchors.fill: parent
anchors.topMargin: 16 * DefaultStyle.dp
anchors.bottomMargin: 16 * DefaultStyle.dp
anchors.leftMargin: 17 * DefaultStyle.dp
anchors.rightMargin: 17 * DefaultStyle.dp
}
}
}
Component {
id: screencastPanel
Item {
Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Partage de votre écran")
Keys.onPressed: (event)=> {
if (event.key == Qt.Key_Escape) {
rightPanel.visible = false
event.accepted = true;
}
}
ScreencastSettings {
anchors.fill: parent
anchors.topMargin: 16 * DefaultStyle.dp
anchors.bottomMargin: 16 * DefaultStyle.dp
anchors.leftMargin: 17 * DefaultStyle.dp
anchors.rightMargin: 17 * DefaultStyle.dp
call: mainWindow.call
}
}
}
Component {
id: participantListPanel
Item {
Keys.onPressed: (event)=> {
if (event.key == Qt.Key_Escape) {
rightPanel.visible = false
event.accepted = true;
}
}
Control.StackView {
id: participantsStack
anchors.fill: parent
anchors.bottomMargin: 16 * DefaultStyle.dp
anchors.leftMargin: 17 * DefaultStyle.dp
anchors.rightMargin: 17 * DefaultStyle.dp
initialItem: participantListComp
onCurrentItemChanged: rightPanel.headerStack.currentIndex = currentItem.Control.StackView.index
property list<string> selectedParticipants
signal participantAdded()
Connections {
target: rightPanel
function onReturnRequested(){ participantsStack.pop()}
}
Component {
id: participantListComp
ParticipantListView {
id: participantList
Component {
id: headerbutton
PopupButton {
popup.contentItem: Button {
background: Item{}
contentItem: RowLayout {
spacing: 0
EffectImage {
colorizationColor: DefaultStyle.main2_600
imageSource: AppIcons.shareNetwork
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
Text {
text: qsTr("Partager le lien de la réunion")
font.pixelSize: 14 * DefaultStyle.dp
}
}
onClicked: {
UtilsCpp.copyToClipboard(mainWindow.call.core.peerAddress)
showInformationPopup(qsTr("Copié"), qsTr("Le lien de la réunion a été copié dans le presse-papier"), true)
}
}
}
}
Control.StackView.onActivated: {
rightPanel.customHeaderButtons = headerbutton.createObject(rightPanel)
rightPanel.headerTitleText = qsTr("Participants (%1)").arg(count)
}
call: mainWindow.call
onAddParticipantRequested: participantsStack.push(addParticipantComp)
onCountChanged: {
rightPanel.headerTitleText = qsTr("Participants (%1)").arg(count)
}
Connections {
target: participantsStack
function onCurrentItemChanged() {
if (participantsStack.currentItem == participantList) rightPanel.headerTitleText = qsTr("Participants (%1)").arg(participantList.count)
}
}
Connections {
target: rightPanel
function onValidateRequested() {
participantList.model.addAddresses(participantsStack.selectedParticipants)
participantsStack.pop()
participantsStack.participantAdded()
}
}
}
}
Component {
id: addParticipantComp
AddParticipantsForm {
id: addParticipantLayout
searchBarColor: DefaultStyle.grey_0
searchBarBorderColor: DefaultStyle.grey_200
onSelectedParticipantsCountChanged: {
rightPanel.headerSubtitleText = qsTr("%1 participant%2 sélectionné%2").arg(selectedParticipantsCount).arg(selectedParticipantsCount > 1 ? "s" : "")
participantsStack.selectedParticipants = selectedParticipants
}
Connections {
target: participantsStack
function onCurrentItemChanged() {
if (participantsStack.currentItem == addParticipantLayout) {
rightPanel.headerTitleText = qsTr("Ajouter des participants")
rightPanel.headerSubtitleText = qsTr("%1 participant%2 sélectionné%2").arg(addParticipantLayout.selectedParticipants.length).arg(addParticipantLayout.selectedParticipants.length > 1 ? "s" : "")
}
}
}
}
}
}
}
}
Component {
id: encryptionPanel
ColumnLayout {
Control.StackView.onActivated: {
rightPanel.headerTitleText = qsTr("Chiffrement")
}
RoundedPane {
Layout.fillWidth: true
leftPadding: 16 * DefaultStyle.dp
rightPadding: 16 * DefaultStyle.dp
topPadding: 13 * DefaultStyle.dp
bottomPadding: 13 * DefaultStyle.dp
Layout.topMargin: 13 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
contentItem: ColumnLayout {
spacing: 12 * DefaultStyle.dp
Text {
text: qsTr("Chiffrement :")
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 7 * DefaultStyle.dp
Text {
property bool isPostQuantum: mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp && mainWindow.call.core.zrtpStats.isPostQuantum
text: qsTr("Chiffrement du média : %1%2").arg(isPostQuantum ? "post Quantum " : "").arg(mainWindow.call.core.encryptionString)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
ColumnLayout {
visible: mainWindow.call && mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
Text {
text: qsTr("Cipher algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.cipherAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: qsTr("Key agreement algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.keyAgreementAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: qsTr("Hash algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.hashAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: qsTr("Authentication algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.authenticationAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: qsTr("SAS algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.sasAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
}
}
}
}
Item{Layout.fillHeight: true}
Button {
visible: mainWindow.call && mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
Layout.fillWidth: true
text: qsTr("Validation chiffrement")
onClicked: zrtpValidation.open()
Layout.bottomMargin: 13 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
leftPadding: 20 * DefaultStyle.dp
rightPadding: 20 * DefaultStyle.dp
topPadding: 11 * DefaultStyle.dp
bottomPadding: 11 * DefaultStyle.dp
}
}
}
Component {
id: statsPanel
ColumnLayout {
property string objectName: "statsPanel"
spacing: 20 * DefaultStyle.dp
Control.StackView.onActivated: {
rightPanel.headerTitleText = qsTr("Statistiques")
}
RoundedPane {
Layout.fillWidth: true
leftPadding: 16 * DefaultStyle.dp
rightPadding: 16 * DefaultStyle.dp
topPadding: 13 * DefaultStyle.dp
bottomPadding: 13 * DefaultStyle.dp
Layout.topMargin: 13 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
contentItem: ColumnLayout {
spacing: 12 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
Text {
text: qsTr("Audio")
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
ColumnLayout {
spacing: 7 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
Text {
text: mainWindow.call ? mainWindow.call.core.audioStats.codec : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: mainWindow.call ? mainWindow.call.core.audioStats.bandwidth : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
}
}
}
RoundedPane {
Layout.fillWidth: true
leftPadding: 16 * DefaultStyle.dp
rightPadding: 16 * DefaultStyle.dp
topPadding: 13 * DefaultStyle.dp
bottomPadding: 13 * DefaultStyle.dp
Layout.topMargin: 13 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
visible: mainWindow.call && (mainWindow.call.core.localVideoEnabled || mainWindow.call.core.remoteVideoEnabled)
contentItem: ColumnLayout {
spacing: 12 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
Text {
text: qsTr("Vidéo")
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
ColumnLayout {
spacing: 7 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
Text {
text: mainWindow.call ? mainWindow.call.core.videoStats.codec : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: mainWindow.call ? mainWindow.call.core.videoStats.bandwidth : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: mainWindow.call ? mainWindow.call.core.videoStats.resolution : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: mainWindow.call ? mainWindow.call.core.videoStats.fps : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
}
}
}
Item{Layout.fillHeight: true}
}
}
}
Component {
id: waitingRoom
WaitingRoom {
id: waitingRoomIn
objectName: "waitingRoom"
Layout.alignment: Qt.AlignCenter
onSettingsButtonCheckedChanged: {
if (settingsButtonChecked) {
rightPanel.visible = true
rightPanel.replace(settingsPanel)
} else {
rightPanel.visible = false
}
}
Binding {
target: callStatusIcon
when: middleItemStackView.currentItem.objectName === "waitingRoom"
property: "imageSource"
value: AppIcons.usersThree
restoreMode: Binding.RestoreBindingOrValue
}
Binding {
target: callStatusText
when: middleItemStackView.currentItem.objectName === "waitingRoom"
property: "text"
value: waitingRoomIn.conferenceInfo ? waitingRoomIn.conferenceInfo.core.subject : ''
restoreMode: Binding.RestoreBindingOrValue
}
Binding {
target: conferenceDate
when: middleItemStackView.currentItem.objectName === "waitingRoom"
property: "text"
value: waitingRoomIn.conferenceInfo ? waitingRoomIn.conferenceInfo.core.startEndDateString : ''
}
Connections {
target: rightPanel
function onVisibleChanged(){ if (!visible) waitingRoomIn.settingsButtonChecked = false}
}
Connections {
target:mainWindow
function onSetUpConferenceRequested(conferenceInfo) {
waitingRoomIn.conferenceInfo = conferenceInfo
}
}
onJoinConfRequested: (uri) => {
mainWindow.joinConference(uri, {'microEnabled':microEnabled, 'localVideoEnabled':localVideoEnabled})
}
onCancelJoiningRequested: mainWindow.cancelJoinConference()
}
}
Component {
id: inCallItem
Item {
property string objectName: "inCallItem"
CallLayout{
anchors.fill: parent
anchors.leftMargin: 20 * DefaultStyle.dp
anchors.rightMargin: (rightPanel.visible ? 0 : 10) * DefaultStyle.dp // Grid and AS have 10 in right margin (so apply -10 here)
anchors.topMargin: 10 * DefaultStyle.dp
call: mainWindow.call
callTerminatedByUser: mainWindow.callTerminatedByUser
}
}
}
RowLayout {
id: bottomButtonsLayout
Layout.alignment: Qt.AlignHCenter
spacing: 58 * DefaultStyle.dp
visible: middleItemStackView.currentItem.objectName == "inCallItem"
function refreshLayout() {
if (mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) {
connectedCallButtons.visible = bottomButtonsLayout.visible
moreOptionsButton.visible = bottomButtonsLayout.visible
bottomButtonsLayout.layoutDirection = Qt.RightToLeft
}
else if (mainWindow.callState === LinphoneEnums.CallState.OutgoingInit) {
connectedCallButtons.visible = false
bottomButtonsLayout.layoutDirection = Qt.LeftToRight
moreOptionsButton.visible = false
}
}
Connections {
target: mainWindow
function onCallStateChanged(){ bottomButtonsLayout.refreshLayout()}
function onCallChanged(){ bottomButtonsLayout.refreshLayout()}
}
function setButtonsEnabled(enabled) {
for(var i=0; i < children.length; ++i) {
children[i].enabled = false
}
}
Button {
Layout.row: 0
icon.source: AppIcons.endCall
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
Layout.preferredWidth: 75 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
contentImageColor: DefaultStyle.grey_0
checkable: false
Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia
|| mainWindow.callState == LinphoneEnums.CallState.IncomingReceived
? 0 : bottomButtonsLayout.columns - 1
background: Rectangle {
anchors.fill: parent
color: DefaultStyle.danger_500main
radius: 71 * DefaultStyle.dp
}
onClicked: {
mainWindow.endCall(mainWindow.call)
mainWindow.callTerminatedByUser = true
}
}
RowLayout {
id: connectedCallButtons
visible: false
Layout.row: 0
Layout.column: 1
spacing: 10 * DefaultStyle.dp
CheckableButton {
id: pauseButton
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
background: Rectangle {
anchors.fill: parent
radius: 71 * DefaultStyle.dp
color: parent.enabled
? parent.checked
? DefaultStyle.success_500main
: parent.pressed
? DefaultStyle.main2_400
: DefaultStyle.grey_500
: DefaultStyle.grey_600
}
enabled: mainWindow.conference || mainWindow.callState != LinphoneEnums.CallState.PausedByRemote
icon.source: enabled && checked ? AppIcons.play : AppIcons.pause
checked: mainWindow.call && mainWindow.callState == LinphoneEnums.CallState.Paused || mainWindow.callState == LinphoneEnums.CallState.Pausing || (!mainWindow.conference && mainWindow.callState == LinphoneEnums.CallState.PausedByRemote)
onClicked: {
mainWindow.call.core.lSetPaused(!mainWindow.call.core.paused)
}
}
CheckableButton {
id: transferCallButton
icon.source: AppIcons.transferCall
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
contentImageColor: enabled ? DefaultStyle.grey_0 : DefaultStyle.grey_500
onCheckedChanged: {
if (checked) {
rightPanel.visible = true
rightPanel.replace(contactsListPanel)
} else {
rightPanel.visible = false
}
}
Connections {
target: rightPanel
function onVisibleChanged(){ if(!rightPanel.visible) transferCallButton.checked = false}
}
}
CheckableButton {
id: newCallButton
checkable: false
icon.source: AppIcons.newCall
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
onClicked: {
var mainWin = UtilsCpp.getMainWindow()
UtilsCpp.smartShowWindow(mainWin)
mainWin.goToNewCall()
}
}
}
RowLayout {
Layout.row: 0
Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia
|| mainWindow.callState == LinphoneEnums.CallState.IncomingReceived
? bottomButtonsLayout.columns - 1 : 0
spacing: 10 * DefaultStyle.dp
CheckableButton {
id: videoCameraButton
enabled: mainWindow.conferenceInfo || (mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning)
iconUrl: AppIcons.videoCamera
checkedIconUrl: AppIcons.videoCameraSlash
checked: mainWindow.call && !mainWindow.call.core.localVideoEnabled
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
onClicked: mainWindow.call.core.lSetLocalVideoEnabled(!mainWindow.call.core.localVideoEnabled)
}
CheckableButton {
iconUrl: AppIcons.microphone
checkedIconUrl: AppIcons.microphoneSlash
checked: mainWindow.call && mainWindow.call.core.microphoneMuted
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
onClicked: mainWindow.call.core.lSetMicrophoneMuted(!mainWindow.call.core.microphoneMuted)
}
CheckableButton {
iconUrl: AppIcons.screencast
visible: !!mainWindow.conference
checkedColor: DefaultStyle.main2_400
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
onCheckedChanged: {
if (checked) {
rightPanel.visible = true
rightPanel.replace(screencastPanel)
} else {
rightPanel.visible = false
}
}
}
CheckableButton {
visible: false
checkable: false
checkedColor: DefaultStyle.main2_400
iconUrl: AppIcons.handWaving
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
}
CheckableButton {
visible: false
iconUrl: AppIcons.smiley
checkedColor: DefaultStyle.main2_400
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
}
CheckableButton {
visible: mainWindow.conference
iconUrl: AppIcons.usersTwo
checkedColor: DefaultStyle.main2_400
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
onCheckedChanged: {
if (checked) {
rightPanel.visible = true
rightPanel.replace(participantListPanel)
} else {
rightPanel.visible = false
}
}
}
PopupButton {
id: moreOptionsButton
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
contentImageColor: enabled && !checked ? DefaultStyle.grey_0 : DefaultStyle.grey_500
icon.source: AppIcons.more
background: Rectangle {
anchors.fill: moreOptionsButton
color: moreOptionsButton.enabled
? moreOptionsButton.checked
? DefaultStyle.main2_400
: DefaultStyle.grey_500
: DefaultStyle.grey_600
radius: 40 * DefaultStyle.dp
}
popup.x: width/2
Connections {
target: moreOptionsButton.popup
function onOpened() {
moreOptionsButton.popup.y = - moreOptionsButton.popup.height - moreOptionsButton.popup.padding
}
}
component MenuButton: Button {
background: Item{}
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
textColor: down || checked ? DefaultStyle.main1_500_main : DefaultStyle.main2_500main
contentImageColor: down || checked ? DefaultStyle.main1_500_main : DefaultStyle.main2_500main
textSize: 14 * DefaultStyle.dp
textWeight: 400 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
}
popup.contentItem: ColumnLayout {
id: optionsList
spacing: 5 * DefaultStyle.dp
MenuButton {
visible: mainWindow.conference
Layout.fillWidth: true
icon.source: AppIcons.squaresFour
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
text: qsTr("Modifier la disposition")
onClicked: {
rightPanel.visible = true
rightPanel.replace(changeLayoutPanel)
moreOptionsButton.close()
}
}
MenuButton {
visible: mainWindow.conference
Layout.fillWidth: true
icon.source: AppIcons.fullscreen
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
text: qsTr("Mode Plein écran")
checkable: true
onToggled: {
if(checked) {
DesktopToolsCpp.screenSaverStatus = false
mainWindow.showFullScreen()
}else{
DesktopToolsCpp.screenSaverStatus = true
mainWindow.showNormal()
}
}
}
MenuButton {
icon.source: AppIcons.callList
Layout.fillWidth: true
text: qsTr("Liste d'appel")
onClicked: {
rightPanel.visible = true
rightPanel.replace(callsListPanel)
moreOptionsButton.close()
}
}
MenuButton {
icon.source: AppIcons.dialer
text: qsTr("Dialer")
Layout.fillWidth: true
onClicked: {
rightPanel.visible = true
rightPanel.replace(dialerPanel)
moreOptionsButton.close()
}
}
MenuButton {
checkable: true
visible: mainWindow.call && !mainWindow.conference
enabled: mainWindow.call && mainWindow.call.core.recordable
icon.source: AppIcons.recordFill
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
checked: mainWindow.call && mainWindow.call.core.recording
contentImageColor: down
? DefaultStyle.main1_500_main
:mainWindow.call && mainWindow.call.core.recording
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
text: mainWindow.call && mainWindow.call.core.recording ? qsTr("Terminer l'enregistrement") : qsTr("Enregistrer l'appel")
textColor: down
? DefaultStyle.main1_500_main
:mainWindow.call && mainWindow.call.core.recording
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
Layout.fillWidth: true
onToggled: {
if (mainWindow.call)
if (mainWindow.call.core.recording) mainWindow.call.core.lStopRecording()
else mainWindow.call.core.lStartRecording()
}
}
MenuButton {
checkable: true
icon.source: !mainWindow.call || mainWindow.call.core.speakerMuted ? AppIcons.speakerSlash : AppIcons.speaker
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
contentImageColor: down
? DefaultStyle.main1_500_main
: mainWindow.call && mainWindow.call.core.speakerMuted
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
text: mainWindow.call && mainWindow.call.core.speakerMuted ? qsTr("Activer le son") : qsTr("Désactiver le son")
textColor: down
? DefaultStyle.main1_500_main
:mainWindow.call && mainWindow.call.core.speakerMuted
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
Layout.fillWidth: true
onCheckedChanged: {
if (mainWindow.call) mainWindow.call.core.lSetSpeakerMuted(!mainWindow.call.core.speakerMuted)
}
}
MenuButton {
Layout.fillWidth: true
icon.source: AppIcons.settings
text: qsTr("Paramètres")
onClicked: {
rightPanel.visible = true
rightPanel.replace(settingsPanel)
moreOptionsButton.close()
}
}
}
}
}
}
}
}
}