import QtQuick 2.7 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.3 import Common 1.0 import Linphone 1.0 //import LinphoneUtils 1.0 import LinphoneEnums 1.0 import App.Styles 1.0 import Common.Styles 1.0 import Units 1.0 import UtilsCpp 1.0 import ColorsList 1.0 import 'qrc:/ui/scripts/Utils/utils.js' as Utils // ============================================================================= DialogPlus { id: conferenceManager property ConferenceInfoModel conferenceInfoModel: ConferenceInfoModel{ onConferenceCreated: { console.log("Conference has been created.") creationStatus.icon = 'led_green' } onConferenceCreationFailed:{ console.log("Conference failed.") creationStatus.icon = 'led_red' } onInvitationsSent: { console.log("Conference => invitations sent. Check in log for invite states.") exit(1) } } readonly property int minParticipants: 1 buttons: [ ColumnLayout{ Layout.fillWidth: true Layout.topMargin:15 Layout.alignment: Qt.AlignLeft Layout.leftMargin: 15 spacing:4 visible: false // TODO Text { Layout.fillWidth: true //: 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. text:qsTr('askEncryption') color: NewConferenceStyle.askEncryptionColor font.pointSize: NewConferenceStyle.titles.pointSize font.weight: Font.DemiBold } Item{ Layout.fillWidth: true Layout.preferredHeight: 50 Icon{ id:secureOff anchors.left:parent.left anchors.leftMargin : 0 anchors.verticalCenter: parent.verticalCenter width:20 height:20 icon: 'secure_off' iconSize:20 } Switch{ id:secureSwitch anchors.left:secureOff.right anchors.leftMargin : 5 anchors.verticalCenter: parent.verticalCenter width:50 enabled:true checked: !SettingsModel.standardChatEnabled && SettingsModel.secureChatEnabled onClicked: { var newCheck = checked if(SettingsModel.standardChatEnabled && checked || SettingsModel.secureChatEnabled && !checked) newCheck = !checked; checked = newCheck; } indicatorStyle: SwitchStyle.aux } Icon{ id:secureOn anchors.left:secureSwitch.right anchors.leftMargin : 15 anchors.verticalCenter: parent.verticalCenter width:20 height:20 icon: 'secure_on' iconSize:20 } } }, TextButtonA { //: 'Cancel' : Cancel button text: qsTr('cancelButton') capitalization: Font.AllUppercase onClicked: exit(0) }, TextButtonB { enabled: selectedParticipants.count >= conferenceManager.minParticipants && subject.text != '' && AccountSettingsModel.conferenceURI != '' //: 'Launch' : Start button text: qsTr('startButton') capitalization: Font.AllUppercase function getInviteMode(){ //return inviteAppAccountCheckBox.checked ? LinphoneEnums:: return 0; } onClicked: { creationStatus.icon = 'led_orange' conferenceInfoModel.isScheduled = scheduledSwitch.checked if( scheduledSwitch.checked){ var startDateTime = Utils.buildDate(dateField.getDate(), timeField.getTime()) startDateTime.setSeconds(0) conferenceInfoModel.dateTime = startDateTime conferenceInfoModel.duration = durationField.text } conferenceInfoModel.subject = subject.text conferenceInfoModel.description = description.text conferenceInfoModel.setParticipants(selectedParticipants.participantListModel) //var callsWindow = App.getCallsWindow() //App.smartShowWindow(callsWindow) //callsWindow.openConference() //CallsListModel.createConference(conferenceInfoModel, secureSwitch.checked, getInviteMode(), false ) conferenceInfoModel.createConference(false && secureSwitch.checked, getInviteMode()) // TODO remove false when Encryption is ready to use } TooltipArea{ visible: AccountSettingsModel.conferenceURI == '' || subject.text == '' || selectedParticipants.count < conferenceManager.minParticipants maxWidth: participantView.width delay:0 text: { var txt = '\n'; if( subject.text == '') //: 'You need to fill a subject.' : Tooltip to warn a user on missing field. txt ='- ' + qsTr('missingSubject') + '\n' if( selectedParticipants.count < conferenceManager.minParticipants) //: 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. txt += '- ' + qsTr('missingParticipants', '', conferenceManager.minParticipants).arg(conferenceManager.minParticipants) + '\n' if( AccountSettingsModel.conferenceURI == '') //: 'You need to set the conference URI in your account settings to create a conference based chat room.' : Tooltip to warn the user that a setting is missong in its configuration. txt += '- ' + qsTr('missingConferenceURI') + '\n' return txt; } } } , Icon{ id: creationStatus height: 10 width: 10 visible: icon != '' icon: '' } ] buttonsAlignment: Qt.AlignRight buttonsLeftMargin: 15 //: 'Start a video conference' : Title of a popup about creation of a video conference title:qsTr('newConferenceTitle') height: window.height - 100 width: window.width - 100 expandHeight: true // --------------------------------------------------------------------------- RowLayout { height: parent.height width: parent.width spacing: 0 ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true Layout.topMargin: 10 spacing: 10 ColumnLayout { Layout.fillWidth: true Layout.rightMargin: 15 spacing:5 Text{ textFormat: Text.RichText //: 'Subject' : Label of a text field about the subject of the chat room text :qsTr('subjectLabel') +'*' color: NewConferenceStyle.titles.textColor font.pointSize: NewConferenceStyle.titles.pointSize font.weight: NewConferenceStyle.titles.weight } TextField { id:subject Layout.fillWidth: true //: 'Give a subject' : Placeholder in a form about setting a subject placeholderText : qsTr('subjectPlaceholder') text: conferenceInfoModel && conferenceInfoModel.subject || '' Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus() TooltipArea{ //: 'Current subject of the Chat Room. It cannot be empty' //~ Tooltip Explanation about the subject of the chat room text : qsTr('subjectTooltip') } } } Rectangle{ Layout.fillWidth: true Layout.preferredHeight: scheduledSwitch.checked ? 120 : 50 Layout.rightMargin: 15 color: '#F7F7F7' ColumnLayout{ anchors.fill: parent spacing: 0 RowLayout{ Layout.fillWidth: true Layout.preferredHeight: 50 Switch{ id:scheduledSwitch Layout.leftMargin : 5 Layout.alignment: Qt.AlignVCenter width:50 enabled: true checked: true onClicked: { checked = !checked } indicatorStyle: SwitchStyle.aux } Text { Layout.fillWidth: true Layout.rightMargin: 15 //: 'Would you like to schedule your conference?' : Ask about setting the conference as scheduled. text: 'Souhaitez-vous programmer cette conférence pour plus tard ?' color: NewConferenceStyle.titles.textColor font.pointSize: NewConferenceStyle.titles.pointSize font.weight: NewConferenceStyle.titles.weight wrapMode: Text.WordWrap } } GridLayout{ id: scheduleForm visible: scheduledSwitch.checked Layout.fillWidth: true Layout.fillHeight: true columns: 4 property var locale: Qt.locale() property date currentDate: new Date() property int cellWidth: (parent.width-15)/columns Component.onCompleted: scheduleForm.updateDateTime() Text{textFormat: Text.RichText; text: 'Date'+'*'; Layout.preferredWidth: parent.cellWidth; wrapMode: Text.WordWrap; color: NewConferenceStyle.titles.textColor; font.weight: NewConferenceStyle.titles.weight; font.pointSize: NewConferenceStyle.titles.pointSize } Text{textFormat: Text.RichText; text: 'Heure de début'+'*'; Layout.preferredWidth: parent.cellWidth; wrapMode: Text.WordWrap; color: NewConferenceStyle.titles.textColor; font.weight: NewConferenceStyle.titles.weight; font.pointSize: NewConferenceStyle.titles.pointSize } Text{textFormat: Text.RichText; text: 'Durée'; Layout.preferredWidth: parent.cellWidth; wrapMode: Text.WordWrap; color: NewConferenceStyle.titles.textColor; font.weight: NewConferenceStyle.titles.weight; font.pointSize: NewConferenceStyle.titles.pointSize } Text{textFormat: Text.RichText; text: 'Fuseau horaire'; Layout.preferredWidth: parent.cellWidth; wrapMode: Text.WordWrap; color: NewConferenceStyle.titles.textColor; font.weight: NewConferenceStyle.titles.weight; font.pointSize: NewConferenceStyle.titles.pointSize } TextField{id: dateField; Layout.preferredWidth: parent.cellWidth color: NewConferenceStyle.fields.textColor; font.weight: NewConferenceStyle.fields.weight; font.pointSize: NewConferenceStyle.fields.pointSize function getDate(){ return Date.fromLocaleDateString(scheduleForm.locale, text,'yyyy/MM/dd') } function setDate(date){ text = date.toLocaleDateString(scheduleForm.locale, 'yyyy/MM/dd') } MouseArea{ anchors.fill: parent onClicked: { if( rightStackView.currentItemType === 1) { rightStackView.currentItemType = 0 rightStackView.pop()// Cancel }else { if( rightStackView.depth > 1 ) rightStackView.pop()//Remove previous request rightStackView.currentItemType = 1 rightStackView.push(datePicker, {selectedDate: new Date(dateField.getDate())}) } } } } TextField{id: timeField; Layout.preferredWidth: parent.cellWidth color: NewConferenceStyle.fields.textColor; font.weight: NewConferenceStyle.fields.weight; font.pointSize: NewConferenceStyle.fields.pointSize function getTime(){ return Date.fromLocaleTimeString(scheduleForm.locale, timeField.text, 'hh:mm') } function setTime(date){ text = date.toLocaleTimeString(scheduleForm.locale, 'hh:mm') } MouseArea{ anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right width: parent.width-50 onClicked: { if( rightStackView.currentItemType === 2) { rightStackView.currentItemType = 0 rightStackView.pop()// Cancel }else { if( rightStackView.depth > 1 ) rightStackView.pop()//Remove previous request rightStackView.currentItemType = 2 rightStackView.push(timePicker,{selectedTime: new Date(timeField.getTime())}) } } } } NumericField{id: durationField; text: '1200'; Layout.preferredWidth: parent.cellWidth; color: NewConferenceStyle.fields.textColor; font.weight: NewConferenceStyle.fields.weight; font.pointSize: NewConferenceStyle.fields.pointSize} TextField{ text: 'Paris'; readOnly: true; Layout.preferredWidth: parent.cellWidth; color: NewConferenceStyle.fields.textColor; font.weight: NewConferenceStyle.fields.weight; font.pointSize: NewConferenceStyle.fields.pointSize} function updateDateTime(){ var storedDate if( dateField.text != '' && timeField.text != ''){ storedDate = Utils.buildDate(dateField.getDate(), timeField.getTime() ) }else storedDate = new Date() var currentDate = new Date() if(currentDate >= storedDate){ var nextStoredDate = UtilsCpp.addMinutes(new Date(), 1) dateField.setDate(nextStoredDate) timeField.setTime(nextStoredDate) } } Timer{ running: scheduleForm.visible repeat: true interval: 1000 onTriggered: { scheduleForm.updateDateTime() } } } } } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true Layout.rightMargin: 15 spacing:5 Text{ Layout.fillWidth: true Layout.preferredHeight: 20 textFormat: Text.RichText //: 'Add a description' : Label of a text field about the description of the conference text : 'Ajouter une description' color: NewConferenceStyle.titles.textColor font.pointSize: NewConferenceStyle.titles.pointSize font.weight: NewConferenceStyle.titles.weight } TextAreaField { id: description Layout.fillWidth: true Layout.fillHeight: true //: 'Description' : Placeholder in a form about setting a description placeholderText : 'Description' text: '' Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus() TooltipArea{ //: 'This description will describe the conference' : Explanation about the description of the conference text : 'This description will describe the conference' } } } ColumnLayout{ Layout.fillWidth: true //Layout.preferredHeight: 60 spacing: 5 CheckBoxText { id: inviteAppAccountCheckBox text: 'Envoyer l\'invitation via mon compte Linphone' width: parent.width checked: true onClicked: { console.log('Send invite with Linphone account: ' + checked) } } CheckBoxText { id: inviteEmailCheckBox visible: false // TODO text: 'Envoyer l\'invitation via mon adresse mail' width: parent.width onClicked: { console.log('Send invite with email: ' + checked) } } } } StackView{ id: rightStackView property int currentItemType: 0 Layout.fillHeight: true Layout.fillWidth: true Layout.minimumWidth: 200 Layout.topMargin: 10 Layout.bottomMargin: 10 clip: true // ------------------------------------------------------------------------- // See and remove selected addresses. // ------------------------------------------------------------------------- initialItem: ColumnLayout{ //anchors.fill: parent Rectangle{ Layout.fillHeight: true Layout.fillWidth: true border.width: 1 border.color: NewConferenceStyle.addressesBorderColor ColumnLayout { anchors.fill: parent anchors.topMargin: 15 anchors.leftMargin: 10 anchors.rightMargin: 10 spacing: 0 SmartSearchBar { id: smartSearchBar Layout.fillWidth: true Layout.topMargin: ConferenceManagerStyle.columns.selector.spacing showHeader:false maxMenuHeight: MainWindowStyle.searchBox.maxHeight //: 'Select participants' : Placeholder for a search on participant to add them in selection. placeholderText: qsTr('participantSelectionPlaceholder') //: 'Search in your contacts or add a custom one to the chat room.' tooltipText: qsTr('participantSelectionTooltip') actions:[{ colorSet: NewConferenceStyle.addParticipant, secure: secureSwitch.checked, visible: true, secureIconVisibleHandler : function(entry) { return UtilsCpp.hasCapability(entry.sipAddress, LinphoneEnums.FriendCapabilityLimeX3Dh) }, handler: function (entry) { selectedParticipants.addAddress(entry.sipAddress) smartSearchBar.addAddressToIgnore(entry.sipAddress); }, }] onEntryClicked: { selectedParticipants.addAddress(entry.sipAddress) smartSearchBar.addAddressToIgnore(entry.sipAddress); } } Text{ Layout.preferredHeight: 20 Layout.rightMargin: 65 Layout.alignment: Qt.AlignRight | Qt.AlignBottom Layout.topMargin: ConferenceManagerStyle.columns.selector.spacing //: 'Admin' : Admin(istrator) //~ one word for admin status text : qsTr('adminStatus') color: NewConferenceStyle.addressesAdminColor font.pointSize: Units.dp * 11 font.weight: Font.Light visible: participantView.count > 0 } ScrollableListViewField { Layout.fillHeight: true Layout.fillWidth: true Layout.bottomMargin: 5 textFieldStyle: TextFieldStyle.unbordered ParticipantsView { id: participantView anchors.fill: parent showContactAddress:false showSwitch : true showSeparator: false isSelectable: false showInvitingIndicator: false function removeParticipant(entry){ smartSearchBar.removeAddressToIgnore(entry.sipAddress) selectedParticipants.removeModel(entry) ++lastContacts.reloadCount } actions: [{ colorSet: NewConferenceStyle.removeParticipant, secure:0, visible:true, //: 'Remove this participant from the selection' : Explanation about removing participant from a selection //~ Tooltip This is a tooltip tooltipText: qsTr('removeParticipantSelection'), handler: function (entry) { removeParticipant(entry) } }] genSipAddress: '' model: ParticipantProxyModel { id:selectedParticipants chatRoomModel:null } onEntryClicked: actions[0].handler(entry) } } } } Item{ Layout.fillWidth: true Layout.preferredHeight: 20 Text{ anchors.fill:parent textFormat: Text.RichText //: 'Required' : Word relative to a star to explain that it is a requirement (Field form) text : '* '+qsTr('requiredField') //font.weight: Font.DemiBold color: NewConferenceStyle.requiredColor font.pointSize: Units.dp * 8 } } } //---------------------------------------------------- // STACKVIEWS //---------------------------------------------------- Component{ id: datePicker DatePicker{ onClicked: { dateField.setDate(date) rightStackView.currentItemType = 0 rightStackView.pop() } } } Component{ id: timePicker TimePicker{ onClicked: { timeField.setTime(date) rightStackView.currentItemType = 0 rightStackView.pop() } } } } } }