linphone-desktop/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml
Julien Wadel 9f9b624abd Display secure icon on contacts if it has the capability.
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.
2023-07-26 16:55:34 +02:00

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
}
}
}
}