mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-21 21:58:06 +00:00
Deactivate video if no codecs are selected. Link to licence in about. Fix loosing ICE configuration. Fix click shortcut on the first item on smartsearch bar. Add separated and editable prefix phone number in assistant.
314 lines
11 KiB
QML
314 lines
11 KiB
QML
import QtQuick 2.12
|
|
import QtQuick.Layouts 1.3
|
|
import QtQml.Models 2.12
|
|
import QtGraphicalEffects 1.12
|
|
import QtQuick.Controls 2.12
|
|
import Common 1.0
|
|
import Common.Styles 1.0
|
|
import Linphone 1.0
|
|
import Linphone.Styles 1.0
|
|
|
|
import LinphoneEnums 1.0
|
|
|
|
import UtilsCpp 1.0
|
|
|
|
import App.Styles 1.0
|
|
|
|
// =============================================================================
|
|
|
|
Rectangle{
|
|
id: mainItem
|
|
property CallModel callModel
|
|
property ConferenceModel conferenceModel: callModel.conferenceModel
|
|
property ParticipantModel me: conferenceModel ? conferenceModel.localParticipant : null
|
|
property bool isMeAdmin: me && me.adminStatus
|
|
property bool isParticipantsMenu: false
|
|
signal close()
|
|
signal layoutChanging(int layoutMode)
|
|
|
|
height: 500
|
|
width: 400
|
|
color: "white"
|
|
radius: IncallMenuStyle.radius
|
|
|
|
// List of title texts in order to allow bindings between all components
|
|
property var menuTitles: [
|
|
//: 'Multimedia parameters' : Menu title to show multimedia devices configuration.
|
|
qsTr('incallMenuMultimedia'),
|
|
//: 'Change layout' : Menu title to change the conference layout.
|
|
qsTr('incallMenuLayout'),
|
|
//: 'Invite participants' : Menu title to invite participants in admin mode.
|
|
mainItem.isMeAdmin ? qsTr('incallMenuInvite')
|
|
//: 'Participants list' : Menu title to show participants in non-admin mode.
|
|
: qsTr('incallMenuParticipants')
|
|
]
|
|
|
|
function showParticipantsMenu(){
|
|
contentsStack.push(participantsMenu, {title:Qt.binding(function() { return mainItem.menuTitles[2]})})
|
|
visible = true
|
|
}
|
|
onVisibleChanged: if(!visible && contentsStack.nViews > 1) {
|
|
contentsStack.pop()
|
|
}
|
|
property bool _activateCamera: false
|
|
Connections{// Enable camera only when status is ok
|
|
target: mainItem.callModel
|
|
onStatusChanged: if( mainItem._activateCamera && (status == CallModel.CallStatusConnected || status == CallModel.CallStatusIdle)){
|
|
camera._activateCamera = false
|
|
callModel.cameraEnabled = true
|
|
}
|
|
}
|
|
ButtonGroup{id: modeGroup}
|
|
ColumnLayout{
|
|
anchors.fill: parent
|
|
// HEADER
|
|
Borders{
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Math.max(IncallMenuStyle.header.height, titleMenu.implicitHeight+20)
|
|
bottomColor: IncallMenuStyle.list.border.colorModel.color
|
|
bottomWidth: IncallMenuStyle.list.border.width
|
|
RowLayout{
|
|
anchors.fill: parent
|
|
ActionButton{
|
|
backgroundRadius: width/2
|
|
isCustom: true
|
|
colorSet: IncallMenuStyle.buttons.back
|
|
onClicked: contentsStack.pop()
|
|
visible: contentsStack.nViews > 1
|
|
}
|
|
Text{
|
|
id: titleMenu
|
|
text: contentsStack.currentItem.title
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: implicitHeight
|
|
horizontalAlignment: Qt.AlignCenter
|
|
color: IncallMenuStyle.header.colorModel.color
|
|
font.pointSize: IncallMenuStyle.header.pointSize
|
|
font.weight: IncallMenuStyle.header.weight
|
|
wrapMode: Text.WordWrap
|
|
elide: Text.ElideRight
|
|
}
|
|
ActionButton{
|
|
Layout.rightMargin: 10
|
|
backgroundRadius: width/2
|
|
isCustom: true
|
|
colorSet: IncallMenuStyle.buttons.close
|
|
onClicked: mainItem.close()
|
|
}
|
|
}
|
|
}
|
|
// CONTENT
|
|
StackView{
|
|
id: contentsStack
|
|
initialItem: settingsMenuComponent
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
}
|
|
Component{
|
|
id: settingsMenuComponent
|
|
ColumnLayout{
|
|
property string objectName: 'settingsMenu'
|
|
//: 'Settings' : Main menu title for settings.
|
|
property string title: qsTr('incallMenuTitle')
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
Repeater{
|
|
model: [
|
|
{titleIndex: 0
|
|
,icon: IncallMenuStyle.settingsIcons.mediaIcon
|
|
, nextPage:mediaMenu
|
|
, visible: true},
|
|
|
|
{titleIndex: 1
|
|
, icon: (mainItem.callModel
|
|
? mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutAudioOnly
|
|
? IncallMenuStyle.settingsIcons.audioOnlyIcon
|
|
: mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid
|
|
? IncallMenuStyle.settingsIcons.gridIcon
|
|
: IncallMenuStyle.settingsIcons.activeSpeakerIcon
|
|
: IncallMenuStyle.settingsIcons.audioOnlyIcon)
|
|
, nextPage:layoutMenu
|
|
, visible: mainItem.callModel && mainItem.callModel.isConference && SettingsModel.videoAvailable},
|
|
|
|
{ titleIndex: 2
|
|
, icon: IncallMenuStyle.settingsIcons.participantsIcon
|
|
, nextPage:participantsMenu
|
|
, visible: mainItem.callModel && mainItem.callModel.isConference}
|
|
]
|
|
delegate:
|
|
Borders{
|
|
bottomColor: IncallMenuStyle.list.border.colorModel.color
|
|
bottomWidth: IncallMenuStyle.list.border.width
|
|
Layout.preferredHeight: Math.max(settingIcon.height, settingsDescription.implicitHeight) + 20
|
|
Layout.fillWidth: true
|
|
visible: modelData.visible
|
|
RowLayout{
|
|
anchors.fill: parent
|
|
Icon{
|
|
id: settingIcon
|
|
Layout.minimumWidth: iconWidth
|
|
Layout.leftMargin: 15
|
|
Layout.alignment: Qt.AlignVCenter
|
|
icon: modelData.icon
|
|
overwriteColor: IncallMenuStyle.list.colorModel.color
|
|
iconWidth: IncallMenuStyle.settingsIcons.width
|
|
iconHeight: IncallMenuStyle.settingsIcons.height
|
|
}
|
|
Text{
|
|
id: settingsDescription
|
|
Layout.fillWidth: true
|
|
height: implicitHeight
|
|
wrapMode: Text.WordWrap
|
|
elide: Text.ElideRight
|
|
|
|
text: mainItem.menuTitles[modelData.titleIndex]
|
|
font.pointSize: IncallMenuStyle.list.pointSize
|
|
color: IncallMenuStyle.list.colorModel.color
|
|
}
|
|
Icon{
|
|
Layout.minimumWidth: iconWidth
|
|
Layout.rightMargin: 10
|
|
Layout.alignment: Qt.AlignVCenter
|
|
//backgroundRadius: width/2
|
|
|
|
icon: IncallMenuStyle.buttons.next.icon
|
|
overwriteColor: IncallMenuStyle.buttons.next.backgroundNormalColor.color
|
|
iconWidth: IncallMenuStyle.buttons.next.iconSize
|
|
iconHeight: IncallMenuStyle.buttons.next.iconSize
|
|
}
|
|
}
|
|
MouseArea{
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
contentsStack.push(modelData.nextPage, {title:Qt.binding(function() { return settingsDescription.text})})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Item{// Spacer
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------------------------------------------------------
|
|
Component{
|
|
id: mediaMenu
|
|
ColumnLayout{
|
|
property string title
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
MultimediaParametersDialog{
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
Layout.minimumHeight: fitHeight
|
|
call: mainItem.callModel
|
|
flat: true
|
|
showMargins: true
|
|
expandHeight: false
|
|
fixedSize: false
|
|
showTitleBar: false
|
|
onExitStatus: contentsStack.pop()
|
|
}
|
|
Item{// Spacer
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------------------------------------------------------
|
|
Component{
|
|
id: layoutMenu
|
|
ColumnLayout{
|
|
property string title
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
Repeater{
|
|
//: 'Mosaic mode' : Grid layout for video conference.
|
|
model: [{text: qsTr('incallMenuGridLayout'), icon: IncallMenuStyle.modeIcons.gridIcon, value:LinphoneEnums.ConferenceLayoutGrid}
|
|
//: 'Active speaker mode' : Active speaker layout for video conference.
|
|
, {text: qsTr('incallMenuActiveSpeakerLayout'), icon: IncallMenuStyle.modeIcons.activeSpeakerIcon, value:LinphoneEnums.ConferenceLayoutActiveSpeaker}
|
|
//: 'Audio only mode' : Audio only layout for video conference.
|
|
, {text: qsTr('incallMenuAudioLayout'), icon: IncallMenuStyle.modeIcons.audioOnlyIcon, value:LinphoneEnums.ConferenceLayoutAudioOnly}
|
|
]
|
|
delegate:
|
|
Borders{
|
|
bottomColor: IncallMenuStyle.list.border.colorModel.color
|
|
bottomWidth: IncallMenuStyle.list.border.width
|
|
Layout.preferredHeight: Math.max(layoutIcon.height, radio.contentItem.implicitHeight) + 20
|
|
Layout.fillWidth: true
|
|
enabled: mainItem.callModel && !mainItem.callModel.updating
|
|
MouseArea{
|
|
anchors.fill: parent
|
|
onClicked: radio.clicked()
|
|
}
|
|
RowLayout{
|
|
anchors.fill: parent
|
|
|
|
RadioButton{
|
|
id: radio
|
|
Layout.fillWidth: true
|
|
Layout.leftMargin: 15
|
|
Layout.preferredHeight: contentItem.implicitHeight
|
|
Layout.alignment: Qt.AlignVCenter
|
|
ButtonGroup.group: modeGroup
|
|
text: modelData.text
|
|
property bool isInternallyChecked: mainItem.callModel ? (mainItem.callModel.localVideoEnabled && modelData.value == mainItem.callModel.conferenceVideoLayout)
|
|
|| (!mainItem.callModel.localVideoEnabled && modelData.value == LinphoneEnums.ConferenceLayoutAudioOnly)
|
|
: false
|
|
// break bind. Radiobutton checked itself without taking care of custom binding. This workaound works as long as we don't really need the binding.
|
|
onIsInternallyCheckedChanged: checked = isInternallyChecked
|
|
Component.onCompleted: checked = isInternallyChecked
|
|
onClicked: mainItem.layoutChanging(modelData.value)
|
|
}
|
|
Icon{
|
|
id: layoutIcon
|
|
Layout.minimumWidth: iconWidth
|
|
Layout.rightMargin: 10
|
|
Layout.alignment: Qt.AlignVCenter
|
|
icon: modelData.icon
|
|
iconWidth: IncallMenuStyle.modeIcons.width
|
|
iconHeight: IncallMenuStyle.modeIcons.height
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Item{// Spacer
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------------------------------------------------------
|
|
Component{
|
|
id: participantsMenu
|
|
ColumnLayout{
|
|
property string title
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
ParticipantsListView{
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
Layout.leftMargin: 10
|
|
Layout.rightMargin: 10
|
|
conferenceModel: mainItem.conferenceModel
|
|
isAdmin: mainItem.isMeAdmin
|
|
Text{
|
|
//: 'Your are currently alone in this meeting' : Message to warn the user when there is no other participant.
|
|
text: qsTr('incallMenuParticipantsAlone')
|
|
visible: parent.count <= 1
|
|
font.pointSize: IncallMenuStyle.list.pointSize
|
|
color: IncallMenuStyle.list.colorModel.color
|
|
}
|
|
}
|
|
Item{// Spacer
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
}
|
|
Component.onCompleted: mainItem.isParticipantsMenu = true
|
|
Component.onDestruction: mainItem.isParticipantsMenu = false
|
|
}
|
|
}
|
|
}
|
|
}
|