client-qml: add initial commit
Change-Id: I32bfdd2a618aa7ac6181da2697e241667b010aab
diff --git a/src/settingsview/components/AdvancedSIPSettingsView.qml b/src/settingsview/components/AdvancedSIPSettingsView.qml
new file mode 100644
index 0000000..5ebcf84
--- /dev/null
+++ b/src/settingsview/components/AdvancedSIPSettingsView.qml
@@ -0,0 +1,2554 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Dialogs 1.3
+import Qt.labs.platform 1.1
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+ColumnLayout {
+ function updateAccountInfoDisplayedAdvanceSIP(){
+ // Call Settings
+ checkBoxAutoAnswerSIP.checked = ClientWrapper.settingsAdaptor.getAccountConfig_AutoAnswer()
+ checkBoxCustomRingtoneSIP.checked = ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtoneEnabled()
+
+ // security
+ btnSIPCACert.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_Enable()
+ btnSIPUserCert.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_Enable()
+ btnSIPPrivateKey.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_Enable()
+ lineEditSIPCertPassword.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_Enable()
+ enableSDESToggle.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_SRTP_Enabled()
+ fallbackRTPToggle.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_SRTP_Enabled()
+
+ btnSIPCACert.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateListFile())
+ btnSIPUserCert.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateFile())
+ btnSIPPrivateKey.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_PrivateKeyFile())
+ lineEditSIPCertPassword.text = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_Password()
+
+ encryptMediaStreamsToggle.checked = ClientWrapper.settingsAdaptor.getAccountConfig_SRTP_Enabled()
+ enableSDESToggle.checked = (ClientWrapper.settingsAdaptor.getAccountConfig_SRTP_KeyExchange() === Account.KeyExchangeProtocol.SDES)
+ fallbackRTPToggle.checked = ClientWrapper.settingsAdaptor.getAccountConfig_SRTP_RtpFallback()
+ encryptNegotitationToggle.checked = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_Enable()
+ verifyIncomingCertificatesServerToogle.checked = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_VerifyServer()
+ verifyIncomingCertificatesClientToogle.checked = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_VerifyClient()
+ requireCeritificateForTLSIncomingToggle.checked = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_RequireClientCertificate()
+
+ var method = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_Method_inInt()
+ tlsProtocolComboBox.currentIndex = method
+
+ outgoingTLSServerNameLineEdit.text = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_Servername()
+ negotiationTimeoutSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_TLS_NegotiationTimeoutSec()
+
+ // Connectivity
+ checkBoxUPnPSIP.checked = ClientWrapper.settingsAdaptor.getAccountConfig_UpnpEnabled()
+ checkBoxTurnEnableSIP.checked = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Enabled()
+ lineEditTurnAddressSIP.text = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Server()
+ lineEditTurnUsernameSIP.text = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Username()
+ lineEditTurnPsswdSIP.text = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Password()
+ lineEditTurnRealmSIP.text = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Realm()
+ lineEditTurnAddressSIP.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Enabled()
+ lineEditTurnUsernameSIP.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Enabled()
+ lineEditTurnPsswdSIP.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Enabled()
+ lineEditTurnRealmSIP.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Enabled()
+
+ checkBoxSTUNEnableSIP.checked = ClientWrapper.settingsAdaptor.getAccountConfig_STUN_Enabled()
+ lineEditSTUNAddressSIP.text = ClientWrapper.settingsAdaptor.getAccountConfig_STUN_Server()
+ lineEditSTUNAddressSIP.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_STUN_Enabled()
+
+ registrationExpireTimeoutSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Registration_Expire()
+ networkInterfaceSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Localport()
+
+ // published address
+ checkBoxCustomAddressPort.checked = ClientWrapper.settingsAdaptor.getAccountConfig_PublishedSameAsLocal()
+ lineEditSIPCustomAddress.text = ClientWrapper.settingsAdaptor.getAccountConfig_PublishedAddress()
+ customPortSIPSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_PublishedPort()
+
+ // codecs
+ videoCheckBoxSIP.checked = ClientWrapper.settingsAdaptor.getAccountConfig_Video_Enabled()
+ updateAudioCodecs()
+ updateVideoCodecs()
+ btnRingtoneSIP.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtoneEnabled()
+ btnRingtoneSIP.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtonePath())
+ lineEditSTUNAddressSIP.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_STUN_Enabled()
+
+ // SDP session negotiation ports
+ audioRTPMinPortSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Audio_AudioPortMin()
+ audioRTPMaxPortSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Audio_AudioPortMax()
+ videoRTPMinPortSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Video_VideoPortMin()
+ videoRTPMaxPortSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Video_VideoPortMax()
+
+ // voicemail
+ lineEditVoiceMailDialCode.text = ClientWrapper.settingsAdaptor.getAccountConfig_Mailbox()
+ }
+
+ function updateAudioCodecs(){
+ audioCodecListModelSIP.layoutAboutToBeChanged()
+ audioCodecListModelSIP.dataChanged(audioCodecListModelSIP.index(0, 0),
+ audioCodecListModelSIP.index(audioCodecListModelSIP.rowCount() - 1, 0))
+ audioCodecListModelSIP.layoutChanged()
+ }
+
+ function updateVideoCodecs(){
+ videoCodecListModelSIP.layoutAboutToBeChanged()
+ videoCodecListModelSIP.dataChanged(videoCodecListModelSIP.index(0, 0),
+ videoCodecListModelSIP.index(videoCodecListModelSIP.rowCount() - 1, 0))
+ videoCodecListModelSIP.layoutChanged()
+ }
+
+ function decreaseAudioCodecPriority(){
+ var index = audioListWidgetSIP.currentIndex
+ var codecId = audioCodecListModelSIP.data(audioCodecListModelSIP.index(index,0), AudioCodecListModel.AudioCodecID)
+
+ ClientWrapper.settingsAdaptor.decreaseAudioCodecPriority(codecId)
+ audioListWidgetSIP.currentIndex = index + 1
+ updateAudioCodecs()
+ }
+
+ function increaseAudioCodecPriority(){
+ var index = audioListWidgetSIP.currentIndex
+ var codecId = audioCodecListModelSIP.data(audioCodecListModelSIP.index(index,0), AudioCodecListModel.AudioCodecID)
+
+ ClientWrapper.settingsAdaptor.increaseAudioCodecPriority(codecId)
+ audioListWidgetSIP.currentIndex = index - 1
+ updateAudioCodecs()
+ }
+
+ function decreaseVideoCodecPriority(){
+ var index = videoListWidgetSIP.currentIndex
+ var codecId = videoCodecListModelSIP.data(videoCodecListModelSIP.index(index,0), VideoCodecListModel.VideoCodecID)
+
+ ClientWrapper.settingsAdaptor.decreaseVideoCodecPriority(codecId)
+ videoListWidgetSIP.currentIndex = index + 1
+ updateVideoCodecs()
+ }
+
+ function increaseVideoCodecPriority(){
+ var index = videoListWidgetSIP.currentIndex
+ var codecId = videoCodecListModelSIP.data(videoCodecListModelSIP.index(index,0), VideoCodecListModel.VideoCodecID)
+
+ ClientWrapper.settingsAdaptor.increaseVideoCodecPriority(codecId)
+ videoListWidgetSIP.currentIndex = index - 1
+ updateVideoCodecs()
+ }
+
+ VideoCodecListModel{
+ id: videoCodecListModelSIP
+ }
+
+ AudioCodecListModel{
+ id: audioCodecListModelSIP
+ }
+
+
+ // slots
+ function audioRTPMinPortSpinBoxEditFinished(value){
+ if (ClientWrapper.settingsAdaptor.getAccountConfig_Audio_AudioPortMax() < value) {
+ audioRTPMinPortSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Audio_AudioPortMin()
+ return
+ }
+ ClientWrapper.settingsAdaptor.audioRTPMinPortSpinBoxEditFinished(value)
+ }
+
+ function audioRTPMaxPortSpinBoxEditFinished(value){
+ if (value < ClientWrapper.settingsAdaptor.getAccountConfig_Audio_AudioPortMin()) {
+ audioRTPMaxPortSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Audio_AudioPortMax()
+ return
+ }
+ ClientWrapper.settingsAdaptor.audioRTPMaxPortSpinBoxEditFinished(value)
+ }
+
+ function videoRTPMinPortSpinBoxEditFinished(value){
+ if (ClientWrapper.settingsAdaptor.getAccountConfig_Video_VideoPortMax() < value) {
+ videoRTPMinPortSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Video_VideoPortMin()
+ return
+ }
+ ClientWrapper.settingsAdaptor.videoRTPMinPortSpinBoxEditFinished(value)
+ }
+
+ function videoRTPMaxPortSpinBoxEditFinished(value){
+ if (value < ClientWrapper.settingsAdaptor.getAccountConfig_Video_VideoPortMin()) {
+ videoRTPMinPortSpinBox.value = ClientWrapper.settingsAdaptor.getAccountConfig_Video_VideoPortMin()
+ return
+ }
+ ClientWrapper.settingsAdaptor.videoRTPMaxPortSpinBoxEditFinished(value)
+ }
+
+
+ function changeRingtonePath(url){
+ if(url.length !== 0) {
+ ClientWrapper.settingsAdaptor.set_RingtonePath(url)
+ btnRingtoneSIP.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtonePath())
+ } else if (ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtonePath().length === 0){
+ btnRingtoneSIP.text = qsTr("Add a custom ringtone")
+ }
+ }
+
+ function changeFileCACert(url){
+ if(url.length !== 0) {
+ ClientWrapper.settingsAdaptor.set_FileCACert(url)
+ btnSIPCACert.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateListFile())
+ }
+ }
+
+ function changeFileUserCert(url){
+ if(url.length !== 0) {
+ ClientWrapper.settingsAdaptor.set_FileUserCert(url)
+ btnSIPUserCert.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateFile())
+ }
+ }
+
+ function changeFilePrivateKey(url){
+ if(url.length !== 0) {
+ ClientWrapper.settingsAdaptor.set_FilePrivateKey(url)
+ btnSIPPrivateKey.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_PrivateKeyFile())
+ }
+ }
+
+ JamiFileDialog {
+ id: ringtonePath_Dialog_SIP
+
+ property string oldPath : ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtonePath()
+ property string openPath : oldPath === "" ? (ClientWrapper.utilsAdaptor.getCurrentPath() + "/ringtones/") : (ClientWrapper.utilsAdaptor.toFileAbsolutepath(oldPath))
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select a new ringtone")
+ folder: openPath
+
+ nameFilters: [qsTr("Audio Files") + " (*.wav *.ogg *.opus *.mp3 *.aiff *.wma)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ changeRingtonePath(url)
+ }
+ }
+
+ JamiFileDialog {
+ id: caCert_Dialog_SIP
+
+ property string oldPath : ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateListFile()
+ property string openPath : oldPath === "" ? (ClientWrapper.utilsAdaptor.getCurrentPath() + "/ringtones/") : (ClientWrapper.utilsAdaptor.toFileAbsolutepath(oldPath))
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select a CA certificate")
+ folder: openPath
+ nameFilters: [qsTr("Certificate File") + " (*.crt)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ changeFileCACert(url)
+ }
+ }
+
+ JamiFileDialog {
+ id: userCert_Dialog_SIP
+
+ property string oldPath : ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateFile()
+ property string openPath : oldPath === "" ? (ClientWrapper.utilsAdaptor.getCurrentPath() + "/ringtones/") : (ClientWrapper.utilsAdaptor.toFileAbsolutepath(oldPath))
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select a user certificate")
+ folder: openPath
+ nameFilters: [qsTr("Certificate File") + " (*.crt)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ changeFileUserCert(url)
+ }
+ }
+
+ JamiFileDialog {
+ id: privateKey_Dialog_SIP
+
+ property string oldPath : ClientWrapper.settingsAdaptor.getAccountConfig_TLS_PrivateKeyFile()
+ property string openPath : oldPath === "" ? (ClientWrapper.utilsAdaptor.getCurrentPath() + "/ringtones/") : (ClientWrapper.utilsAdaptor.toFileAbsolutepath(oldPath))
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select a private key")
+ folder: openPath
+ nameFilters: [qsTr("Key File") + " (*.key)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ changeFilePrivateKey(url)
+ }
+ }
+
+ spacing: 6
+ Layout.preferredWidth: 532
+ Layout.maximumWidth: 532
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 24
+ Layout.preferredHeight: 24
+ Layout.maximumHeight: 24
+ }
+
+ // call setting section
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Call Settings")
+
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+
+ ToggleSwitch {
+ id: checkBoxAutoAnswerSIP
+ labelText: qsTr("Auto Answer Call")
+ fontPointSize: 10
+
+ Layout.leftMargin: 20
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setAutoAnswerCalls(checked)
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+ Layout.maximumHeight: 30
+
+ ToggleSwitch {
+ id: checkBoxCustomRingtoneSIP
+ labelText: qsTr("Enable Custom Ringtone")
+ fontPointSize: 10
+
+ Layout.maximumWidth: 164
+ Layout.preferredWidth: 164
+ Layout.minimumWidth: 164
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setEnableRingtone(checked)
+ btnRingtoneSIP.enabled = checked
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ HoverableRadiusButton {
+ id: btnRingtoneSIP
+
+ radius: height / 2
+
+ Layout.maximumWidth: 164
+ Layout.preferredWidth: 164
+ Layout.minimumWidth: 164
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.width: 16
+ icon.height: 16
+
+ onClicked: {
+ ringtonePath_Dialog_SIP.open()
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ // voice mail section
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Voicemail")
+
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 13
+ Layout.preferredHeight: 13
+ Layout.maximumHeight: 13
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.maximumWidth: 162
+ Layout.preferredWidth: 162
+ Layout.minimumWidth: 162
+
+ Layout.minimumHeight: 28
+ Layout.preferredHeight: 28
+ Layout.maximumHeight: 28
+
+ text: qsTr("Voicemail Dial Code")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ InfoLineEdit {
+ id: lineEditVoiceMailDialCode
+
+ fieldLayoutWidth: 250
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.lineEditVoiceMailDialCodeEditFinished(text)
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ // security section
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Security")
+
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 13
+ Layout.preferredHeight: 13
+ Layout.minimumHeight: 13
+ }
+
+ GridLayout {
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+
+ rowSpacing: 6
+ columnSpacing: 6
+
+ rows: 14
+ columns: 3
+
+ // First row
+ ToggleSwitch{
+ id: encryptMediaStreamsToggle
+
+ labelText: qsTr("Encrypt Media Streams(SRTP)")
+ fontPointSize: 10
+
+ Layout.row: 0
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseSRTP(checked)
+ enableSDESToggle.enabled = checked
+ fallbackRTPToggle.enabled = checked
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 0
+ Layout.column: 1
+ }
+
+ // second row
+ ToggleSwitch{
+ id: enableSDESToggle
+
+ labelText: qsTr("Enable SDES(Key Exchange)")
+ fontPointSize: 10
+
+ Layout.row: 1
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseSDES(checked)
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 1
+ Layout.column: 1
+ }
+
+ // third row
+ ToggleSwitch{
+ id: fallbackRTPToggle
+
+ labelText: qsTr("Can Fallback on RTP")
+ fontPointSize: 10
+
+ Layout.row: 2
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseRTPFallback(checked)
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 2
+ Layout.column: 1
+ }
+
+ // fourth row
+ ToggleSwitch{
+ id: encryptNegotitationToggle
+
+ labelText: qsTr("Encrypt Negotiation(TLS)")
+ fontPointSize: 10
+
+ Layout.row: 3
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseTLS(checked)
+ btnSIPCACert.enabled = checked
+ btnSIPUserCert.enabled = checked
+ btnSIPPrivateKey.enabled = checked
+ lineEditSIPCertPassword.enabled = checked
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 3
+ Layout.column: 1
+ }
+
+ // fifth row
+ RowLayout{
+ spacing: 6
+ Layout.maximumHeight: 30
+
+ Layout.row: 4
+ Layout.column: 0
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label{
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ Layout.maximumWidth: 209
+ Layout.preferredWidth: 209
+ Layout.minimumWidth: 209
+
+ text: qsTr("CA Certificate")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 4
+ Layout.column: 1
+ }
+
+ HoverableRadiusButton{
+ id: btnSIPCACert
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ Layout.maximumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.minimumWidth: 250
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.width: 16
+ icon.height: 16
+
+ Layout.row: 4
+ Layout.column: 2
+
+ onClicked: {
+ caCert_Dialog_SIP.open()
+ }
+ }
+
+ // sixth row
+ RowLayout{
+ spacing: 6
+ Layout.maximumHeight: 30
+
+ Layout.row: 5
+ Layout.column: 0
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label{
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ Layout.maximumWidth: 209
+ Layout.preferredWidth: 209
+ Layout.minimumWidth: 209
+
+ text: qsTr("User Certificate")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 5
+ Layout.column: 1
+ }
+
+ HoverableRadiusButton{
+ id: btnSIPUserCert
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ Layout.maximumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.minimumWidth: 250
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.width: 16
+ icon.height: 16
+
+ Layout.row: 5
+ Layout.column: 2
+
+ onClicked: {
+ userCert_Dialog_SIP.open()
+ }
+ }
+
+ // seventh row
+ RowLayout{
+ spacing: 6
+ Layout.maximumHeight: 30
+
+ Layout.row: 6
+ Layout.column: 0
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label{
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ Layout.maximumWidth: 209
+ Layout.preferredWidth: 209
+ Layout.minimumWidth: 209
+
+ text: qsTr("Private Key")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 6
+ Layout.column: 1
+ }
+
+ HoverableRadiusButton{
+ id: btnSIPPrivateKey
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ Layout.maximumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.minimumWidth: 250
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.width: 16
+ icon.height: 16
+
+ Layout.row: 6
+ Layout.column: 2
+
+ onClicked: {
+ privateKey_Dialog_SIP.open()
+ }
+ }
+
+ // eight row
+ RowLayout{
+ spacing: 6
+ Layout.maximumHeight: 30
+
+ Layout.row: 7
+ Layout.column: 0
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label{
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ Layout.maximumWidth: 209
+ Layout.preferredWidth: 209
+ Layout.minimumWidth: 209
+
+ text: qsTr("Private Key Password")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 7
+ Layout.column: 1
+ }
+
+ InfoLineEdit {
+ id: lineEditSIPCertPassword
+
+ Layout.alignment: Qt.AlignCenter
+
+ fieldLayoutWidth: 250
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ echoMode: TextInput.Password
+
+ Layout.row: 7
+ Layout.column: 2
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.lineEditSIPCertPasswordLineEditTextChanged(text)
+ }
+ }
+
+ // nineth row
+ ToggleSwitch{
+ id: verifyIncomingCertificatesServerToogle
+
+ labelText: qsTr("Verify Certificates(Server Side)")
+ fontPointSize: 10
+
+ Layout.row: 8
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setVerifyCertificatesServer(checked)
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 8
+ Layout.column: 1
+ }
+
+ // tenth row
+ ToggleSwitch{
+ id: verifyIncomingCertificatesClientToogle
+
+ labelText: qsTr("Verify Certificates(Client Side)")
+ fontPointSize: 10
+
+ Layout.row: 9
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setVerifyCertificatesClient(checked)
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 9
+ Layout.column: 1
+ }
+
+ //eleventh row
+ ToggleSwitch{
+ id: requireCeritificateForTLSIncomingToggle
+
+ labelText: qsTr("TLS Connections Require Certificate")
+ fontPointSize: 10
+
+ Layout.row: 10
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setRequireCertificatesIncomingTLS(checked)
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row:10
+ Layout.column: 1
+ }
+
+ // twelveth row
+ Label{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ text: qsTr("TLS Protocol Method")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 11
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 11
+ Layout.column: 1
+ }
+
+ SettingParaCombobox{
+ id:tlsProtocolComboBox
+
+ Layout.maximumWidth: 252
+ Layout.preferredWidth: 252
+ Layout.minimumWidth: 252
+
+ Layout.maximumHeight: 29
+ Layout.minimumHeight: 29
+ Layout.preferredHeight: 29
+
+ Layout.alignment: Qt.AlignCenter
+
+ font.pointSize: 10
+ font.kerning: true
+
+ Layout.row: 11
+ Layout.column: 2
+
+ textRole: "textDisplay"
+
+ model: ListModel{
+ ListElement{textDisplay: "Default"; firstArg: "Default"; secondArg: 0}
+ ListElement{textDisplay: "TLSv1"; firstArg: "TLSv1"; secondArg: 1}
+ ListElement{textDisplay: "TLSv1.1"; firstArg: "TLSv1.1"; secondArg: 2}
+ ListElement{textDisplay: "TLSv1.2"; firstArg: "TLSv1.2"; secondArg: 3}
+ }
+
+ onActivated: {
+ var indexOfOption = tlsProtocolComboBox.model.get(index).secondArg
+ ClientWrapper.settingsAdaptor.tlsProtocolComboBoxIndexChanged(parseInt(indexOfOption))
+ }
+ }
+
+ // 13th row
+ Label{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ text: qsTr("Outgoing TLS Server Name")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 12
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 12
+ Layout.column: 1
+ }
+
+ InfoLineEdit {
+ id: outgoingTLSServerNameLineEdit
+
+ Layout.alignment: Qt.AlignCenter
+
+ fieldLayoutWidth: 250
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 12
+ Layout.column: 2
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.outgoingTLSServerNameLineEditTextChanged(text)
+ }
+ }
+
+ // 14th row
+ Label{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ text: qsTr("Negotiation Timeout(seconds)")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 13
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 13
+ Layout.column: 1
+ }
+
+ SpinBox{
+ id:negotiationTimeoutSpinBox
+
+ Layout.maximumWidth: 252
+ Layout.preferredWidth: 252
+ Layout.minimumWidth: 252
+
+ Layout.maximumHeight: 30
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+
+ Layout.alignment: Qt.AlignCenter
+
+ font.pointSize: 10
+ font.kerning: true
+
+ from: 0
+ to: 3000
+ stepSize: 1
+
+ Layout.row: 13
+ Layout.column: 2
+
+ onValueModified: {
+ ClientWrapper.settingsAdaptor.negotiationTimeoutSpinBoxValueChanged(value)
+ }
+ }
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ // connectivity section
+ ColumnLayout{
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Connectivity")
+
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.minimumHeight: 10
+ }
+
+ GridLayout{
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+
+ rowSpacing: 6
+ columnSpacing: 6
+
+ rows: 9
+ columns: 3
+
+ // 1st row
+ Label{
+ Layout.minimumWidth: 286
+ Layout.preferredWidth: 286
+
+ Layout.minimumHeight: 28
+ Layout.preferredHeight: 28
+ Layout.maximumHeight: 28
+
+ text: qsTr("Registration Expire Timeout(seconds)")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 0
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 0
+ Layout.column: 1
+ }
+
+ SpinBox{
+ id: registrationExpireTimeoutSpinBox
+
+ Layout.maximumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.minimumWidth: 250
+
+ Layout.maximumHeight: 30
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+
+ Layout.alignment: Qt.AlignCenter
+
+ font.pointSize: 10
+ font.kerning: true
+
+ from: 0
+ to: 3000
+ stepSize: 1
+
+ Layout.row: 0
+ Layout.column: 2
+
+ onValueModified: {
+ ClientWrapper.settingsAdaptor.registrationTimeoutSpinBoxValueChanged(value)
+ }
+ }
+
+ // 2nd row
+ Label{
+ Layout.minimumWidth: 286
+ Layout.preferredWidth: 286
+
+ Layout.minimumHeight: 28
+ Layout.preferredHeight: 28
+ Layout.maximumHeight: 28
+
+ text: qsTr("Newtwork interface")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 1
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 1
+ Layout.column: 1
+ }
+
+ SpinBox{
+ id: networkInterfaceSpinBox
+
+ Layout.maximumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.minimumWidth: 250
+
+ Layout.maximumHeight: 30
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+
+ Layout.alignment: Qt.AlignCenter
+
+ font.pointSize: 10
+ font.kerning: true
+
+ from: 0
+ to: 65536
+ stepSize: 1
+
+ Layout.row: 1
+ Layout.column: 2
+
+ onValueModified: {
+ ClientWrapper.settingsAdaptor.networkInterfaceSpinBoxValueChanged(value)
+ }
+ }
+
+ // 3rd row
+ ToggleSwitch{
+ id: checkBoxUPnPSIP
+
+ labelText: qsTr("Use UPnP")
+ fontPointSize: 10
+
+ Layout.row: 2
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseUPnP(checked)
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 2
+ Layout.column: 1
+ }
+
+ // 4th row
+ ToggleSwitch{
+ id: checkBoxTurnEnableSIP
+
+ labelText: qsTr("Use TURN")
+ fontPointSize: 10
+
+ Layout.row: 3
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseTURN(checked)
+ lineEditTurnAddressSIP.enabled = checked
+ lineEditTurnUsernameSIP.enabled = checked
+ lineEditTurnPsswdSIP.enabled = checked
+ lineEditTurnRealmSIP.enabled = checked
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 3
+ Layout.column: 1
+ }
+
+ // 5th row
+ RowLayout{
+ spacing: 6
+ Layout.maximumHeight: 30
+
+ Layout.row: 4
+ Layout.column: 0
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label{
+ Layout.maximumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.minimumHeight: 27
+
+ Layout.maximumWidth: 260
+ Layout.preferredWidth: 260
+ Layout.minimumWidth: 260
+
+ text: qsTr("TURN Address")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 4
+ Layout.column: 1
+ }
+
+
+ InfoLineEdit {
+ id: lineEditTurnAddressSIP
+
+ Layout.alignment: Qt.AlignCenter
+
+ fieldLayoutWidth: 250
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 4
+ Layout.column: 2
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setTURNAddress(text)
+ }
+ }
+
+ // 6th row
+ RowLayout{
+ spacing: 6
+ Layout.maximumHeight: 30
+
+ Layout.row: 5
+ Layout.column: 0
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label{
+ Layout.maximumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.minimumHeight: 27
+
+ Layout.maximumWidth: 260
+ Layout.preferredWidth: 260
+ Layout.minimumWidth: 260
+
+ text: qsTr("TURN Username")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 5
+ Layout.column: 1
+ }
+
+ InfoLineEdit {
+ id: lineEditTurnUsernameSIP
+
+ Layout.alignment: Qt.AlignCenter
+
+ fieldLayoutWidth: 250
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 5
+ Layout.column: 2
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setTURNUsername(text)
+ }
+ }
+
+ // 7th row
+ RowLayout{
+ spacing: 6
+ Layout.maximumHeight: 30
+
+ Layout.row: 6
+ Layout.column: 0
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label{
+ Layout.maximumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.minimumHeight: 27
+
+ Layout.maximumWidth: 260
+ Layout.preferredWidth: 260
+ Layout.minimumWidth: 260
+
+ text: qsTr("TURN Password")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 6
+ Layout.column: 1
+ }
+
+ InfoLineEdit {
+ id: lineEditTurnPsswdSIP
+
+ Layout.alignment: Qt.AlignCenter
+
+ fieldLayoutWidth: 250
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 6
+ Layout.column: 2
+
+ echoMode: TextInput.Password
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setTURNPassword(text)
+ }
+ }
+
+ // 8th row
+ RowLayout{
+ spacing: 6
+ Layout.maximumHeight: 30
+
+ Layout.row: 7
+ Layout.column: 0
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label{
+ Layout.maximumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.minimumHeight: 27
+
+ Layout.maximumWidth: 260
+ Layout.preferredWidth: 260
+ Layout.minimumWidth: 260
+
+ text: qsTr("TURN Realm")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 7
+ Layout.column: 1
+ }
+
+ InfoLineEdit {
+ id: lineEditTurnRealmSIP
+
+ Layout.alignment: Qt.AlignCenter
+
+ fieldLayoutWidth: 250
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 7
+ Layout.column: 2
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setTURNRealm(text)
+ }
+ }
+
+ // 9th row
+ ToggleSwitch{
+ id: checkBoxSTUNEnableSIP
+
+ labelText: qsTr("Use STUN")
+ fontPointSize: 10
+
+ Layout.row: 8
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseSTUN(checked)
+ lineEditSTUNAddressSIP.enabled = checked
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.row: 8
+ Layout.column: 1
+ }
+
+ InfoLineEdit {
+ id: lineEditSTUNAddressSIP
+
+ Layout.alignment: Qt.AlignCenter
+
+ fieldLayoutWidth: 250
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 8
+ Layout.column: 2
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setSTUNAddress(text)
+ }
+ }
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ // public address section
+ ColumnLayout{
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Public Address")
+
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.minimumHeight: 10
+ }
+
+ GridLayout{
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+
+ rowSpacing: 6
+ columnSpacing: 6
+
+ rows: 3
+ columns: 3
+
+ // 1st row
+ ToggleSwitch{
+ id: checkBoxCustomAddressPort
+
+ Layout.maximumWidth: 88
+ labelText: qsTr("Use Custom Address/Port")
+ fontPointSize: 10
+
+ Layout.row: 0
+ Layout.column: 0
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseCustomAddressAndPort(checked)
+ lineEditSIPCustomAddress.enabled = checked
+ customPortSIPSpinBox.enabled = checked
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.row: 0
+ Layout.column: 1
+ }
+
+ //2nd row
+ Label{
+ Layout.leftMargin: 26
+
+ Layout.maximumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.minimumHeight: 27
+
+ Layout.maximumWidth: 60
+ Layout.preferredWidth: 60
+ Layout.minimumWidth: 60
+
+ text: qsTr("Address")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 1
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.row: 1
+ Layout.column: 1
+ }
+
+ InfoLineEdit {
+ id: lineEditSIPCustomAddress
+
+ Layout.alignment: Qt.AlignCenter
+
+ fieldLayoutWidth: 250
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 1
+ Layout.column: 2
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.lineEditSIPCustomAddressLineEditTextChanged(text)
+ }
+ }
+
+ //3rd row
+ Label{
+ Layout.leftMargin: 26
+
+ Layout.maximumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.minimumHeight: 27
+
+ Layout.maximumWidth: 60
+ Layout.preferredWidth: 60
+ Layout.minimumWidth: 60
+
+ text: qsTr("Port")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 2
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.row: 2
+ Layout.column: 1
+ }
+
+ SpinBox{
+ id: customPortSIPSpinBox
+
+ Layout.maximumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.minimumWidth: 250
+
+ Layout.maximumHeight: 30
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+
+ Layout.alignment: Qt.AlignCenter
+
+ font.pointSize: 10
+ font.kerning: true
+
+ from: 0
+ to: 65535
+ stepSize: 1
+
+ Layout.row: 2
+ Layout.column: 2
+
+ onValueModified: {
+ ClientWrapper.settingsAdaptor.customPortSIPSpinBoxValueChanged(value)
+ }
+ }
+ }
+ }
+
+ // media section
+ ColumnLayout{
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Media")
+
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.minimumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ ToggleSwitch {
+ id: videoCheckBoxSIP
+
+ Layout.leftMargin: 20
+
+ labelText: qsTr("Enable Video")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setVideoState(checked)
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+
+ ColumnLayout {
+ spacing: 6
+ Layout.maximumWidth: 348
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Video Codecs")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.minimumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.maximumWidth: 20
+ }
+
+ HoverableRadiusButton {
+ id: videoDownPushButtonSIP
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+ scale: 1
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ font.pointSize: 9
+ font.kerning: true
+
+ icon.source: "qrc:/images/icons/round-arrow_drop_down-24px.svg"
+ icon.width: 32
+ icon.height: 32
+
+ onClicked: {
+ decreaseVideoCodecPriority()
+ }
+ }
+
+ HoverableRadiusButton {
+ id: videoUpPushButtonSIP
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ font.pointSize: 9
+ font.kerning: true
+
+ icon.source: "qrc:/images/icons/round-arrow_drop_up-24px.svg"
+ icon.width: 32
+ icon.height: 32
+
+ onClicked: {
+ increaseVideoCodecPriority()
+ }
+ }
+ }
+
+ ListViewJami {
+ id: videoListWidgetSIP
+
+ Layout.minimumWidth: 348
+ Layout.preferredWidth: 348
+ Layout.maximumWidth: 348
+
+ Layout.minimumHeight: 192
+ Layout.preferredHeight: 192
+ Layout.maximumHeight: 192
+
+ model: videoCodecListModelSIP
+
+ delegate: VideoCodecDelegate {
+ id: videoCodecDelegate
+
+ width: videoListWidgetSIP.width
+ height: videoListWidgetSIP.height / 4
+
+ videoCodecName : VideoCodecName
+ isEnabled : IsEnabled
+ videoCodecId: VideoCodecID
+
+ onClicked: {
+ videoListWidgetSIP.currentIndex = index
+ }
+
+ onVideoCodecStateChange:{
+ ClientWrapper.settingsAdaptor.videoCodecsStateChange(idToSet , isToBeEnabled)
+ updateVideoCodecs()
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.maximumWidth: 348
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Audio Codecs")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.minimumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.maximumWidth: 20
+ }
+
+ HoverableRadiusButton {
+ id: audioDownPushButtonSIP
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ font.pointSize: 9
+ font.kerning: true
+
+ icon.source: "qrc:/images/icons/round-arrow_drop_down-24px.svg"
+ icon.width: 32
+ icon.height: 32
+
+ onClicked: {
+ decreaseAudioCodecPriority()
+ }
+ }
+
+ HoverableRadiusButton {
+ id: audioUpPushButtonSIP
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ font.pointSize: 9
+ font.kerning: true
+
+ icon.source: "qrc:/images/icons/round-arrow_drop_up-24px.svg"
+ icon.width: 32
+ icon.height: 32
+
+ onClicked: {
+ increaseAudioCodecPriority()
+ }
+ }
+ }
+
+ ListViewJami {
+ id: audioListWidgetSIP
+
+ Layout.minimumWidth: 348
+ Layout.preferredWidth: 348
+ Layout.maximumWidth: 348
+
+ Layout.minimumHeight: 192
+ Layout.preferredHeight: 192
+ Layout.maximumHeight: 192
+
+ model: audioCodecListModelSIP
+
+ delegate: AudioCodecDelegate {
+ id: audioCodecDelegate
+
+ width: audioListWidgetSIP.width
+ height: audioListWidgetSIP.height / 4
+
+ layer.mipmap: false
+ clip: true
+
+ audioCodecName : AudioCodecName
+ isEnabled : IsEnabled
+ audioCodecId: AudioCodecID
+ samplerRate: Samplerate
+
+ onClicked: {
+ audioListWidgetSIP.currentIndex = index
+ }
+
+ onAudioCodecStateChange:{
+ ClientWrapper.settingsAdaptor.audioCodecsStateChange(idToSet , isToBeEnabled)
+ updateAudioCodecs()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ ColumnLayout{
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("SDP Session Negotiation(ICE Fallback)")
+
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 21
+ Layout.preferredHeight: 21
+ Layout.maximumHeight: 21
+
+ text: qsTr("Only used during negotiation in case ICE is not supported")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.minimumHeight: 10
+ }
+
+ GridLayout{
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+
+ rowSpacing: 6
+ columnSpacing: 6
+
+ rows: 4
+ columns: 3
+
+ // 1st row
+ Label{
+ Layout.minimumWidth: 162
+ Layout.preferredWidth: 162
+ Layout.maximumWidth: 162
+
+ Layout.minimumHeight: 28
+ Layout.preferredHeight: 28
+ Layout.maximumHeight: 28
+
+ text: qsTr("Audio RTP Min Port")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 0
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.row: 0
+ Layout.column: 1
+ }
+
+ SpinBox{
+ id:audioRTPMinPortSpinBox
+
+ Layout.minimumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.maximumWidth: 250
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ from: 0
+ to: 65535
+ stepSize: 1
+
+ Layout.row: 0
+ Layout.column: 2
+
+ onValueModified: {
+ audioRTPMinPortSpinBoxEditFinished(value)
+ }
+ }
+
+ // 2nd row
+ Label{
+ Layout.minimumWidth: 162
+ Layout.preferredWidth: 162
+ Layout.maximumWidth: 162
+
+ Layout.minimumHeight: 28
+ Layout.preferredHeight: 28
+ Layout.maximumHeight: 28
+
+ text: qsTr("Audio RTP Max Port")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 1
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.row: 1
+ Layout.column: 1
+ }
+
+ SpinBox{
+ id:audioRTPMaxPortSpinBox
+
+ Layout.minimumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.maximumWidth: 250
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ from: 0
+ to: 65535
+ stepSize: 1
+
+ Layout.row: 1
+ Layout.column: 2
+
+ onValueModified: {
+ audioRTPMaxPortSpinBoxEditFinished(value)
+ }
+ }
+
+ // 3rd row
+ Label{
+ Layout.minimumWidth: 162
+ Layout.preferredWidth: 162
+ Layout.maximumWidth: 162
+
+ Layout.minimumHeight: 28
+ Layout.preferredHeight: 28
+ Layout.maximumHeight: 28
+
+ text: qsTr("Video RTP Min Port")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 2
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.row: 2
+ Layout.column: 1
+ }
+
+ SpinBox{
+ id:videoRTPMinPortSpinBox
+
+ Layout.minimumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.maximumWidth: 250
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ from: 0
+ to: 65535
+ stepSize: 1
+
+ Layout.row: 2
+ Layout.column: 2
+
+ onValueModified: {
+ videoRTPMinPortSpinBoxEditFinished(value)
+ }
+ }
+
+ // 4th row
+ Label{
+ Layout.minimumWidth: 162
+ Layout.preferredWidth: 162
+ Layout.maximumWidth: 162
+
+ Layout.minimumHeight: 28
+ Layout.preferredHeight: 28
+ Layout.maximumHeight: 28
+
+ text: qsTr("Video RTP Max Port")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.row: 3
+ Layout.column: 0
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.row: 3
+ Layout.column: 1
+ }
+
+ SpinBox{
+ id:videoRTPMaxPortSpinBox
+
+ Layout.minimumWidth: 250
+ Layout.preferredWidth: 250
+ Layout.maximumWidth: 250
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ from: 0
+ to: 65535
+ stepSize: 1
+
+ Layout.row: 3
+ Layout.column: 2
+
+ onValueModified: {
+ videoRTPMaxPortSpinBoxEditFinished(value)
+ }
+ }
+ }
+ }
+
+ // spacers
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 48
+ Layout.preferredHeight: 48
+ Layout.minimumHeight: 48
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+}
+
+
diff --git a/src/settingsview/components/AdvancedSettingsView.qml b/src/settingsview/components/AdvancedSettingsView.qml
new file mode 100644
index 0000000..003869b
--- /dev/null
+++ b/src/settingsview/components/AdvancedSettingsView.qml
@@ -0,0 +1,1370 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Dialogs 1.3
+import Qt.labs.platform 1.1
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+ColumnLayout {
+ function updateAccountInfoDisplayedAdvance() {
+ //Call Settings
+ checkAutoConnectOnLocalNetwork.checked = ClientWrapper.settingsAdaptor.getAccountConfig_PeerDiscovery()
+ checkBoxUntrusted.checked = ClientWrapper.settingsAdaptor.getAccountConfig_DHT_PublicInCalls()
+ checkBoxAutoAnswer.checked = ClientWrapper.settingsAdaptor.getAccountConfig_AutoAnswer()
+ checkBoxCustomRingtone.checked = ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtoneEnabled()
+
+ // Name Server
+ lineEditNameServer.text = ClientWrapper.settingsAdaptor.getAccountConfig_RingNS_Uri()
+
+ //OpenDHT Config
+ checkBoxEnableProxy.checked = ClientWrapper.settingsAdaptor.getAccountConfig_ProxyEnabled()
+ lineEditProxy.text = ClientWrapper.settingsAdaptor.getAccountConfig_ProxyServer()
+ lineEditBootstrap.text = ClientWrapper.settingsAdaptor.getAccountConfig_Hostname()
+
+ // Security
+ btnCACert.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateListFile())
+ btnUserCert.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateFile())
+ btnPrivateKey.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_PrivateKeyFile())
+
+ // Connectivity
+ checkBoxUPnP.checked = ClientWrapper.settingsAdaptor.getAccountConfig_UpnpEnabled()
+ checkBoxTurnEnable.checked = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Enabled()
+ lineEditTurnAddress.text = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Server()
+ lineEditTurnUsername.text = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Username()
+ lineEditTurnPassword.text = ClientWrapper.settingsAdaptor.getAccountConfig_TURN_Password()
+ checkBoxSTUNEnable.checked = ClientWrapper.settingsAdaptor.getAccountConfig_STUN_Enabled()
+ lineEditSTUNAddress.text = ClientWrapper.settingsAdaptor.getAccountConfig_STUN_Server()
+ // codecs
+ videoCheckBox.checked = ClientWrapper.settingsAdaptor.getAccountConfig_Video_Enabled()
+ // update audio and video codec, make sure this change does not trigger item change events
+ updateAudioCodecs();
+ updateVideoCodecs();
+ btnRingtone.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtoneEnabled()
+ btnRingtone.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtonePath())
+ lineEditProxy.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_ProxyEnabled()
+ lineEditSTUNAddress.enabled = ClientWrapper.settingsAdaptor.getAccountConfig_STUN_Enabled()
+ }
+
+ function updateAudioCodecs(){
+ audioCodecListModel.layoutAboutToBeChanged()
+ audioCodecListModel.dataChanged(audioCodecListModel.index(0, 0),
+ audioCodecListModel.index(audioCodecListModel.rowCount() - 1, 0))
+ audioCodecListModel.layoutChanged()
+ }
+
+ function updateVideoCodecs(){
+ videoCodecListModel.layoutAboutToBeChanged()
+ videoCodecListModel.dataChanged(videoCodecListModel.index(0, 0),
+ videoCodecListModel.index(videoCodecListModel.rowCount() - 1, 0))
+ videoCodecListModel.layoutChanged()
+ }
+
+ function decreaseAudioCodecPriority(){
+ var index = audioListWidget.currentIndex
+ var codecId = audioCodecListModel.data(audioCodecListModel.index(index,0), AudioCodecListModel.AudioCodecID)
+
+ ClientWrapper.settingsAdaptor.decreaseAudioCodecPriority(codecId)
+ audioListWidget.currentIndex = index + 1
+ updateAudioCodecs()
+ }
+
+ function increaseAudioCodecPriority(){
+ var index = audioListWidget.currentIndex
+ var codecId = audioCodecListModel.data(audioCodecListModel.index(index,0), AudioCodecListModel.AudioCodecID)
+
+ ClientWrapper.settingsAdaptor.increaseAudioCodecPriority(codecId)
+ audioListWidget.currentIndex = index - 1
+ updateAudioCodecs()
+ }
+
+ function decreaseVideoCodecPriority(){
+ var index = videoListWidget.currentIndex
+ var codecId = videoCodecListModel.data(videoCodecListModel.index(index,0), VideoCodecListModel.VideoCodecID)
+
+ ClientWrapper.settingsAdaptor.decreaseVideoCodecPriority(codecId)
+ videoListWidget.currentIndex = index + 1
+ updateVideoCodecs()
+ }
+
+ function increaseVideoCodecPriority(){
+ var index = videoListWidget.currentIndex
+ var codecId = videoCodecListModel.data(videoCodecListModel.index(index,0), VideoCodecListModel.VideoCodecID)
+
+ ClientWrapper.settingsAdaptor.increaseVideoCodecPriority(codecId)
+ videoListWidget.currentIndex = index - 1
+ updateVideoCodecs()
+ }
+
+ VideoCodecListModel{
+ id: videoCodecListModel
+ }
+
+ AudioCodecListModel{
+ id: audioCodecListModel
+ }
+
+ function changeRingtonePath(url){
+ if(url.length !== 0) {
+ ClientWrapper.settingsAdaptor.set_RingtonePath(url)
+ btnRingtone.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtonePath())
+ } else if (ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtonePath().length === 0){
+ btnRingtone.text = qsTr("Add a custom ringtone")
+ }
+ }
+
+ function changeFileCACert(url){
+ if(url.length !== 0) {
+ ClientWrapper.settingsAdaptor.set_FileCACert(url)
+ btnCACert.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateListFile())
+ }
+ }
+
+ function changeFileUserCert(url){
+ if(url.length !== 0) {
+ ClientWrapper.settingsAdaptor.set_FileUserCert(url)
+ btnUserCert.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateFile())
+ }
+ }
+
+ function changeFilePrivateKey(url){
+ if(url.length !== 0) {
+ ClientWrapper.settingsAdaptor.set_FilePrivateKey(url)
+ btnPrivateKey.text = ClientWrapper.utilsAdaptor.toFileInfoName(ClientWrapper.settingsAdaptor.getAccountConfig_TLS_PrivateKeyFile())
+ }
+ }
+
+ JamiFileDialog {
+ id: ringtonePath_Dialog
+
+ property string oldPath : ClientWrapper.settingsAdaptor.getAccountConfig_Ringtone_RingtonePath()
+ property string openPath : oldPath === "" ? (ClientWrapper.utilsAdaptor.getCurrentPath() + "/ringtones/") : (ClientWrapper.utilsAdaptor.toFileAbsolutepath(oldPath))
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select a new ringtone")
+ folder: openPath
+
+ nameFilters: [qsTr("Audio Files") + " (*.wav *.ogg *.opus *.mp3 *.aiff *.wma)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ changeRingtonePath(url)
+ }
+ }
+
+ JamiFileDialog {
+ id: caCert_Dialog
+
+ property string oldPath : ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateListFile()
+ property string openPath : oldPath === "" ? (ClientWrapper.utilsAdaptor.getCurrentPath() + "/ringtones/") : (ClientWrapper.utilsAdaptor.toFileAbsolutepath(oldPath))
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select a CA certificate")
+ folder: openPath
+ nameFilters: [qsTr("Certificate File") + " (*.crt)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ changeFileCACert(url)
+ }
+ }
+
+ JamiFileDialog {
+ id: userCert_Dialog
+
+ property string oldPath : ClientWrapper.settingsAdaptor.getAccountConfig_TLS_CertificateFile()
+ property string openPath : oldPath === "" ? (ClientWrapper.utilsAdaptor.getCurrentPath() + "/ringtones/") : (ClientWrapper.utilsAdaptor.toFileAbsolutepath(oldPath))
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select a user certificate")
+ folder: openPath
+ nameFilters: [qsTr("Certificate File") + " (*.crt)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ changeFileUserCert(url)
+ }
+ }
+
+ JamiFileDialog {
+ id: privateKey_Dialog
+
+ property string oldPath : ClientWrapper.settingsAdaptor.getAccountConfig_TLS_PrivateKeyFile()
+ property string openPath : oldPath === "" ? (ClientWrapper.utilsAdaptor.getCurrentPath() + "/ringtones/") : (ClientWrapper.utilsAdaptor.toFileAbsolutepath(oldPath))
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select a private key")
+ folder: openPath
+ nameFilters: [qsTr("Key File") + " (*.key)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ changeFilePrivateKey(url)
+ }
+ }
+
+ spacing: 6
+
+ Layout.preferredWidth: 532
+ Layout.maximumWidth: 532
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 24
+ Layout.preferredHeight: 24
+ Layout.maximumHeight: 24
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Call Settings")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ ToggleSwitch {
+ id: checkBoxUntrusted
+
+ Layout.leftMargin: 20
+
+ labelText: qsTr("Allow incoming calls from unknown contacts")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setCallsUntrusted(checked)
+ }
+ }
+
+ ToggleSwitch {
+ id: checkBoxAutoAnswer
+
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+
+ labelText: qsTr("Auto Answer Calls")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setAutoAnswerCalls(checked)
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+ Layout.maximumHeight: 30
+
+ ToggleSwitch {
+ id: checkBoxCustomRingtone
+
+ labelText: qsTr("Enable Custom Ringtone")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setEnableRingtone(checked)
+ btnRingtone.enabled = checked
+ }
+ }
+
+ HoverableRadiusButton {
+ id: btnRingtone
+
+ Layout.minimumWidth: 300
+ Layout.preferredWidth: 300
+ Layout.maximumWidth: 300
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.width: 16
+ icon.height: 16
+
+ onClicked: {
+ ringtonePath_Dialog.open()
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Name Server")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+ Layout.maximumHeight: 29
+
+ Label {
+ Layout.minimumWidth: 60
+
+ Layout.minimumHeight: 29
+ Layout.preferredHeight: 29
+ Layout.maximumHeight: 29
+
+ text: qsTr("Address")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ InfoLineEdit {
+ id: lineEditNameServer
+
+ fieldLayoutWidth: 300
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setNameServer(text)
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("OpenDHT Configuration")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+
+ ToggleSwitch {
+ id: checkBoxEnableProxy
+
+ labelText: qsTr("Enable proxy")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setEnableProxy(checked)
+ lineEditProxy.enabled = checked
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ InfoLineEdit {
+ id: lineEditProxy
+
+ fieldLayoutWidth: 300
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setProxyAddress(text)
+ }
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+
+ Label {
+ id: labelBootstrap
+
+ Layout.minimumWidth: 72
+ Layout.preferredWidth: 72
+
+ Layout.minimumHeight: 29
+ Layout.preferredHeight: 29
+ Layout.maximumHeight: 29
+
+ text: qsTr("Bootstrap")
+ font.pointSize: 10
+ font.kerning: true
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ InfoLineEdit {
+ id: lineEditBootstrap
+
+ fieldLayoutWidth: 300
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setBootstrapAddress(text)
+ }
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Security")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ GridLayout {
+ rows: 4
+ columns: 2
+ rowSpacing: 0
+ columnSpacing: 6
+
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+
+ // CA Certificate
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 32
+ Layout.preferredHeight: 32
+ Layout.maximumHeight: 32
+
+ text: qsTr("CA Certificate")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ HoverableRadiusButton {
+ id: btnCACert
+
+ radius: height / 2
+
+ Layout.minimumWidth: 298
+ Layout.preferredWidth: 298
+ Layout.maximumWidth: 298
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.width: 16
+ icon.height: 16
+
+ onClicked: {
+ caCert_Dialog.open()
+ }
+ }
+
+ // User Certificate
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 32
+ Layout.preferredHeight: 32
+ Layout.maximumHeight: 32
+
+ text: qsTr("User Certificate")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ HoverableRadiusButton {
+ id: btnUserCert
+
+ radius: height / 2
+
+ Layout.minimumWidth: 298
+ Layout.preferredWidth: 298
+ Layout.maximumWidth: 298
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.width: 16
+ icon.height: 16
+
+ onClicked: {
+ userCert_Dialog.open()
+ }
+ }
+
+ // Private Key
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 32
+ Layout.preferredHeight: 32
+ Layout.maximumHeight: 32
+
+ text: qsTr("Private Key")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ HoverableRadiusButton {
+ id: btnPrivateKey
+
+ radius: height / 2
+
+ Layout.minimumWidth: 298
+ Layout.preferredWidth: 298
+ Layout.maximumWidth: 298
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.width: 16
+ icon.height: 16
+
+ onClicked: {
+ privateKey_Dialog.open()
+ }
+ }
+
+ // Private key password
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 29
+ Layout.preferredHeight: 29
+ Layout.maximumHeight: 29
+
+ text: qsTr("Private Key Password")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ InfoLineEdit {
+ id: lineEditCertPassword
+
+ fieldLayoutWidth: 300
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ echoMode: TextInput.Password
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+ Layout.topMargin: 10
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Connectivity")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ GridLayout {
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+
+ rows: 6
+ columns: 3
+ rowSpacing: 6
+ columnSpacing: 6
+
+ // row 2
+ ToggleSwitch {
+ id: checkAutoConnectOnLocalNetwork
+
+ Layout.row: 0
+ Layout.column: 0
+
+ labelText: qsTr("Auto Connect On Local Network")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setAutoConnectOnLocalNetwork(checked)
+ }
+ }
+
+ Item {
+ Layout.row: 0
+ Layout.column: 1
+
+ Layout.fillHeight: true
+
+ Layout.minimumWidth: 40
+ Layout.preferredWidth: 40
+ Layout.maximumWidth: 40
+ }
+
+ // row 2
+ ToggleSwitch {
+ id: checkBoxUPnP
+
+ Layout.row: 1
+ Layout.column: 0
+
+ labelText: qsTr("Use UPnP")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseUPnP(checked)
+ }
+ }
+
+ Item {
+ Layout.row: 1
+ Layout.column: 1
+
+ Layout.fillHeight: true
+
+ Layout.minimumWidth: 40
+ Layout.preferredWidth: 40
+ Layout.maximumWidth: 40
+ }
+
+ // row 3
+ ToggleSwitch {
+ id: checkBoxTurnEnable
+
+ Layout.row: 2
+ Layout.column: 0
+
+ labelText: qsTr("Use TURN")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseTURN(checked)
+ }
+ }
+
+ // row 4
+ Label {
+ Layout.row: 3
+ Layout.column: 0
+
+ Layout.minimumWidth: 124
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("TURN Address")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ InfoLineEdit {
+ id: lineEditTurnAddress
+
+ Layout.row: 3
+ Layout.column: 2
+
+ fieldLayoutWidth: 300
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setTURNAddress(text)
+ }
+ }
+
+ //row 5
+ Label {
+ Layout.row: 4
+ Layout.column: 0
+
+ Layout.minimumWidth: 124
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("TURN Username")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ InfoLineEdit {
+ id: lineEditTurnUsername
+
+ Layout.row: 4
+ Layout.column: 2
+
+ fieldLayoutWidth: 300
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setTURNUsername(text)
+ }
+ }
+
+ //row 6
+ Label {
+ Layout.row: 5
+ Layout.column: 0
+
+ Layout.minimumWidth: 124
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("TURN Password")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ InfoLineEdit {
+ id: lineEditTurnPassword
+ layer.mipmap: false
+
+ Layout.row: 5
+ Layout.column: 2
+
+ fieldLayoutWidth: 300
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ echoMode: TextInput.Password
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setTURNPassword(text)
+ }
+ }
+
+ // row 7
+ ToggleSwitch {
+ id: checkBoxSTUNEnable
+
+ Layout.row: 6
+ Layout.column: 0
+
+ labelText: qsTr("Use STUN")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setUseSTUN(checked)
+ lineEditSTUNAddress.enabled = checked
+ }
+ }
+
+ InfoLineEdit {
+ id: lineEditSTUNAddress
+
+ Layout.row: 6
+ Layout.column: 2
+
+ fieldLayoutWidth: 300
+ fieldLayoutHeight: 29
+
+ font.pointSize: 10
+ font.kerning: true
+
+ placeholderText: qsTr("STUN Address")
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setSTUNAddress(text)
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+ Layout.topMargin: 10
+
+ Layout.minimumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.maximumHeight: 27
+
+ text: qsTr("Media")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ ToggleSwitch {
+ id: videoCheckBox
+
+ Layout.leftMargin: 20
+
+ labelText: qsTr("Enable Video")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ ClientWrapper.settingsAdaptor.setVideoState(checked)
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+
+ ColumnLayout {
+ spacing: 6
+ //Layout.fillWidth: true
+ Layout.maximumWidth: 348
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Video Codecs")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.minimumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.maximumWidth: 20
+ }
+
+ HoverableRadiusButton {
+ id: videoDownPushButton
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+ radius: height / 2
+ scale: 1
+
+ font.pointSize: 9
+ font.kerning: true
+
+ icon.source: "qrc:/images/icons/round-arrow_drop_down-24px.svg"
+ icon.width: 32
+ icon.height: 32
+
+ onClicked: {
+ decreaseVideoCodecPriority()
+ }
+ }
+
+ HoverableRadiusButton {
+ id: videoUpPushButton
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+ radius: height / 2
+
+ font.pointSize: 9
+ font.kerning: true
+
+ icon.source: "qrc:/images/icons/round-arrow_drop_up-24px.svg"
+ icon.width: 32
+ icon.height: 32
+
+ onClicked: {
+ increaseVideoCodecPriority()
+ }
+ }
+ }
+
+ ListViewJami {
+ id: videoListWidget
+
+ Layout.minimumWidth: 348
+ Layout.preferredWidth: 348
+ Layout.maximumWidth: 348
+
+ Layout.minimumHeight: 192
+ Layout.preferredHeight: 192
+ Layout.maximumHeight: 192
+
+ model: videoCodecListModel
+
+ delegate: VideoCodecDelegate {
+ id: videoCodecDelegate
+
+ width: videoListWidget.width
+ height: videoListWidget.height / 4
+
+ videoCodecName : VideoCodecName
+ isEnabled : IsEnabled
+ videoCodecId: VideoCodecID
+
+ onClicked: {
+ videoListWidget.currentIndex = index
+ }
+
+ onVideoCodecStateChange:{
+ ClientWrapper.settingsAdaptor.videoCodecsStateChange(idToSet , isToBeEnabled)
+ updateVideoCodecs()
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.maximumWidth: 348
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Audio Codecs")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.minimumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.maximumWidth: 20
+ }
+
+ HoverableRadiusButton {
+ id: audioDownPushButton
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ font.pointSize: 9
+ font.kerning: true
+
+ icon.source: "qrc:/images/icons/round-arrow_drop_down-24px.svg"
+ icon.width: 32
+ icon.height: 32
+
+ onClicked: {
+ decreaseAudioCodecPriority()
+ }
+ }
+
+ HoverableRadiusButton {
+ id: audioUpPushButton
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ radius: height / 2
+
+ font.pointSize: 9
+ font.kerning: true
+
+ icon.source: "qrc:/images/icons/round-arrow_drop_up-24px.svg"
+ icon.width: 32
+ icon.height: 32
+
+ onClicked: {
+ increaseAudioCodecPriority()
+ }
+ }
+ }
+
+ ListViewJami {
+ id: audioListWidget
+
+ Layout.minimumWidth: 348
+ Layout.preferredWidth: 348
+ Layout.maximumWidth: 348
+
+ Layout.minimumHeight: 192
+ Layout.preferredHeight: 192
+ Layout.maximumHeight: 192
+
+ model: audioCodecListModel
+
+ delegate: AudioCodecDelegate {
+ id: audioCodecDelegate
+
+ width: audioListWidget.width
+ height: audioListWidget.height / 4
+
+ layer.mipmap: false
+ clip: true
+
+ audioCodecName : AudioCodecName
+ isEnabled : IsEnabled
+ audioCodecId: AudioCodecID
+ samplerRate: Samplerate
+
+ onClicked: {
+ audioListWidget.currentIndex = index
+ }
+
+ onAudioCodecStateChange:{
+ ClientWrapper.settingsAdaptor.audioCodecsStateChange(idToSet , isToBeEnabled)
+ updateAudioCodecs()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 48
+ Layout.preferredHeight: 48
+ Layout.maximumHeight: 48
+ }
+}
diff --git a/src/settingsview/components/AudioCodecDelegate.qml b/src/settingsview/components/AudioCodecDelegate.qml
new file mode 100644
index 0000000..9f80a2e
--- /dev/null
+++ b/src/settingsview/components/AudioCodecDelegate.qml
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+ItemDelegate {
+ id: videoCodecDelegate
+
+ property string audioCodecName : ""
+ property bool isEnabled : false
+ property int audioCodecId
+ property string samplerRate: ""
+
+ signal audioCodecStateChange(string idToSet , bool isToBeEnabled)
+
+ property int checkBoxWidth: 10
+
+ highlighted: ListView.isCurrentItem
+
+ RowLayout{
+ anchors.fill: parent
+ z: 1
+
+ spacing: 10
+
+ CheckBox{
+ id: checkBoxIsEnabled
+
+ Layout.leftMargin: 20
+
+ Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
+ Layout.fillHeight: true
+
+ Layout.minimumWidth: checkBoxWidth
+ Layout.preferredWidth: checkBoxWidth
+ Layout.maximumWidth: checkBoxWidth
+
+ tristate: false
+ checkState: isEnabled ? Qt.Checked : Qt.Unchecked
+
+ indicator.implicitWidth: checkBoxWidth
+ indicator.implicitHeight:checkBoxWidth
+
+ indicator.layer.textureSize.width: checkBoxWidth
+ indicator.layer.textureSize.height: checkBoxWidth
+
+ text: ""
+
+ nextCheckState: function() {
+ var result
+ var result_bool
+
+ if (checkState === Qt.Checked){
+ result = Qt.Unchecked
+ result_bool = false
+ } else {
+ result = Qt.Checked
+ result_bool = true
+ }
+ audioCodecStateChange(audioCodecId,result_bool)
+ return result
+ }
+ }
+
+ Label{
+ id: formatNameLabel
+
+ Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ text: audioCodecName + " " + samplerRate + " Hz"
+ font.pointSize: 8
+ font.kerning: true
+ }
+ }
+}
diff --git a/src/settingsview/components/AvSettingPage.qml b/src/settingsview/components/AvSettingPage.qml
new file mode 100644
index 0000000..a999e32
--- /dev/null
+++ b/src/settingsview/components/AvSettingPage.qml
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+Rectangle {
+ id: avSettingPage
+
+ AudioInputDeviceModel{
+ id: audioInputDeviceModel
+ }
+
+ AudioOutputDeviceModel{
+ id: audioOutputDeviceModel
+ }
+
+ AudioManagerListModel{
+ id: audioManagerListModel
+ }
+
+ VideoInputDeviceModel{
+ id: videoInputDeviceModel
+ }
+
+ VideoFormatResolutionModel{
+ id: videoFormatResolutionModel
+ }
+
+ VideoFormatFpsModel{
+ id: videoFormatFpsModel
+ }
+
+ function populateAVSettings(){
+ audioInputDeviceModel.reset()
+ audioOutputDeviceModel.reset()
+
+ inputComboBox.currentIndex = audioInputDeviceModel.getCurrentSettingIndex()
+ outputComboBox.currentIndex = audioOutputDeviceModel.getCurrentSettingIndex()
+ ringtoneDeviceComboBox.currentIndex = audioOutputDeviceModel.getCurrentRingtoneDeviceIndex()
+
+ audioManagerRowLayout.visible = (audioManagerListModel.rowCount() > 0)
+ if(audioManagerListModel.rowCount() > 0){
+ audioManagerComboBox.currentIndex = audioManagerListModel.getCurrentSettingIndex()
+ }
+
+ populateVideoSettings()
+ var encodeAccel = ClientWrapper.avmodel.getHardwareAcceleration()
+ hardwareAccelControl.checked = encodeAccel
+ }
+
+ function populateVideoSettings() {
+ videoInputDeviceModel.reset()
+
+ deviceBox.enabled = (videoInputDeviceModel.deviceCount() > 0)
+ resolutionBox.enabled = (videoInputDeviceModel.deviceCount() > 0)
+ fpsBox.enabled = (videoInputDeviceModel.deviceCount() > 0)
+ labelVideoDevice.enabled = (videoInputDeviceModel.deviceCount() > 0)
+ labelVideoResolution.enabled = (videoInputDeviceModel.deviceCount() > 0)
+ labelVideoFps.enabled = (videoInputDeviceModel.deviceCount() > 0)
+
+ deviceBox.currentIndex = videoInputDeviceModel.getCurrentSettingIndex()
+ slotDeviceBoxCurrentIndexChanged(deviceBox.currentIndex)
+
+ try{
+ startPreviewing(false)
+ } catch (err2){ console.log("Start preview fail when populate video settings, exception: "+ err2.message)}
+
+ }
+
+ function setFormatListForCurrentDevice(){
+ var device = ClientWrapper.avmodel.getCurrentVideoCaptureDevice()
+ if(ClientWrapper.settingsAdaptor.get_DeviceCapabilitiesSize(device) === 0){
+ return
+ }
+
+ try{
+ videoFormatResolutionModel.reset()
+ resolutionBox.currentIndex = videoFormatResolutionModel.getCurrentSettingIndex()
+ slotFormatCurrentIndexChanged(resolutionBox.currentIndex,true)
+ } catch(err){console.warn("Exception: " + err.message)}
+ }
+
+ function startPreviewing(force = false){
+ ClientWrapper.accountAdaptor.startPreviewing(force)
+ previewAvailable = true
+ }
+
+ function stopPreviewing(){
+ ClientWrapper.accountAdaptor.stopPreviewing()
+ }
+
+ function startAudioMeter(async = true){
+ audioInputMeter.start()
+ ClientWrapper.accountAdaptor.startAudioMeter(async)
+ }
+
+ function stopAudioMeter(async = true){
+ audioInputMeter.stop()
+ ClientWrapper.accountAdaptor.stopAudioMeter(async)
+ }
+
+ // slots for av page
+ function slotAudioMeter(id, level){
+ if (id === "audiolayer_id") {
+ audioInputMeter.setLevel(level)
+ }
+ }
+
+ function slotSetHardwareAccel(state){
+ ClientWrapper.accountAdaptor.avModel().setHardwareAcceleration(state)
+ startPreviewing(true)
+ }
+
+ function slotAudioManagerIndexChanged(index){
+ stopAudioMeter(false)
+ var selectedAudioManager = audioManagerListModel.data(audioManagerListModel.index(
+ index, 0), AudioManagerListModel.AudioManagerID)
+ ClientWrapper.avmodel.setAudioManager(selectedAudioManager)
+ startAudioMeter(false)
+ }
+
+ function slotRingtoneDeviceIndexChanged(index){
+ stopAudioMeter(false)
+ var selectedRingtoneDeviceName = audioOutputDeviceModel.data(audioOutputDeviceModel.index(
+ index, 0), AudioOutputDeviceModel.Device_ID)
+ ClientWrapper.avmodel.setRingtoneDevice(selectedRingtoneDeviceName)
+ startAudioMeter(false)
+ }
+
+ function slotAudioOutputIndexChanged(index){
+ stopAudioMeter(false)
+ var selectedOutputDeviceName = audioOutputDeviceModel.data(audioOutputDeviceModel.index(
+ index, 0), AudioOutputDeviceModel.Device_ID)
+ ClientWrapper.avmodel.setOutputDevice(selectedOutputDeviceName)
+ startAudioMeter(false)
+ }
+
+ function slotAudioInputIndexChanged(index){
+ stopAudioMeter(false)
+ var selectedInputDeviceName = audioInputDeviceModel.data(audioInputDeviceModel.index(
+ index, 0), AudioInputDeviceModel.Device_ID)
+
+ ClientWrapper.avmodel.setInputDevice(selectedInputDeviceName)
+ startAudioMeter(false)
+ }
+
+ function slotDeviceBoxCurrentIndexChanged(index){
+ if(videoInputDeviceModel.deviceCount() <= 0){
+ return
+ }
+
+ try{
+ var deviceId = videoInputDeviceModel.data(videoInputDeviceModel.index(
+ index, 0), VideoInputDeviceModel.DeviceId)
+ var deviceName = videoInputDeviceModel.data(videoInputDeviceModel.index(
+ index, 0), VideoInputDeviceModel.DeviceName)
+ if(deviceId.length === 0){
+ console.warn("Couldn't find device: " + deviceName)
+ return
+ }
+
+ ClientWrapper.avmodel.setCurrentVideoCaptureDevice(deviceId)
+ ClientWrapper.avmodel.setDefaultDevice(deviceId)
+ setFormatListForCurrentDevice()
+ startPreviewing(true)
+ } catch(err){console.warn(err.message)}
+ }
+
+ function slotFormatCurrentIndexChanged(index, isResolutionIndex){
+ var resolution
+ var rate
+ if(isResolutionIndex){
+ resolution = videoFormatResolutionModel.data(videoFormatResolutionModel.index(
+ index, 0), VideoFormatResolutionModel.Resolution)
+ videoFormatFpsModel.currentResolution = resolution
+ fpsBox.currentIndex = videoFormatFpsModel.getCurrentSettingIndex()
+ rate = videoFormatFpsModel.data(videoFormatFpsModel.index(
+ fpsBox.currentIndex, 0), VideoFormatFpsModel.FPS)
+ } else {
+ resolution = videoFormatResolutionModel.data(videoFormatResolutionModel.index(
+ resolutionBox.currentIndex, 0), VideoFormatResolutionModel.Resolution)
+ videoFormatFpsModel.currentResolution = resolution
+ rate = videoFormatFpsModel.data(videoFormatFpsModel.index(
+ index, 0), VideoFormatFpsModel.FPS)
+ }
+
+ try{
+ ClientWrapper.settingsAdaptor.set_Video_Settings_Rate_And_Resolution(ClientWrapper.avmodel.getCurrentVideoCaptureDevice(),rate,resolution)
+ } catch(error){console.warn(error.message)}
+ }
+
+ function slotVideoDeviceListChanged(){
+ populateVideoSettings()
+ }
+
+ property bool previewAvailable: false
+
+ Connections{
+ target: ClientWrapper.avmodel
+
+ function onAudioMeter(id, level){
+ slotAudioMeter(id,level)
+ }
+ }
+
+ Connections{
+ target: ClientWrapper.renderManager
+
+ function onVideoDeviceListChanged(){
+ slotVideoDeviceListChanged()
+ }
+ }
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ScrollView{
+ anchors.fill: parent
+ clip: true
+
+ RowLayout {
+ width: avSettingPage.width
+ height: avSettingPage.height
+
+ spacing: 0
+ Item {
+ Layout.fillHeight: true
+ Layout.maximumWidth: 48
+ Layout.preferredWidth: 48
+ Layout.minimumWidth: 48
+ }
+
+ ColumnLayout {
+ spacing: 7
+
+ Layout.fillHeight: true
+ Layout.maximumWidth: 580
+ Layout.preferredWidth: 580
+ Layout.minimumWidth: 580
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ Label {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 25
+ Layout.preferredHeight: 25
+ Layout.maximumHeight: 25
+
+ text: qsTr("Audio / Video")
+ font.pointSize: 15
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 24
+ Layout.preferredHeight: 24
+ Layout.maximumHeight: 24
+ }
+
+ ColumnLayout {
+ spacing: 0
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 21
+ Layout.preferredHeight: 21
+ Layout.maximumHeight: 21
+
+ text: qsTr("Audio")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 7
+ Layout.fillWidth: true
+
+ RowLayout {
+ spacing: 7
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.maximumWidth: 77
+ Layout.preferredWidth: 77
+ Layout.minimumWidth: 77
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Microphone")
+ font.pointSize: 11
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ SettingParaCombobox {
+ id: inputComboBox
+
+ Layout.maximumWidth: 360
+ Layout.preferredWidth: 360
+ Layout.minimumWidth: 360
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ model: audioInputDeviceModel
+
+ textRole: "ID_UTF8"
+
+ onActivated: {
+ slotAudioInputIndexChanged(index)
+ }
+ }
+ }
+
+ // the audio level meter
+ LevelMeter {
+ id: audioInputMeter
+
+ Layout.leftMargin: 20
+
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+
+ indeterminate: false
+ from: 0
+ to: 100
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 5
+ Layout.preferredHeight: 5
+ Layout.maximumHeight: 5
+ }
+
+ RowLayout {
+ spacing: 7
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.maximumWidth: 95
+ Layout.preferredWidth: 95
+ Layout.minimumWidth: 95
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Output Device")
+ font.pointSize: 11
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ SettingParaCombobox {
+ id: outputComboBox
+
+ Layout.maximumWidth: 360
+ Layout.preferredWidth: 360
+ Layout.minimumWidth: 360
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ model: audioOutputDeviceModel
+
+ textRole: "ID_UTF8"
+
+ onActivated: {
+ slotAudioOutputIndexChanged(index)
+ }
+ }
+ }
+
+ RowLayout {
+ spacing: 7
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.maximumWidth: 77
+ Layout.preferredWidth: 77
+ Layout.minimumWidth: 77
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Ringtone Device")
+ font.pointSize: 11
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ SettingParaCombobox {
+ id: ringtoneDeviceComboBox
+
+ Layout.maximumWidth: 360
+ Layout.preferredWidth: 360
+ Layout.minimumWidth: 360
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ model: audioOutputDeviceModel
+
+ textRole: "ID_UTF8"
+
+ onActivated: {
+ slotRingtoneDeviceIndexChanged(index)
+ }
+ }
+ }
+
+ RowLayout {
+ id: audioManagerRowLayout
+
+ spacing: 7
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.maximumWidth: 77
+ Layout.preferredWidth: 77
+ Layout.minimumWidth: 77
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Audio Manager")
+ font.pointSize: 11
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ SettingParaCombobox {
+ id: audioManagerComboBox
+
+ Layout.maximumWidth: 360
+ Layout.preferredWidth: 360
+ Layout.minimumWidth: 360
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ model: audioManagerListModel
+
+ textRole: "ID_UTF8"
+
+ onActivated: {
+ slotAudioManagerIndexChanged(index)
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ ColumnLayout {
+ spacing: 7
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Video")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ RowLayout {
+ spacing: 7
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+ Layout.maximumHeight: 30
+
+ Label {
+ id: labelVideoDevice
+
+ Layout.maximumWidth: 44
+ Layout.preferredWidth: 44
+ Layout.minimumWidth: 44
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Device")
+ font.pointSize: 11
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ SettingParaCombobox {
+ id: deviceBox
+
+ Layout.maximumWidth: 360
+ Layout.preferredWidth: 360
+ Layout.minimumWidth: 360
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ model: videoInputDeviceModel
+
+ textRole: "DeviceName_UTF8"
+
+ onActivated: {
+ slotDeviceBoxCurrentIndexChanged(index)
+ }
+ }
+ }
+
+ RowLayout {
+ spacing: 7
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+ Layout.maximumHeight: 30
+
+ Label {
+ id: labelVideoResolution
+
+ Layout.maximumWidth: 47
+ Layout.preferredWidth: 47
+ Layout.minimumWidth: 47
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Resolution")
+ font.pointSize: 11
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ SettingParaCombobox {
+ id: resolutionBox
+
+ Layout.maximumWidth: 360
+ Layout.preferredWidth: 360
+ Layout.minimumWidth: 360
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ model: videoFormatResolutionModel
+ textRole: "Resolution_UTF8"
+
+ onActivated: {
+ slotFormatCurrentIndexChanged(index,true)
+ }
+ }
+ }
+
+ RowLayout {
+ spacing: 7
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+ Layout.maximumHeight: 30
+
+ Label {
+ id: labelVideoFps
+
+ Layout.maximumWidth: 47
+ Layout.preferredWidth: 47
+ Layout.minimumWidth: 47
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Fps")
+ font.pointSize: 11
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ SettingParaCombobox {
+ id: fpsBox
+
+ Layout.maximumWidth: 360
+ Layout.preferredWidth: 360
+ Layout.minimumWidth: 360
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+
+ model: videoFormatFpsModel
+ textRole: "FPS_ToDisplay_UTF8"
+
+ onActivated: {
+ slotFormatCurrentIndexChanged(index,false)
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ RowLayout{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.preferredWidth: 580
+ Layout.minimumWidth: 580
+
+ Layout.minimumHeight: 224
+ Layout.preferredHeight: 224
+ Layout.maximumHeight: 224
+
+ Rectangle {
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillHeight: true
+ Layout.minimumWidth: 580
+
+ color: "black"
+
+ PreviewRenderer{
+ id: peviewWidget
+
+ visible: previewAvailable
+ height: parent.height
+ width: 224
+ x: (parent.width - width) /2
+ y: 0
+ }
+ }
+ }
+
+ Label {
+ visible: !previewAvailable
+
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Preview unavailable")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ // Toggle switch to enable hardware acceleration
+ ToggleSwitch {
+ id: hardwareAccelControl
+
+ labelText: "Enable hardware acceleration"
+
+ onSwitchToggled: {
+ slotSetHardwareAccel(checked)
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ }
+}
diff --git a/src/settingsview/components/BannedItemDelegate.qml b/src/settingsview/components/BannedItemDelegate.qml
new file mode 100644
index 0000000..980d539
--- /dev/null
+++ b/src/settingsview/components/BannedItemDelegate.qml
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+ItemDelegate {
+ id: deviceItemDelegate
+
+ property string contactName : ""
+ property string contactID: ""
+ property string contactPicture_base64:""
+
+ signal btnReAddContactClicked
+
+ function btnReAddContactEnter(){
+ btnReAddContact.enterBtn()
+ }
+
+ function btnReAddContactExit(){
+ btnReAddContact.exitBtn()
+ }
+
+ function btnReAddContactPress(){
+ btnReAddContact.pressBtn()
+ }
+
+ function btnReAddContactRelease(){
+ btnReAddContact.releaseBtn()
+ }
+
+ highlighted: ListView.isCurrentItem
+
+ RowLayout{
+ anchors.fill: parent
+
+ spacing: 7
+
+ Label{
+ id: labelContactAvatar
+
+ Layout.alignment: Qt.AlignVCenter
+
+ Layout.leftMargin: 7
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+
+ Layout.minimumWidth: 48
+ Layout.preferredWidth: 48
+ Layout.maximumWidth: 48
+
+ Layout.minimumHeight: 48
+ Layout.preferredHeight: 48
+ Layout.maximumHeight: 48
+
+ background: Rectangle{
+ anchors.fill: parent
+ color: "transparent"
+ Image {
+ id: avatarImg
+
+ anchors.fill: parent
+ source: "data:image/png;base64," + contactPicture_base64
+ fillMode: Image.PreserveAspectCrop
+ layer.enabled: true
+ layer.effect: OpacityMask {
+ maskSource: Rectangle{
+ width: avatarImg.width
+ height: avatarImg.height
+ radius: {
+ var size = ((avatarImg.width <= avatarImg.height)? avatarImg.width:avatarImg.height)
+ return size /2
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Item{
+ Layout.minimumWidth: 8
+ Layout.preferredWidth: 8
+ Layout.maximumWidth: 8
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ ColumnLayout{
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+
+ Layout.alignment: Qt.AlignVCenter
+
+ spacing: 7
+
+ Label{
+ id: labelContactName
+
+ Layout.fillWidth: true
+ Layout.minimumWidth: 0
+ Layout.maximumWidth: 16777215
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 8
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ text: contactName === "" ? qsTr("name") : contactName
+ }
+
+ Label{
+ id: labelContactId
+
+ Layout.fillWidth: true
+ Layout.minimumWidth: 0
+ Layout.maximumWidth: 16777215
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 8
+ font.kerning: true
+
+ horizontalAlignment: Qt.AlignLeft
+ verticalAlignment: Qt.AlignVCenter
+
+ text: contactID === "" ? qsTr("id") : contactID
+ }
+ }
+
+ HoverableRadiusButton{
+ id: btnReAddContact
+
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 8
+ font.kerning: true
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ source:"qrc:/images/icons/ic_person_add_black_24dp_2x.png"
+
+ ToolTip.visible: isHovering
+ ToolTip.text: qsTr("Add as contact")
+
+ onClicked: {
+ btnReAddContactClicked()
+ }
+ }
+
+ Item{
+ Layout.rightMargin: 7
+
+ Layout.minimumWidth: 8
+ Layout.preferredWidth: 8
+ Layout.maximumWidth: 8
+
+ Layout.minimumHeight: 20
+ }
+ }
+}
+
diff --git a/src/settingsview/components/CurrentAccountSettingsScrollPage.qml b/src/settingsview/components/CurrentAccountSettingsScrollPage.qml
new file mode 100644
index 0000000..b3d4392
--- /dev/null
+++ b/src/settingsview/components/CurrentAccountSettingsScrollPage.qml
@@ -0,0 +1,1376 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Dialogs 1.3
+import Qt.labs.platform 1.1
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+Rectangle {
+ id: accountViewRect
+
+ enum RegName {
+ BLANK,
+ INVALIDFORM,
+ TAKEN,
+ FREE,
+ SEARCHING
+ }
+
+ property int regNameUi: CurrentAccountSettingsScrollPage.BLANK
+ property string registeredName: ""
+ property bool registeredIdNeedsSet: false
+
+ property int refreshVariable : 0
+
+ signal navigateToMainView
+ signal navigateToNewWizardView
+
+ function refreshRelevantUI(){
+ refreshVariable++
+ refreshVariable--
+ }
+
+ Connections {
+ id: btnRegisterNameClickConnection
+ target: btnRegisterName
+
+ enabled: {
+ refreshVariable
+ switch (regNameUi) {
+ case CurrentAccountSettingsScrollPage.FREE:
+ return true
+ default:
+ return false
+ }
+ }
+
+ function onClicked() {
+ slotRegisterName()
+ }
+ }
+
+ function updateAccountInfoDisplayed() {
+ setAvatar()
+
+ accountEnableCheckBox.checked = ClientWrapper.settingsAdaptor.get_CurrentAccountInfo_Enabled()
+ displayNameLineEdit.text = ClientWrapper.settingsAdaptor.getCurrentAccount_Profile_Info_Alias()
+
+ var showLocalAccountConfig = (ClientWrapper.settingsAdaptor.getAccountConfig_Manageruri() === "")
+ passwdPushButton.visible = showLocalAccountConfig
+ btnExportAccount.visible = showLocalAccountConfig
+ linkDevPushButton.visible = showLocalAccountConfig
+
+ registeredIdNeedsSet = (ClientWrapper.settingsAdaptor.get_CurrentAccountInfo_RegisteredName() === "")
+
+ if(!registeredIdNeedsSet){
+ currentRegisteredID.text = ClientWrapper.settingsAdaptor.get_CurrentAccountInfo_RegisteredName()
+ } else {
+ currentRegisteredID.text = ""
+ }
+
+ currentRingID.text = ClientWrapper.settingsAdaptor.getCurrentAccount_Profile_Info_Uri()
+
+ // update device list view
+ updateAndShowDevicesSlot()
+
+ bannedContactsListWidget.visible = false
+ bannedContactsLayoutWidget.visible = (bannedListModel.rowCount() > 0)
+
+ if (advanceSettingsView.visible) {
+ advanceSettingsView.updateAccountInfoDisplayedAdvance()
+ }
+ refreshRelevantUI()
+ }
+
+ function connectCurrentAccount() {
+ accountConnections_ContactModel.enabled = true
+ accountConnections_DeviceModel.enabled = true
+ }
+
+ function disconnectAccountConnections() {
+ accountConnections_ContactModel.enabled = false
+ accountConnections_DeviceModel.enabled = false
+ }
+
+ function isPhotoBoothOpened() {
+ return currentAccountAvatar.takePhotoState
+ }
+
+ function setAvatar() {
+ currentAccountAvatar.setAvatarPixmap(
+ ClientWrapper.settingsAdaptor.getAvatarImage_Base64(
+ currentAccountAvatar.boothWidht),
+ ClientWrapper.settingsAdaptor.getIsDefaultAvatar())
+ }
+
+ function stopBooth() {
+ currentAccountAvatar.stopBooth()
+ }
+
+ function toggleBannedContacts(){
+ var bannedContactsVisible = bannedContactsListWidget.visible
+ bannedContactsListWidget.visible = !bannedContactsVisible
+ updateAndShowBannedContactsSlot()
+ }
+
+ function unban(index){
+ ClientWrapper.settingsAdaptor.unbanContact(index)
+ updateAndShowBannedContactsSlot()
+ }
+
+ Connections {
+ id: accountConnections_ContactModel
+ target: ClientWrapper.contactModel
+
+ function onModelUpdated(uri, needsSorted) {
+ updateAndShowBannedContactsSlot()
+ }
+
+ function onContactAdded(contactUri){
+ updateAndShowBannedContactsSlot()
+ }
+
+ function onContactRemoved(contactUri){
+ updateAndShowBannedContactsSlot()
+ }
+ }
+
+ Connections {
+ id: accountConnections_DeviceModel
+ target: ClientWrapper.deviceModel
+
+ function onDeviceAdded(id) {
+ updateAndShowDevicesSlot()
+ }
+
+ function onDeviceRevoked(id, status) {
+ updateAndShowDevicesSlot()
+ }
+
+ function onDeviceUpdated(id) {
+ updateAndShowDevicesSlot()
+ }
+ }
+
+ // slots
+ function verifyRegisteredNameSlot() {
+ if (ClientWrapper.settingsAdaptor.get_CurrentAccountInfo_RegisteredName() !== "") {
+ regNameUi = CurrentAccountSettingsScrollPage.BLANK
+ } else {
+ registeredName = ClientWrapper.utilsAdaptor.stringSimplifier(
+ currentRegisteredID.text)
+ if (registeredName !== "") {
+ if (ClientWrapper.utilsAdaptor.validateRegNameForm(registeredName)) {
+ regNameUi = CurrentAccountSettingsScrollPage.SEARCHING
+ lookUpLabelTimer.restart()
+ } else {
+ regNameUi = CurrentAccountSettingsScrollPage.INVALIDFORM
+ }
+ } else {
+ regNameUi = CurrentAccountSettingsScrollPage.BLANK
+ }
+ }
+ }
+
+ Timer {
+ id: lookUpLabelTimer
+
+ interval: 300
+ onTriggered: {
+ beforeNameLookup()
+ }
+ }
+
+ function beforeNameLookup() {
+ ClientWrapper.nameDirectory.lookupName("", registeredName)
+ }
+
+ Connections {
+ target: ClientWrapper.nameDirectory
+ enabled: true
+
+ function onRegisteredNameFound(status, address, name) {
+ afterNameLookup(status, name)
+ }
+ }
+
+ function afterNameLookup(status, regName) {
+ if (registeredName === regName && regName.length > 2) {
+ switch (status) {
+ case NameDirectory.LookupStatus.NOT_FOUND:
+ regNameUi = CurrentAccountSettingsScrollPage.FREE
+ break
+ default:
+ regNameUi = CurrentAccountSettingsScrollPage.TAKEN
+ break
+ }
+ } else {
+ regNameUi = CurrentAccountSettingsScrollPage.BLANK
+ }
+ }
+
+ function setAccEnableSlot(state) {
+ ClientWrapper.accountModel.setAccountEnabled(ClientWrapper.utilsAdaptor.getCurrAccId(), state)
+ }
+
+ /*
+ * JamiFileDialog for exporting account
+ */
+ JamiFileDialog {
+ id: exportBtn_Dialog
+
+ mode: JamiFileDialog.SaveFile
+
+ title: qsTr("Export Account Here")
+ folder: StandardPaths.writableLocation(StandardPaths.DesktopLocation)
+
+ nameFilters: [qsTr("Jami archive files") + " (*.gz)", qsTr(
+ "All files") + " (*)"]
+
+ onAccepted: {
+ // is there password? If so, go to password dialog, else, go to following directly
+ var exportPath = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ if (ClientWrapper.accountAdaptor.hasPassword()) {
+ passwordDialog.openDialog(PasswordDialog.ExportAccount,exportPath)
+ return
+ } else {
+ if (exportPath.length > 0) {
+ var isSuccessful = ClientWrapper.accountAdaptor.accoundModel().exportToFile(ClientWrapper.utilsAdaptor.getCurrAccId(), exportPath,"")
+ var title = isSuccessful ? qsTr("Success") : qsTr("Error")
+ var iconMode = isSuccessful ? StandardIcon.Information : StandardIcon.Critical
+ var info = isSuccessful ? qsTr("Export Successful") : qsTr("Export Failed")
+ msgDialog.openWithParameters(title,info, iconMode, StandardButton.Ok)
+ }
+ }
+ }
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+ }
+
+ function exportAccountSlot() {
+ exportBtn_Dialog.open()
+ }
+
+ PasswordDialog {
+ id: passwordDialog
+
+ onDoneSignal: {
+ var success = (code === successCode)
+ var title = success ? qsTr("Success") : qsTr("Error")
+ var iconMode = success ? StandardIcon.Information : StandardIcon.Critical
+
+ var info
+ switch(currentPurpose){
+ case PasswordDialog.ExportAccount:
+ info = success ? qsTr("Export Successful") : qsTr("Export Failed")
+ break
+ case PasswordDialog.ChangePassword:
+ info = success ? qsTr("Password Changed Successfully") : qsTr("Password Change Failed")
+ break
+ case PasswordDialog.SetPassword:
+ info = success ? qsTr("Password Set Successfully") : qsTr("Password Set Failed")
+ passwdPushButton.text = success ? qsTr("Change Password") : qsTr("Set Password")
+ break
+ }
+
+ msgDialog.openWithParameters(title,info, iconMode, StandardButton.Ok)
+ }
+ }
+
+ MessageBox {
+ id: msgDialog
+ }
+
+ function passwordClicked() {
+ if (ClientWrapper.accountAdaptor.hasPassword()){
+ passwordDialog.openDialog(PasswordDialog.ChangePassword)
+ } else {
+ passwordDialog.openDialog(PasswordDialog.SetPassword)
+ }
+ }
+
+ function delAccountSlot() {
+ deleteAccountDialog.open()
+ }
+
+ DeleteAccountDialog{
+ id: deleteAccountDialog
+
+ anchors.centerIn: parent.Center
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+
+ onAccepted: {
+ ClientWrapper.accountAdaptor.setSelectedAccountId()
+ ClientWrapper.accountAdaptor.setSelectedConvId()
+
+ if(ClientWrapper.utilsAdaptor.getAccountListSize() > 0){
+ navigateToMainView()
+ } else {
+ navigateToNewWizardView()
+ }
+ }
+ }
+
+ NameRegistrationDialog{
+ id : nameRegistrationDialog
+
+ onAccepted: {
+ registeredIdNeedsSet = false
+ }
+ }
+
+ function slotRegisterName() {
+ refreshRelevantUI()
+ nameRegistrationDialog.openNameRegistrationDialog(registeredName)
+ }
+
+ LinkDeviceDialog{
+ id: linkDeviceDialog
+
+ onAccepted: {
+ updateAndShowDevicesSlot()
+ }
+ }
+
+ function showLinkDevSlot() {
+ linkDeviceDialog.openLinkDeviceDialog()
+ }
+
+ RevokeDevicePasswordDialog{
+ id: revokeDevicePasswordDialog
+
+ onRevokeDeviceWithPassword:{
+ revokeDeviceWithIDAndPassword(idOfDevice, password)
+ }
+ }
+
+ MessageBox{
+ id: revokeDeviceMessageBox
+
+ property string idOfDev: ""
+
+ title:qsTr("Remove Device")
+ text :qsTr("Are you sure you wish to remove this device?")
+ icon :StandardIcon.Information
+ standardButtons: StandardButton.Ok | StandardButton.Cancel
+
+ onYes: {
+ accepted()
+ }
+
+ onNo:{
+ rejected()
+ }
+
+ onDiscard: {
+ rejected()
+ }
+
+ onAccepted: {
+ revokeDeviceWithIDAndPassword(idOfDev,"")
+ }
+
+ onRejected: {}
+ }
+
+ function removeDeviceSlot(index){
+ var idOfDevice = deviceItemListModel.data(deviceItemListModel.index(index,0), DeviceItemListModel.DeviceID)
+ if(ClientWrapper.accountAdaptor.hasPassword()){
+ revokeDevicePasswordDialog.openRevokeDeviceDialog(idOfDevice)
+ } else {
+ revokeDeviceMessageBox.idOfDev = idOfDevice
+ revokeDeviceMessageBox.open()
+ }
+ }
+
+ function revokeDeviceWithIDAndPassword(idDevice, password){
+ ClientWrapper.deviceModel.revokeDevice(idDevice, password)
+ updateAndShowDevicesSlot()
+ }
+
+ function updateAndShowBannedContactsSlot() {
+ if(bannedListModel.rowCount() <= 0){
+ bannedContactsLayoutWidget.visible = false
+ return
+ }
+
+ bannedListModel.reset()
+ }
+
+ function updateAndShowDevicesSlot() {
+ if(ClientWrapper.settingsAdaptor.getAccountConfig_Manageruri() === ""){
+ linkDevPushButton.visible = true
+ }
+
+ deviceItemListModel.reset()
+ }
+
+ DeviceItemListModel {
+ id: deviceItemListModel
+ }
+
+ BannedListModel{
+ id: bannedListModel
+ }
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 0
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+
+ Layout.alignment: Qt.AlignTop
+ }
+
+ RowLayout {
+ spacing: 6
+
+ Layout.alignment: Qt.AlignTop
+
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: accountPageTitle.height
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.minimumWidth: 30
+ }
+
+ Label {
+ id: accountPageTitle
+
+ Layout.preferredWidth: 117
+
+ Layout.maximumHeight: 25
+ Layout.preferredHeight: 25
+ Layout.minimumHeight: 25
+
+ text: qsTr("Jami Account")
+
+ font.pointSize: 15
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+
+ ScrollView {
+ id: accoutScrollView
+
+ property ScrollBar hScrollBar: ScrollBar.horizontal
+ property ScrollBar vScrollBar: ScrollBar.vertical
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ScrollBar.horizontal.policy: ScrollBar.AsNeeded
+ ScrollBar.vertical.policy: ScrollBar.AsNeeded
+
+ font.pointSize: 8
+ font.kerning: true
+ clip: true
+
+ ColumnLayout {
+ id: accoutnViewLayout
+
+ Layout.fillHeight: true
+ Layout.maximumWidth: 625
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.minimumWidth: 30
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.leftMargin: 30
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 24
+ Layout.preferredWidth: 24
+ Layout.minimumWidth: 24
+ }
+
+ ToggleSwitch {
+ id: accountEnableCheckBox
+
+ labelText: qsTr("Enable")
+ fontPointSize: 11
+
+ onSwitchToggled: {
+ setAccEnableSlot(checked)
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 21
+ Layout.preferredHeight: 21
+ Layout.minimumHeight: 21
+
+ text: qsTr("Profile")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.minimumHeight: 10
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ layoutDirection: Qt.LeftToRight
+
+ spacing: 6
+
+ PhotoboothView {
+ id: currentAccountAvatar
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 261
+ Layout.preferredWidth: 261
+ Layout.minimumWidth: 261
+ Layout.maximumHeight: 261
+ Layout.preferredHeight: 261
+ Layout.minimumHeight: 261
+
+ Layout.leftMargin: 20
+
+ onImageAcquired: {
+ ClientWrapper.settingsAdaptor.setCurrAccAvatar(imgBase64)
+ }
+
+ onImageCleared: {
+ ClientWrapper.settingsAdaptor.clearCurrentAvatar()
+ setAvatar()
+ }
+ }
+
+ InfoLineEdit {
+ id: displayNameLineEdit
+
+ fieldLayoutWidth: 261
+
+ Layout.leftMargin: 20
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.accountAdaptor.setCurrAccDisplayName(
+ displayNameLineEdit.text)
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 21
+ Layout.preferredHeight: 21
+ Layout.minimumHeight: 21
+
+ text: qsTr("Identity")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 10
+ Layout.preferredWidth: 10
+ Layout.minimumWidth: 10
+ }
+
+ ColumnLayout {
+ spacing: 7
+
+ Layout.fillWidth: true
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Layout.leftMargin: 20
+
+ Layout.maximumWidth: 625
+
+ Label {
+ Layout.maximumWidth: 13
+ Layout.preferredWidth: 13
+ Layout.minimumWidth: 13
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Id")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ TextField {
+ id: currentRingID
+
+ property var backgroundColor: "transparent"
+ property var borderColor: "transparent"
+
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 10
+ font.kerning: true
+ font.bold: true
+
+ readOnly: true
+ selectByMouse: true
+
+ text: { refreshVariable
+ return ClientWrapper.settingsAdaptor.getCurrentAccount_Profile_Info_Uri()}
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ background: Rectangle {
+ anchors.fill: parent
+ radius: 0
+ border.color: currentRingID.borderColor
+ border.width: 0
+ color: currentRingID.backgroundColor
+ }
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.maximumHeight: 32
+
+ Layout.leftMargin: 20
+
+ layoutDirection: Qt.LeftToRight
+
+ Label {
+ id: lblRegisteredName
+
+ Layout.maximumWidth: 127
+ Layout.preferredWidth: 127
+ Layout.minimumWidth: 127
+
+ Layout.minimumHeight: 32
+ Layout.preferredHeight: 32
+ Layout.maximumHeight: 32
+
+ text: qsTr("Registered name")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+ Layout.alignment: Qt.AlignVCenter
+
+ TextField {
+ id: currentRegisteredID
+
+ Layout.maximumWidth: 300
+ Layout.preferredWidth: 300
+ Layout.minimumWidth: 300
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ placeholderText: { refreshVariable
+ var result = registeredIdNeedsSet ? qsTr("Type here to register a username") : ""
+ return result}
+
+ text: {
+ refreshVariable
+ if (!registeredIdNeedsSet){
+ return ClientWrapper.settingsAdaptor.get_CurrentAccountInfo_RegisteredName()
+ } else {
+ return ""
+ }
+ }
+ selectByMouse: true
+ readOnly: { refreshVariable
+ return !registeredIdNeedsSet}
+
+ font.pointSize: 10
+ font.kerning: true
+ font.bold: { refreshVariable
+ return !registeredIdNeedsSet}
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ background: Rectangle {
+ anchors.fill: parent
+ radius: {refreshVariable
+ var result = registeredIdNeedsSet ? height / 2 : 0
+ return result}
+ border.color: "transparent"
+ border.width: {refreshVariable
+ var result = registeredIdNeedsSet ? 2 : 0
+ return result}
+ color: {refreshVariable
+ var result = registeredIdNeedsSet ? Qt.rgba(
+ 240 / 256, 240 / 256,
+ 240 / 256,
+ 1.0) : "transparent"
+ return result}
+ }
+
+ onTextEdited: {
+ verifyRegisteredNameSlot()
+ }
+
+ onEditingFinished: {
+ verifyRegisteredNameSlot()
+ }
+ }
+
+ LookupStatusLabel {
+ id: lookupStatusLabel
+
+ visible:{refreshVariable
+ var result = registeredIdNeedsSet
+ && (regNameUi
+ !== CurrentAccountSettingsScrollPage.BLANK)
+ return result}
+
+ MouseArea {
+ id: lookupStatusLabelArea
+ anchors.fill: parent
+ property bool isHovering: false
+
+ onEntered: isHovering = true
+ onExited: isHovering = false
+
+ hoverEnabled: true
+ }
+
+ ToolTip.visible: lookupStatusLabelArea.isHovering
+ ToolTip.text: {
+ switch (regNameUi) {
+ case CurrentAccountSettingsScrollPage.BLANK:
+ return qsTr("")
+ case CurrentAccountSettingsScrollPage.INVALIDFORM:
+ return qsTr("A registered name should not have any spaces and must be at least three letters long")
+ case CurrentAccountSettingsScrollPage.TAKEN:
+ return qsTr("This name is already taken")
+ case CurrentAccountSettingsScrollPage.FREE:
+ return qsTr("Register this name")
+ case CurrentAccountSettingsScrollPage.SEARCHING:
+ return qsTr("")
+ default:
+ return qsTr("")
+ }
+ }
+
+ lookupStatusState: {
+ switch (regNameUi) {
+ case CurrentAccountSettingsScrollPage.BLANK:
+ return "Blank"
+ case CurrentAccountSettingsScrollPage.INVALIDFORM:
+ return "Invalid"
+ case CurrentAccountSettingsScrollPage.TAKEN:
+ return "Taken"
+ case CurrentAccountSettingsScrollPage.FREE:
+ return "Free"
+ case CurrentAccountSettingsScrollPage.SEARCHING:
+ return "Searching"
+ default:
+ return "Blank"
+ }
+ }
+ }
+
+ HoverableRadiusButton {
+ id: btnRegisterName
+
+ visible: {refreshVariable
+ var result = registeredIdNeedsSet
+ && (regNameUi
+ === CurrentAccountSettingsScrollPage.FREE)
+ return result}
+
+ Layout.maximumWidth: 80
+ Layout.preferredWidth: 80
+ Layout.minimumWidth: 80
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Register")
+ font.pointSize: 10
+ font.kerning: true
+
+ radius: height / 2
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Layout.leftMargin: 20
+
+ HoverableButtonTextItem {
+ id: passwdPushButton
+
+ visible: ClientWrapper.settingsAdaptor.getAccountConfig_Manageruri() === ""
+
+ Layout.maximumWidth: 261
+ Layout.preferredWidth: 261
+ Layout.minimumWidth: 261
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+ text: ClientWrapper.accountAdaptor.hasPassword() ? qsTr("Change Password") : qsTr("Set Password")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ radius: height / 2
+
+ onClicked: {
+ passwordClicked()
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Layout.leftMargin: 20
+
+ HoverableButtonTextItem {
+ id: btnExportAccount
+
+ visible: ClientWrapper.settingsAdaptor.getAccountConfig_Manageruri() === ""
+
+ Layout.maximumWidth: 261
+ Layout.preferredWidth: 261
+ Layout.minimumWidth: 261
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Export Account")
+ font.pointSize: 10
+ font.kerning: true
+
+ radius: height / 2
+
+ onClicked: {
+ exportAccountSlot()
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Layout.leftMargin: 20
+
+ HoverableButtonTextItem {
+ id: btnDeletAccount
+
+ backgroundColor: "red"
+ onEnterColor: Qt.rgba(150 / 256, 0, 0, 0.7)
+ onDisabledBackgroundColor: Qt.rgba(
+ 255 / 256,
+ 0, 0, 0.8)
+ onPressColor: backgroundColor
+ textColor: "white"
+
+ Layout.maximumWidth: 261
+ Layout.preferredWidth: 261
+ Layout.minimumWidth: 261
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Delete Account")
+ font.pointSize: 10
+ font.kerning: true
+
+ radius: height / 2
+
+ onClicked: {
+ delAccountSlot()
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.minimumHeight: 27
+
+ text: qsTr("Linked Device")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 10
+ Layout.preferredWidth: 10
+ Layout.minimumWidth: 10
+ }
+
+ ColumnLayout {
+ spacing: 7
+
+ Layout.fillWidth: true
+
+ ListViewJami {
+ id: settingsListView
+
+ Layout.leftMargin: 20
+
+ Layout.fillWidth: true
+
+ Layout.minimumWidth: 580
+ Layout.preferredWidth: 605
+
+ Layout.minimumHeight: 164
+ Layout.preferredHeight: 164
+ Layout.maximumHeight: 164
+
+ model: deviceItemListModel
+
+ delegate: DeviceItemDelegate{
+ id: settingsListDelegate
+
+ width: settingsListView.width
+ height: 85
+
+ deviceName : DeviceName
+ deviceId: DeviceID
+ isCurrent: IsCurrent
+
+ onClicked: {
+ settingsListView.currentIndex = index
+ }
+
+ onBtnRemoveDeviceClicked:{
+ removeDeviceSlot(index)
+ }
+ }
+ }
+
+ HoverableRadiusButton {
+ id: linkDevPushButton
+
+ visible: ClientWrapper.settingsAdaptor.getAccountConfig_Manageruri() === ""
+
+ Layout.leftMargin: 20
+
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ radius: height / 2
+
+ text: qsTr("+Link Another Device")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ showLinkDevSlot()
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ // banned list view
+ ColumnLayout {
+ id: bannedContactsLayoutWidget
+
+ Layout.fillWidth: true
+ spacing: 6
+
+ RowLayout {
+ Layout.leftMargin: 9
+ Layout.rightMargin: 8
+ Layout.topMargin: 1
+
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.preferredWidth: 164
+ Layout.minimumWidth: 164
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ text: qsTr("Banned Contact")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 10
+ Layout.preferredWidth: 10
+ Layout.minimumWidth: 10
+ }
+
+ HoverableRadiusButton {
+ id: bannedContactsBtn
+
+ Layout.maximumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.minimumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ radius: height / 2
+
+ icon.source: bannedContactsListWidget.visible? "qrc:/images/icons/round-arrow_drop_up-24px.svg" : "qrc:/images/icons/round-arrow_drop_down-24px.svg"
+ icon.height: 32
+ icon.width: 32
+
+ onClicked: {
+ toggleBannedContacts()
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ ColumnLayout {
+ id: bannedContactsListWidget
+
+ spacing: 6
+
+ Layout.leftMargin: 9
+ Layout.rightMargin: 8
+ Layout.bottomMargin: 9
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ListViewJami {
+ id: bannedListWidget
+
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+
+ Layout.minimumWidth: 580
+
+ Layout.minimumHeight: 150
+ Layout.preferredHeight: 150
+ Layout.maximumHeight: 150
+
+ model: bannedListModel
+
+ delegate: BannedItemDelegate{
+ id: bannedListDelegate
+
+ width: bannedListWidget.width
+ height: 74
+
+ contactName : ContactName
+ contactID: ContactID
+ contactPicture_base64: ContactPicture
+
+ onClicked: {
+ bannedListWidget.currentIndex = index
+ }
+
+ onBtnReAddContactClicked: {
+ unban(index)
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ HoverableRadiusButton {
+ id: advancedAccountSettingsPButton
+
+ Layout.minimumWidth: 180
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ text: qsTr("Advanced Account Settings")
+ font.pointSize: 10
+ font.kerning: true
+
+ icon.source: {
+ if (advanceSettingsView.visible) {
+ return "qrc:/images/icons/round-arrow_drop_up-24px.svg"
+ } else {
+ return "qrc:/images/icons/round-arrow_drop_down-24px.svg"
+ }
+ }
+
+ icon.height: 24
+ icon.width: 24
+
+ onClicked: {
+ advanceSettingsView.visible = !advanceSettingsView.visible
+ if (advanceSettingsView.visible) {
+ advanceSettingsView.updateAccountInfoDisplayedAdvance()
+ var mappedCoor = advancedAccountSettingsPButton.mapToItem(accoutnViewLayout,advancedAccountSettingsPButton.x,advancedAccountSettingsPButton.y)
+ accoutScrollView.vScrollBar.position = mappedCoor.y / accoutnViewLayout.height
+ } else {
+ accoutScrollView.vScrollBar.position = 0
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 48
+ Layout.preferredHeight: 48
+ Layout.maximumHeight: 48
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.leftMargin: 30
+
+ // instantiate advance setting page
+ AdvancedSettingsView {
+ id: advanceSettingsView
+
+ Layout.leftMargin: 10
+ visible: false
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+}
diff --git a/src/settingsview/components/CurrentSIPAccountSettingScrollPage.qml b/src/settingsview/components/CurrentSIPAccountSettingScrollPage.qml
new file mode 100644
index 0000000..b5d1d2c
--- /dev/null
+++ b/src/settingsview/components/CurrentSIPAccountSettingScrollPage.qml
@@ -0,0 +1,633 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+Rectangle {
+ signal navigateToMainView
+ signal navigateToNewWizardView
+
+ function updateAccountInfoDisplayed() {
+ displaySIPNameLineEdit.text = ClientWrapper.settingsAdaptor.getCurrentAccount_Profile_Info_Alias()
+ usernameSIP.text = ClientWrapper.settingsAdaptor.getAccountConfig_Username()
+ hostnameSIP.text = ClientWrapper.settingsAdaptor.getAccountConfig_Hostname()
+ passSIPlineEdit.text = ClientWrapper.settingsAdaptor.getAccountConfig_Password()
+ proxySIP.text = ClientWrapper.settingsAdaptor.getAccountConfig_ProxyServer()
+
+ accountSIPEnableCheckBox.checked = ClientWrapper.settingsAdaptor.get_CurrentAccountInfo_Enabled()
+
+ setAvatar()
+
+ if (advanceSIPSettingsView.visible) {
+ advanceSIPSettingsView.updateAccountInfoDisplayedAdvanceSIP()
+ }
+ }
+
+ function isPhotoBoothOpened() {
+ return currentSIPAccountAvatar.takePhotoState
+ }
+
+ function setAvatar() {
+ currentSIPAccountAvatar.setAvatarPixmap(
+ ClientWrapper.settingsAdaptor.getAvatarImage_Base64(
+ currentSIPAccountAvatar.boothWidht),
+ ClientWrapper.settingsAdaptor.getIsDefaultAvatar())
+ }
+
+ function stopBooth() {
+ currentSIPAccountAvatar.stopBooth()
+ }
+
+ // slots
+ function setAccEnableSlot(state) {
+ ClientWrapper.accountModel.setAccountEnabled(ClientWrapper.utilsAdaptor.getCurrAccId(), state)
+ }
+
+ function delAccountSlot() {
+ deleteAccountDialog_SIP.open()
+ }
+
+ DeleteAccountDialog{
+ id: deleteAccountDialog_SIP
+
+ anchors.centerIn: parent.Center
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+
+ onAccepted: {
+ ClientWrapper.accountAdaptor.setSelectedAccountId()
+ ClientWrapper.accountAdaptor.setSelectedConvId()
+
+ if(ClientWrapper.utilsAdaptor.getAccountListSize() > 0){
+ navigateToMainView()
+ } else {
+ navigateToNewWizardView()
+ }
+ }
+ }
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 0
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+
+ Layout.alignment: Qt.AlignTop
+ }
+
+ RowLayout {
+ spacing: 6
+
+ Layout.alignment: Qt.AlignTop
+
+ Layout.fillWidth: true
+ Layout.maximumHeight: 31
+ Layout.minimumHeight: 0
+ Layout.preferredHeight: accountPageTitleSIP.height
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 48
+ Layout.preferredWidth: 48
+ Layout.minimumWidth: 48
+ }
+
+ Label {
+ id: accountPageTitleSIP
+
+ Layout.preferredWidth: 133
+
+ Layout.preferredHeight: 31
+ Layout.minimumHeight: 25
+
+ text: qsTr("SIP Account")
+
+ font.pointSize: 15
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+
+ ScrollView {
+ id: accountSIPScrollView
+
+ property ScrollBar hScrollBar: ScrollBar.horizontal
+ property ScrollBar vScrollBar: ScrollBar.vertical
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ScrollBar.horizontal.policy: ScrollBar.AsNeeded
+ ScrollBar.vertical.policy: ScrollBar.AsNeeded
+
+ font.pointSize: 8
+ font.kerning: true
+ clip: true
+
+ ColumnLayout {
+ id: accountSIPLayout
+
+ Layout.fillHeight: true
+ Layout.maximumWidth: 598
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.minimumWidth: 30
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.leftMargin: 48
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 24
+ Layout.preferredWidth: 24
+ Layout.minimumWidth: 24
+ }
+
+ ToggleSwitch {
+ id: accountSIPEnableCheckBox
+
+ labelText: qsTr("Enable")
+ fontPointSize: 10
+
+ onSwitchToggled: {
+ setAccEnableSlot(checked)
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 21
+ Layout.preferredHeight: 21
+ Layout.minimumHeight: 21
+
+ text: qsTr("Profile")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.minimumHeight: 10
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ layoutDirection: Qt.LeftToRight
+
+ spacing: 6
+
+ PhotoboothView {
+ id: currentSIPAccountAvatar
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 261
+ Layout.preferredWidth: 261
+ Layout.minimumWidth: 261
+ Layout.maximumHeight: 261
+ Layout.preferredHeight: 261
+ Layout.minimumHeight: 261
+
+ Layout.leftMargin: 20
+
+ onImageAcquired: {
+ ClientWrapper.settingsAdaptor.setCurrAccAvatar(imgBase64)
+ }
+
+ onImageCleared: {
+ ClientWrapper.settingsAdaptor.clearCurrentAvatar()
+ setAvatar()
+ }
+ }
+
+ InfoLineEdit {
+ id: displaySIPNameLineEdit
+
+ fieldLayoutWidth: 261
+
+ Layout.leftMargin: 20
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.accountAdaptor.setCurrAccDisplayName(
+ displaySIPNameLineEdit.text)
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ spacing: 6
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 27
+ Layout.preferredHeight: 27
+ Layout.minimumHeight: 27
+
+ text: qsTr("Identity")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.minimumHeight: 10
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ spacing: 6
+
+ GridLayout {
+ rows: 4
+ columns: 2
+ flow: GridLayout.LeftToRight
+ rowSpacing: 14
+ columnSpacing: 6
+
+ Layout.fillWidth: true
+
+ Layout.leftMargin: 20
+
+ // user name
+ Label {
+ Layout.maximumWidth: 76
+ Layout.preferredWidth: 76
+ Layout.minimumWidth: 76
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ text: qsTr("Username")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ InfoLineEdit {
+ id: usernameSIP
+
+ fieldLayoutWidth: 300
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setAccountConfig_Username(
+ usernameSIP.text)
+ }
+ }
+
+ // host name
+ Label {
+ Layout.maximumWidth: 76
+ Layout.preferredWidth: 76
+ Layout.minimumWidth: 76
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ text: qsTr("Hostname")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ InfoLineEdit {
+ id: hostnameSIP
+
+ fieldLayoutWidth: 300
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setAccountConfig_Hostname(
+ hostnameSIP.text)
+ }
+ }
+
+ // proxy
+ Label {
+ Layout.maximumWidth: 76
+ Layout.preferredWidth: 76
+ Layout.minimumWidth: 76
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ text: qsTr("Proxy")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ InfoLineEdit {
+ id: proxySIP
+
+ fieldLayoutWidth: 300
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setAccountConfig_ProxyServer(
+ proxySIP.text)
+ }
+ }
+
+ // password
+ Label {
+ Layout.maximumWidth: 76
+ Layout.preferredWidth: 76
+ Layout.minimumWidth: 76
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ text: qsTr("Password")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ InfoLineEdit {
+ id: passSIPlineEdit
+
+ fieldLayoutWidth: 300
+
+ font.pointSize: 10
+ font.kerning: true
+
+ echoMode: TextInput.Password
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ onEditingFinished: {
+ ClientWrapper.settingsAdaptor.setAccountConfig_Password(
+ passSIPlineEdit.text)
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.minimumHeight: 10
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+ Layout.leftMargin: 20
+
+ HoverableButtonTextItem {
+ id: btnSIPDeletAccount
+
+ backgroundColor: "red"
+ onEnterColor: Qt.rgba(150 / 256, 0, 0, 0.7)
+ onDisabledBackgroundColor: Qt.rgba(
+ 255 / 256,
+ 0, 0, 0.8)
+ onPressColor: backgroundColor
+ textColor: "white"
+
+ Layout.maximumWidth: 261
+ Layout.preferredWidth: 261
+ Layout.minimumWidth: 261
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ radius: height / 2
+
+ text: qsTr("Delete Account")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ delAccountSlot()
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 40
+ Layout.preferredHeight: 40
+ Layout.minimumHeight: 40
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ Layout.minimumWidth: 598
+ Layout.preferredWidth: 598
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ HoverableRadiusButton {
+ id: advancedAccountSettingsSIPButton
+
+ Layout.minimumWidth: 180
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ text: qsTr("Advanced Account Settings")
+ font.pointSize: 10
+ font.kerning: true
+
+ icon.source: {
+ if (advanceSIPSettingsView.visible) {
+ return "qrc:/images/icons/round-arrow_drop_up-24px.svg"
+ } else {
+ return "qrc:/images/icons/round-arrow_drop_down-24px.svg"
+ }
+ }
+
+ icon.height: 24
+ icon.width: 24
+
+ onClicked: {
+ advanceSIPSettingsView.visible = !advanceSIPSettingsView.visible
+ if(advanceSIPSettingsView.visible){
+ advanceSIPSettingsView.updateAccountInfoDisplayedAdvanceSIP()
+ var coor = advancedAccountSettingsSIPButton.mapToItem(accountSIPLayout,advancedAccountSettingsSIPButton.x,advancedAccountSettingsSIPButton.y)
+ accountSIPScrollView.vScrollBar.position = coor.y / accountSIPLayout.height
+ } else {
+ accountSIPScrollView.vScrollBar.position = 0
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 48
+ Layout.preferredHeight: 48
+ Layout.maximumHeight: 48
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ Layout.leftMargin: 30
+
+ // instantiate advance setting page
+ AdvancedSIPSettingsView {
+ id: advanceSIPSettingsView
+
+ Layout.leftMargin: 10
+ visible: false
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+}
diff --git a/src/settingsview/components/DeviceItemDelegate.qml b/src/settingsview/components/DeviceItemDelegate.qml
new file mode 100644
index 0000000..f250261
--- /dev/null
+++ b/src/settingsview/components/DeviceItemDelegate.qml
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+ItemDelegate {
+ id: deviceItemDelegate
+
+ property string deviceName : ""
+ property string deviceId: ""
+ property bool isCurrent : false
+
+ property bool editable : false
+
+ signal btnRemoveDeviceClicked
+
+ function btnEditDeviceEnter(){
+ btnEditDevice.enterBtn()
+ }
+
+ function btnEditDeviceExit(){
+ btnEditDevice.exitBtn()
+ }
+
+ function btnEditPress(){
+ btnEditDevice.pressBtn()
+ }
+
+ function btnEditRelease(){
+ btnEditDevice.releaseBtn()
+ }
+
+ function toggleEditable(){
+ editable = !editable
+ if(editable){
+ ClientWrapper.settingsAdaptor.setDeviceName(editDeviceName.text)
+ }
+ }
+
+ highlighted: ListView.isCurrentItem
+
+ RowLayout{
+ anchors.fill: parent
+
+ spacing: 7
+
+ Label{
+ Layout.leftMargin: 7
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ background: Rectangle{
+ anchors.fill: parent
+ Image {
+ anchors.fill: parent
+ source: "qrc:/images/icons/baseline-desktop_windows-24px.svg"
+ }
+ }
+ }
+
+ ColumnLayout{
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+
+ InfoLineEdit{
+ id: editDeviceName
+
+ Layout.fillWidth: true
+ Layout.minimumWidth: 0
+ Layout.maximumWidth: 16777215
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ font.pointSize: 8
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ readOnly: !editable
+
+ text: deviceName
+ }
+
+ RowLayout{
+ Layout.maximumWidth: editDeviceName.fieldLayoutWidth
+
+ Layout.minimumHeight: 30
+
+ Label{
+ id: labelDeviceId
+
+ //Layout.minimumWidth: 71
+ Layout.minimumHeight: 30
+
+ font.pointSize: 8
+ font.kerning: true
+ text: deviceId === "" ? qsTr("Device Id") : deviceId
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.minimumWidth: 0
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ id: labelThisDevice
+
+ //Layout.minimumWidth: 80
+ Layout.minimumHeight: 30
+
+ visible: isCurrent
+
+ font.pointSize: 8
+ font.kerning: true
+ font.italic: true
+ color: "green"
+ text: qsTr("this device")
+ }
+ }
+ }
+
+ HoverableRadiusButton{
+ id: btnEditDevice
+
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ source:{
+ if(isCurrent) {
+ var path = editable ? "qrc:/images/icons/round-edit-24px.svg" : "qrc:/images/icons/round-save_alt-24px.svg"
+ return path
+ } else {
+ return "qrc:/images/icons/round-remove_circle-24px.svg"
+ }
+ }
+
+ ToolTip.visible: isHovering
+ ToolTip.text: {
+ if(isCurrent) {
+ if(editable){
+ return qsTr("Edit Device Name")
+ } else {
+ return qsTr("Save new device name")
+ }
+ } else {
+ return qsTr("Unlink Device From Account")
+ }
+ }
+
+ onClicked: {
+ if(isCurrent) {
+ toggleEditable()
+ } else {
+ btnRemoveDeviceClicked()
+ }
+ }
+ }
+
+ Item{
+ Layout.rightMargin: 7
+
+ Layout.minimumWidth: 8
+ Layout.preferredWidth: 8
+ Layout.maximumWidth: 8
+
+ Layout.minimumHeight: 20
+ }
+ }
+}
diff --git a/src/settingsview/components/GeneralSettingsPage.qml b/src/settingsview/components/GeneralSettingsPage.qml
new file mode 100644
index 0000000..72eb4d1
--- /dev/null
+++ b/src/settingsview/components/GeneralSettingsPage.qml
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import Qt.labs.platform 1.1
+import QtGraphicalEffects 1.14
+import net.jami.Models 1.0
+import "../../commoncomponents"
+
+Rectangle {
+ id: generalSettingsRect
+
+ function populateGeneralSettings(){
+ // settings
+ closeOrMinCheckBox.checked = ClientWrapper.settingsAdaptor.getSettingsValue_CloseOrMinimized()
+ applicationOnStartUpCheckBox.checked = ClientWrapper.utilsAdaptor.checkStartupLink()
+ notificationCheckBox.checked = ClientWrapper.settingsAdaptor.getSettingsValue_EnableNotifications()
+
+ alwaysRecordingCheckBox.checked = ClientWrapper.avmodel.getAlwaysRecord()
+ recordPreviewCheckBox.checked = ClientWrapper.avmodel.getRecordPreview()
+ recordQualityValueLabel.text = ClientWrapper.utilsAdaptor.getRecordQualityString(ClientWrapper.avmodel.getRecordQuality() / 100)
+ recordQualitySlider.value = ClientWrapper.avmodel.getRecordQuality() / 100
+
+ ClientWrapper.avmodel.setRecordPath(ClientWrapper.settingsAdaptor.getDir_Document())
+
+ autoUpdateCheckBox.checked = ClientWrapper.settingsAdaptor.getSettingsValue_AutoUpdate()
+ }
+
+ function slotSetNotifications(state){
+ ClientWrapper.settingsAdaptor.setNotifications(state)
+ }
+
+ function slotSetClosedOrMin(state){
+ ClientWrapper.settingsAdaptor.setClosedOrMin(state)
+ }
+
+ function slotSetRunOnStartUp(state){
+ ClientWrapper.settingsAdaptor.setRunOnStartUp(state)
+ }
+
+ function slotSetUpdateAutomatic(state){
+ ClientWrapper.settingsAdaptor.setUpdateAutomatic(state)
+ }
+
+ function slotAlwaysRecordingClicked(state){
+ ClientWrapper.avmodel.setAlwaysRecord(state)
+ }
+
+ function slotRecordPreviewClicked(state){
+ ClientWrapper.avmodel.setRecordPreview(state)
+ }
+
+ function slotRecordQualitySliderValueChanged(value){
+ recordQualityValueLabel.text = ClientWrapper.utilsAdaptor.getRecordQualityString(value)
+ updateRecordQualityTimer.restart()
+ }
+
+ Timer{
+ id: updateRecordQualityTimer
+
+ interval: 500
+
+ onTriggered: {
+ slotRecordQualitySliderSliderReleased()
+ }
+ }
+
+ function slotRecordQualitySliderSliderReleased(){
+ var value = recordQualitySlider.value
+ ClientWrapper.avmodel.setRecordQuality(value * 100)
+ }
+
+ function openDownloadFolderSlot(){
+ downloadPathDialog.open()
+ }
+
+ FolderDialog {
+ id: downloadPathDialog
+
+ title: qsTr("Select A Folder For Your Downloads")
+ currentFolder: StandardPaths.writableLocation(StandardPaths.DownloadLocation)
+
+ onAccepted: {
+ var dir = ClientWrapper.utilsAdaptor.getAbsPath(folder.toString())
+ downloadPath = dir
+ }
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+ }
+
+ function openRecordFolderSlot(){
+ recordPathDialog.open()
+ }
+
+ FolderDialog {
+ id: recordPathDialog
+
+ title: qsTr("Select A Folder For Your Recordings")
+ currentFolder: StandardPaths.writableLocation(StandardPaths.HomeLocation)
+
+ onAccepted: {
+ var dir = ClientWrapper.utilsAdaptor.getAbsPath(folder.toString())
+ recordPath = dir
+ }
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+ }
+
+ //TODO: complete check for update and check for Beta slot functions
+ function checkForUpdateSlot(){}
+ function installBetaSlot(){}
+
+ // settings
+ property string downloadPath: ClientWrapper.settingsAdaptor.getDir_Download()
+
+ // recording
+ //property AVModel avmodel: ClientWrapper.accountAdaptor.avModel()
+ property string recordPath: ClientWrapper.settingsAdaptor.getDir_Document()
+
+ onDownloadPathChanged: {
+ if(downloadPath === "") return
+ ClientWrapper.settingsAdaptor.setDownloadPath(downloadPath)
+ }
+
+ onRecordPathChanged: {
+ if(recordPath === "") return
+
+ if(ClientWrapper.avmodel){
+ ClientWrapper.avmodel.setRecordPath(recordPath)
+ }
+ }
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ScrollView{
+ anchors.fill: parent
+ clip: true
+
+ RowLayout {
+ width: generalSettingsRect.width
+ height: generalSettingsRect.height
+
+ spacing: 0
+
+ Item {
+ Layout.fillHeight: true
+ Layout.maximumWidth: 48
+ Layout.preferredWidth: 48
+ Layout.minimumWidth: 48
+ }
+
+ ColumnLayout {
+ spacing: 6
+
+ Layout.fillHeight: true
+ Layout.maximumWidth: 580
+ Layout.preferredWidth: 580
+ Layout.minimumWidth: 580
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ Label {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 25
+ Layout.preferredHeight: 25
+ Layout.maximumHeight: 25
+
+ text: qsTr("General")
+ font.pointSize: 15
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 24
+ Layout.preferredHeight: 24
+ Layout.maximumHeight: 24
+ }
+
+ // system setting panel
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 21
+ Layout.preferredHeight: 21
+ Layout.maximumHeight: 21
+
+ text: qsTr("System")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ ToggleSwitch {
+ id: notificationCheckBox
+
+ Layout.leftMargin: 20
+
+ labelText: "Enable desktop notifications"
+ fontPointSize: 11
+
+ onSwitchToggled: {
+ slotSetNotifications(checked)
+ }
+ }
+
+ ToggleSwitch {
+ id: closeOrMinCheckBox
+
+ Layout.leftMargin: 20
+
+ labelText: "Keep minimize on close"
+ fontPointSize: 11
+
+ onSwitchToggled: {
+ slotSetClosedOrMin(checked)
+ }
+ }
+
+ ToggleSwitch {
+ id: applicationOnStartUpCheckBox
+
+ Layout.leftMargin: 20
+
+ labelText: "Run on Startup"
+ fontPointSize: 11
+
+ onSwitchToggled: {
+ slotSetRunOnStartUp(checked)
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 94
+ Layout.preferredWidth: 94
+ Layout.minimumWidth: 94
+
+ text: qsTr("Download folder")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ HoverableRadiusButton {
+ id: downloadButton
+
+ Layout.maximumWidth: 320
+ Layout.preferredWidth: 320
+ Layout.minimumWidth: 320
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.height: 24
+ icon.width: 24
+
+ text: downloadPath
+ fontPointSize: 10
+
+ onClicked: {
+ openDownloadFolderSlot()
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ // call recording setting panel
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ Label {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 21
+ Layout.preferredHeight: 21
+ Layout.maximumHeight: 21
+
+ text: qsTr("Call Recording")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ ToggleSwitch {
+ id: alwaysRecordingCheckBox
+
+ Layout.leftMargin: 20
+
+ labelText: "Always record calls"
+ fontPointSize: 11
+
+ onSwitchToggled: {
+ slotAlwaysRecordingClicked(checked)
+ }
+ }
+
+ ToggleSwitch {
+ id: recordPreviewCheckBox
+
+ Layout.leftMargin: 20
+
+ labelText: "Record preview video for a call"
+ fontPointSize: 11
+
+ onSwitchToggled: {
+ slotRecordPreviewClicked(checked)
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 42
+ Layout.preferredWidth: 42
+ Layout.minimumWidth: 42
+
+ text: qsTr("Quality")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ ColumnLayout {
+ spacing: 0
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: recordQualityValueLabel.width
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ Label {
+ id: recordQualityValueLabel
+
+ Layout.minimumWidth: 40
+
+ Layout.minimumHeight: 16
+ Layout.preferredHeight: 16
+ Layout.maximumHeight: 16
+
+ text: qsTr("VALUE ")
+
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ Slider{
+ id: recordQualitySlider
+
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 320
+ Layout.preferredWidth: 320
+ Layout.minimumWidth: 320
+
+ from: 0
+ to: 500
+ stepSize: 1
+
+ onMoved: {
+ slotRecordQualitySliderValueChanged(value)
+ }
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Label {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 42
+ Layout.preferredWidth: 42
+ Layout.minimumWidth: 42
+
+ text: qsTr("Save in")
+ font.pointSize: 10
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ HoverableRadiusButton {
+ id: recordPathButton
+
+ Layout.maximumWidth: 320
+ Layout.preferredWidth: 320
+ Layout.minimumWidth: 320
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/round-folder-24px.svg"
+ icon.height: 24
+ icon.width: 24
+
+ text: recordPath
+ fontPointSize: 10
+
+ onClicked: {
+ openRecordFolderSlot()
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ }
+
+ // update setting panel
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ visible: Qt.platform.os == "windows"? true : false
+
+ Label {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 21
+ Layout.preferredHeight: 21
+ Layout.maximumHeight: 21
+
+ text: qsTr("Updates")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: 10
+ Layout.preferredHeight: 10
+ Layout.maximumHeight: 10
+ }
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillWidth: true
+
+ ToggleSwitch {
+ id: autoUpdateCheckBox
+
+ Layout.leftMargin: 20
+
+ labelText: "Check for updates automatically"
+ fontPointSize: 11
+
+ onSwitchToggled: {
+ slotSetUpdateAutomatic(checked)
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ HoverableRadiusButton {
+ id: checkUpdateButton
+
+ Layout.maximumWidth: 275
+ Layout.preferredWidth: 275
+ Layout.minimumWidth: 275
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ text: "Check for updates now"
+ fontPointSize: 10
+
+ onClicked: {
+ checkForUpdateSlot()
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ RowLayout {
+ spacing: 6
+
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ HoverableRadiusButton {
+ id: installBetaButton
+
+ Layout.maximumWidth: 275
+ Layout.preferredWidth: 275
+ Layout.minimumWidth: 275
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ text: "Install the latest beta version"
+ fontPointSize: 10
+
+ onClicked: {
+ installBetaSlot()
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ // spacer on the bottom
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/IconButton.qml b/src/settingsview/components/IconButton.qml
new file mode 100644
index 0000000..7e992a9
--- /dev/null
+++ b/src/settingsview/components/IconButton.qml
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtQuick.Controls.Universal 2.12
+import QtGraphicalEffects 1.14
+
+import "../../constant"
+
+Button {
+ id: button
+ checkable: true
+ hoverEnabled: true
+
+ property alias imageSource: buttonPix.source
+ property alias buttonText: buttonText.text
+
+ property string backgroundColor: JamiTheme.releaseColor
+ property string onPressColor: JamiTheme.pressColor
+ property string onReleaseColor: JamiTheme.releaseColor
+ property string onEnterColor: JamiTheme.hoverColor
+ property string onExitColor: JamiTheme.transparentColor
+ property string checkedColor: JamiTheme.releaseColor
+
+ signal checkedToggledForLeftPanel(var checked)
+ signal checkedToggledForRightPanel(var checked)
+
+ function setCheckedState(check, triggerSignal) {
+ button.checked = check
+ if (triggerSignal) {
+ checkedToggledForLeftPanel(check)
+ checkedToggledForRightPanel(check)
+ }
+ button.background.color = check ? button.checkedColor : button.onExitColor
+ }
+
+ onClicked: {
+ setCheckedState(true, true)
+ }
+
+ Layout.minimumHeight: 60
+ Layout.preferredHeight: 60
+ Layout.maximumHeight: 60
+
+ Layout.fillWidth: true
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: parent.checked ? button.checkedColor : button.onExitColor
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: 24
+ Image {
+ id: buttonPix
+ Layout.minimumHeight: 24
+ Layout.preferredHeight: 24
+ Layout.maximumHeight: 24
+
+ Layout.minimumWidth: 24
+ Layout.preferredWidth: 24
+ Layout.maximumWidth: 24
+
+ Layout.leftMargin: 24
+
+ Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
+ }
+
+ Label {
+ id: buttonText
+
+ Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ font.pointSize: 11
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ hoverEnabled: true
+
+ onPressed: {
+ if (!button.checked) {
+ parent.color = button.onPressColor
+ }
+ }
+ onReleased: {
+ button.clicked()
+ if (!button.checked) {
+ parent.color = button.onExitColor
+ }
+ }
+ onEntered: {
+ if (!button.checked) {
+ parent.color = button.onEnterColor
+ }
+ }
+ onExited: {
+ if (!button.checked) {
+ parent.color = button.onExitColor
+ }
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/LeftPanelView.qml b/src/settingsview/components/LeftPanelView.qml
new file mode 100644
index 0000000..f11fe23
--- /dev/null
+++ b/src/settingsview/components/LeftPanelView.qml
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 1.4 as CT
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+
+import "../../commoncomponents"
+
+ScrollView{
+ id: leftPanelView
+
+ property int contentViewportWidth: 200
+ property int contentViewPortHeight: 768
+
+ property alias btnAccountSettings: accountSettingsButton
+ property alias btnGeneralSettings: generalSettingsButton
+ property alias btnMediaSettings: mediaSettingsButton
+ property alias btnPluginSettings: pluginSettingsButton
+
+ signal btnExitClicked
+
+ Component.onCompleted: {
+ accountSettingsButton.setCheckedState(true, true)
+ }
+
+ anchors.fill: parent
+ clip: true
+
+ ColumnLayout {
+ spacing: 0
+
+ width: contentViewportWidth
+ height: contentViewPortHeight
+
+ Item {
+ Layout.fillWidth: true
+ Layout.maximumHeight: 13
+ Layout.preferredHeight: 13
+ Layout.minimumHeight: 13
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+
+ Layout.rightMargin: 14
+
+ Item {
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ Label {
+ Layout.maximumWidth: 57
+ Layout.preferredWidth: 57
+ Layout.minimumWidth: 57
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ text: qsTr("Settings")
+ font.pointSize: 12
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ HoverableRadiusButton {
+ id: btnExitSettings
+ Layout.maximumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.minimumWidth: 30
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+ backgroundColor: "transparent"
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/round-close-24px.svg"
+ icon.height: 24
+ icon.width: 24
+
+ onClicked: {
+ btnExitClicked()
+ }
+ }
+ }
+ Item {
+ Layout.fillWidth: true
+ Layout.maximumHeight: 13
+ Layout.preferredHeight: 13
+ Layout.minimumHeight: 13
+ }
+
+ IconButton {
+ id: accountSettingsButton
+
+ buttonText: qsTr("Account")
+ imageSource: "qrc:/images/icons/baseline-people-24px.svg"
+
+ onCheckedToggledForLeftPanel: {
+ generalSettingsButton.setCheckedState(!checked, false)
+ mediaSettingsButton.setCheckedState(!checked, false)
+ pluginSettingsButton.setCheckedState(!checked, false)
+ }
+ }
+
+ IconButton {
+ id: generalSettingsButton
+
+ buttonText: qsTr("General")
+ imageSource: "qrc:/images/icons/round-settings-24px.svg"
+
+ onCheckedToggledForLeftPanel: {
+ accountSettingsButton.setCheckedState(!checked, false)
+ mediaSettingsButton.setCheckedState(!checked, false)
+ pluginSettingsButton.setCheckedState(!checked, false)
+ }
+ }
+
+ IconButton {
+ id: mediaSettingsButton
+
+ buttonText: qsTr("Audio/Video")
+ imageSource: "qrc:/images/icons/baseline-desktop_windows-24px.svg"
+
+ onCheckedToggledForLeftPanel: {
+ generalSettingsButton.setCheckedState(!checked, false)
+ accountSettingsButton.setCheckedState(!checked, false)
+ pluginSettingsButton.setCheckedState(!checked, false)
+ }
+ }
+
+ IconButton {
+ id: pluginSettingsButton
+
+ buttonText: qsTr("Plugins")
+ imageSource: "qrc:/images/icons/extension_24dp.svg"
+
+ onCheckedToggledForLeftPanel: {
+ generalSettingsButton.setCheckedState(!checked, false)
+ accountSettingsButton.setCheckedState(!checked, false)
+ mediaSettingsButton.setCheckedState(!checked, false)
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+
+}
+
diff --git a/src/settingsview/components/LevelMeter.qml b/src/settingsview/components/LevelMeter.qml
new file mode 100644
index 0000000..045d329
--- /dev/null
+++ b/src/settingsview/components/LevelMeter.qml
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+ProgressBar {
+ id: levelMeter
+
+ value: {
+ return clamp(rmsLevel * 300.0, 0.0, 100.0)
+ }
+
+ property real rmsLevel: 0
+
+ function clamp(num,a,b){
+ return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b))
+ }
+
+ function start(){
+ rmsLevel = 0
+ }
+
+ function stop(){
+
+ }
+
+ function setLevel(rmsLevelIn){
+ rmsLevel = rmsLevelIn
+ }
+
+}
diff --git a/src/settingsview/components/LinkDeviceDialog.qml b/src/settingsview/components/LinkDeviceDialog.qml
new file mode 100644
index 0000000..c1caca1
--- /dev/null
+++ b/src/settingsview/components/LinkDeviceDialog.qml
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+Dialog {
+ id: linkDeviceDialog
+
+ function openLinkDeviceDialog(){
+ infoLabel.text = qsTr("This pin and the account password should be entered in your device within 10 minutes.")
+ passwordEdit.clear()
+ linkDeviceDialog.open()
+ if(ClientWrapper.accountAdaptor.hasPassword()){
+ stackedWidget.currentIndex = 0
+ } else {
+ setGeneratingPage()
+ }
+ }
+
+ function setGeneratingPage(){
+ if(passwordEdit.length === 0 && ClientWrapper.accountAdaptor.hasPassword()){
+ setExportPage(NameDirectory.ExportOnRingStatus.WRONG_PASSWORD, "")
+ return
+ }
+
+ stackedWidget.currentIndex = 1
+ spinnerMovie.playing = true
+
+ timerForExport.restart()
+ }
+
+ function slotExportOnRing(){
+ ClientWrapper.accountModel.exportOnRing(ClientWrapper.utilsAdaptor.getCurrAccId(),passwordEdit.text)
+ }
+
+ Timer{
+ id: timerForExport
+
+ repeat: false
+ interval: 200
+
+ onTriggered: {
+ timeOut.restart()
+ slotExportOnRing()
+ }
+ }
+
+ Timer{
+ id: timeOut
+
+ repeat: false
+ interval: exportTimeout
+
+ onTriggered: {
+ setExportPage(NameDirectory.ExportOnRingStatus.NETWORK_ERROR, "")
+ }
+ }
+
+ function setExportPage(status, pin){
+ timeOut.stop()
+
+ if(status === NameDirectory.ExportOnRingStatus.SUCCESS){
+ infoLabel.isSucessState = true
+ yourPinLabel.visible = true
+ exportedPIN.visible = true
+ infoLabel.text = qsTr("This pin and the account password should be entered in your device within 10 minutes.")
+ exportedPIN.text = pin
+ } else {
+ infoLabel.isSucessState = false
+ yourPinLabel.visible = false
+ exportedPIN.visible = false
+
+ switch(status){
+ case NameDirectory.ExportOnRingStatus.WRONG_PASSWORD:
+ infoLabel.text = qsTr("Incorrect password")
+
+ break
+ case NameDirectory.ExportOnRingStatus.NETWORK_ERROR:
+ infoLabel.text = qsTr("Error connecting to the network.\nPlease try again later.")
+
+ break
+ case NameDirectory.ExportOnRingStatus.INVALID:
+ infoLabel.text = qsTr("Something went wrong.\n")
+
+ break
+ }
+ }
+ stackedWidget.currentIndex = 2
+ }
+
+ property int exportTimeout : 20000
+
+ Connections{
+ target: ClientWrapper.nameDirectory
+
+ function onExportOnRingEnded(status, pin){
+ setExportPage(status, pin)
+ }
+ }
+
+ visible: false
+
+ anchors.centerIn: parent.Center
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+
+ title: qsTr("Link another device")
+
+ onClosed: {
+ if(infoLabel.isSucessState){
+ accept()
+ } else {
+ reject()
+ }
+ }
+
+ contentItem: Rectangle{
+ implicitWidth: 365
+ implicitHeight: 208
+
+ StackLayout{
+ id: stackedWidget
+ anchors.fill: parent
+
+ currentIndex: 2
+
+ Rectangle{
+ id: passwordConfirmPage
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.leftMargin: 11
+ Layout.rightMargin: 11
+ Layout.topMargin: 11
+ Layout.bottomMargin: 11
+
+ ColumnLayout{
+ anchors.fill: parent
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ Layout.preferredWidth: 219
+ Layout.alignment: Qt.AlignHCenter
+ wrapMode: Text.Wrap
+ text: qsTr("Enter your account password")
+ font.pointSize: 8
+ font.kerning: true
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ InfoLineEdit{
+ id: passwordEdit
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.minimumWidth: 294
+ Layout.preferredWidth: 294
+
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ echoMode: TextInput.Password
+
+ placeholderText: qsTr("Password")
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ RowLayout{
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ HoverableRadiusButton{
+ id: btnPasswordOk
+
+ Layout.maximumWidth: 130
+ Layout.preferredWidth: 130
+ Layout.minimumWidth: 130
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ radius: height /2
+
+ text: qsTr("Register")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ setGeneratingPage()
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+ Layout.minimumWidth: 40
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ HoverableButtonTextItem {
+ id: btnCancel
+
+ Layout.maximumWidth: 130
+ Layout.preferredWidth: 130
+ Layout.minimumWidth: 130
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ backgroundColor: "red"
+ onEnterColor: Qt.rgba(150 / 256, 0, 0, 0.7)
+ onDisabledBackgroundColor: Qt.rgba(
+ 255 / 256,
+ 0, 0, 0.8)
+ onPressColor: backgroundColor
+ textColor: "white"
+
+ radius: height /2
+
+ text: qsTr("Cancel")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ reject()
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+ Layout.minimumWidth: 40
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+ }
+
+ Rectangle{
+ id: exportingPage
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.leftMargin: 11
+ Layout.rightMargin: 11
+ Layout.topMargin: 11
+ Layout.bottomMargin: 11
+
+ ColumnLayout{
+ anchors.fill: parent
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+ Layout.minimumHeight: 40
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ Layout.fillWidth: true
+ spacing: 0
+
+ Layout.maximumHeight: 30
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 0
+ Layout.preferredWidth: 341
+
+ Layout.minimumHeight: 0
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ wrapMode: Text.Wrap
+ text: qsTr("Exporting Account")
+ font.pointSize: 8
+ font.kerning: true
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ spacing: 7
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ id: exportingSpinner
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 96
+ Layout.preferredWidth: 96
+ Layout.minimumWidth: 96
+
+ Layout.maximumHeight: 96
+ Layout.preferredHeight: 96
+ Layout.minimumHeight: 96
+
+ background: Rectangle {
+ anchors.fill: parent
+ AnimatedImage {
+ id: spinnerMovie
+
+ anchors.fill: parent
+
+ source: "qrc:/images/jami_eclipse_spinner.gif"
+
+ playing: exportingSpinner.visible
+ paused: false
+ fillMode: Image.PreserveAspectFit
+ mipmap: true
+ }
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+ Layout.minimumHeight: 40
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+ }
+ }
+
+ Rectangle{
+ id: exportedPage
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.leftMargin: 11
+ Layout.rightMargin: 11
+ Layout.topMargin: 11
+ Layout.bottomMargin: 11
+
+ ColumnLayout{
+ anchors.fill: parent
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ id: yourPinLabel
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.preferredHeight: 25
+
+ wrapMode: Text.Wrap
+ text: "Your PIN is:"
+ font.pointSize: 8
+ font.kerning: true
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ id: exportedPIN
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.preferredHeight: 25
+
+ wrapMode: Text.Wrap
+ text: "PIN"
+ font.pointSize: 12
+ font.kerning: true
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ RowLayout{
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ id: infoLabel
+
+ property bool isSucessState: false
+ property int borderWidth : isSucessState? 1 : 0
+ property int borderRadius : isSucessState? 15 : 0
+ property string backgroundColor : isSucessState? "whitesmoke" : "transparent"
+ property string borderColor : isSucessState? "lightgray" : "transparent"
+ color: isSucessState ? "#2b5084" : "black"
+ padding: isSucessState ? 8 : 0
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: 320
+ Layout.preferredHeight: 50
+
+ wrapMode: Text.Wrap
+ text: qsTr("This pin and the account password should be entered in your device within 10 minutes.")
+ font.pointSize: 8
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ background: Rectangle{
+ id: infoLabelBackground
+
+ anchors.fill: parent
+ border.width: infoLabel.borderWidth
+ border.color: infoLabel.borderColor
+ radius: infoLabel.borderRadius
+ color: infoLabel.backgroundColor
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ HoverableRadiusButton{
+ id: btnCloseExportDialog
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 130
+ Layout.preferredWidth: 130
+ Layout.minimumWidth: 130
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ radius: height /2
+
+ text: qsTr("Close")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ if(infoLabel.isSucessState){
+ accept()
+ } else {
+ reject()
+ }
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/NameRegistrationDialog.qml b/src/settingsview/components/NameRegistrationDialog.qml
new file mode 100644
index 0000000..ab9988d
--- /dev/null
+++ b/src/settingsview/components/NameRegistrationDialog.qml
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+Dialog {
+ id: nameRegistrationDialog
+
+ property string registerdName : ""
+
+ function openNameRegistrationDialog(registerNameIn){
+ registerdName = registerNameIn
+ lblRegistrationError.text = qsTr("Something went wrong")
+ passwordEdit.clear()
+ if(ClientWrapper.accountAdaptor.hasPassword()){
+ stackedWidget.currentIndex = 0
+ } else {
+ startRegistration()
+ }
+
+ nameRegistrationDialog.open()
+ }
+
+ function startRegistration(){
+ startSpinner()
+ timerForStartRegistration.restart()
+ }
+
+ function slotStartNameRegistration(){
+ var password = passwordEdit.text
+ ClientWrapper.accountModel.registerName(ClientWrapper.utilsAdaptor.getCurrAccId(), password, registerdName)
+ }
+
+ function startSpinner(){
+ stackedWidget.currentIndex = 1
+ spinnerLabel.visible = true
+ spinnerMovie.playing = true
+ }
+
+ Timer{
+ id: timerForStartRegistration
+
+ interval: 100
+ repeat: false
+
+ onTriggered: {
+ slotStartNameRegistration()
+ }
+ }
+
+ Connections{
+ target: ClientWrapper.nameDirectory
+
+ function onNameRegistrationEnded(status, name){
+ if(status === NameDirectory.RegisterNameStatus.SUCCESS){
+ accept()
+ } else {
+ switch(status){
+ case NameDirectory.RegisterNameStatus.WRONG_PASSWORD:
+ lblRegistrationError.text = qsTr("Incorrect password")
+ break
+
+ case NameDirectory.RegisterNameStatus.NETWORK_ERROR:
+ lblRegistrationError.text = qsTr("Network error")
+ break
+ default:
+ break
+ }
+ stackedWidget.currentIndex = 2
+ }
+ }
+ }
+
+ visible: false
+
+ anchors.centerIn: parent.Center
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+
+ title: qsTr("Set Registered Name")
+
+ onClosed: {
+ reject()
+ }
+
+ contentItem: Rectangle{
+ implicitWidth: 365
+ implicitHeight: 208
+
+ StackLayout{
+ id: stackedWidget
+ anchors.fill: parent
+
+ currentIndex: 0
+
+ Rectangle{
+ id: passwordConfirmPage
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.leftMargin: 11
+ Layout.rightMargin: 11
+ Layout.topMargin: 11
+ Layout.bottomMargin: 11
+
+ ColumnLayout{
+ anchors.fill: parent
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ Layout.preferredWidth: 219
+ Layout.alignment: Qt.AlignHCenter
+ wrapMode: Text.Wrap
+ text: qsTr("Enter your account password")
+ font.pointSize: 8
+ font.kerning: true
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ InfoLineEdit{
+ id: passwordEdit
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.minimumWidth: 294
+ Layout.preferredWidth: 294
+
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ echoMode: TextInput.Password
+
+ placeholderText: qsTr("Password")
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ RowLayout{
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillWidth: true
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ HoverableRadiusButton{
+ id: btnRegister
+
+ Layout.maximumWidth: 130
+ Layout.preferredWidth: 130
+ Layout.minimumWidth: 130
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ radius: height /2
+
+ text: qsTr("Register")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ startRegistration()
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+ Layout.minimumWidth: 40
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ HoverableButtonTextItem {
+ id: btnCancel
+
+ Layout.maximumWidth: 130
+ Layout.preferredWidth: 130
+ Layout.minimumWidth: 130
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ backgroundColor: "red"
+ onEnterColor: Qt.rgba(150 / 256, 0, 0, 0.7)
+ onDisabledBackgroundColor: Qt.rgba(
+ 255 / 256,
+ 0, 0, 0.8)
+ onPressColor: backgroundColor
+ textColor: "white"
+
+ radius: height /2
+
+ text: qsTr("Cancel")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ reject()
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+ Layout.minimumWidth: 40
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+ }
+
+ Rectangle{
+ id: registeringPage
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.leftMargin: 11
+ Layout.rightMargin: 11
+ Layout.topMargin: 11
+ Layout.bottomMargin: 11
+
+ ColumnLayout{
+ anchors.fill: parent
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+ Layout.minimumHeight: 40
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ Layout.fillWidth: true
+ spacing: 0
+
+ Layout.maximumHeight: 30
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 0
+ Layout.preferredWidth: 341
+
+ Layout.minimumHeight: 0
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ wrapMode: Text.Wrap
+ text: qsTr("Registering Name")
+ font.pointSize: 8
+ font.kerning: true
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ spacing: 7
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ id: spinnerLabel
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 96
+ Layout.preferredWidth: 96
+ Layout.minimumWidth: 96
+
+ Layout.maximumHeight: 96
+ Layout.preferredHeight: 96
+ Layout.minimumHeight: 96
+
+ background: Rectangle {
+ anchors.fill: parent
+ AnimatedImage {
+ id: spinnerMovie
+
+ anchors.fill: parent
+
+ source: "qrc:/images/jami_eclipse_spinner.gif"
+
+ playing: spinnerLabel.visible
+ paused: false
+ fillMode: Image.PreserveAspectFit
+ mipmap: true
+ }
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ }
+
+ Item{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillHeight: true
+ Layout.minimumHeight: 40
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+ }
+ }
+
+ Rectangle{
+ id: nameNotRegisteredPage
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ ColumnLayout{
+ anchors.fill: parent
+
+ Item{
+ Layout.fillHeight: true
+ Layout.minimumHeight: 40
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ spacing: 7
+ Layout.fillWidth: true
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ Label{
+ id: lblRegistrationError
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.maximumWidth: 0
+ Layout.preferredWidth: 341
+
+ Layout.minimumHeight: 0
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ wrapMode: Text.Wrap
+ text: qsTr("Something went wrong")
+ font.pointSize: 8
+ font.kerning: true
+ color: "red"
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.minimumHeight: 40
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ spacing: 7
+ Layout.fillWidth: true
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ HoverableRadiusButton{
+ id: btnCloseRegisterDialog
+
+ Layout.maximumWidth: 130
+ Layout.preferredWidth: 130
+ Layout.minimumWidth: 130
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ radius: height /2
+
+ text: qsTr("Close")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ reject()
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+ }
+
+ Item{
+ Layout.fillHeight: true
+ Layout.minimumHeight: 40
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/PluginItemDelegate.qml b/src/settingsview/components/PluginItemDelegate.qml
new file mode 100644
index 0000000..3946a15
--- /dev/null
+++ b/src/settingsview/components/PluginItemDelegate.qml
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+ItemDelegate {
+ id: pluginItemDelegate
+
+ property string pluginName : ""
+ property string pluginId: ""
+ property string pluginIcon: ""
+ property bool isLoaded: false
+
+ signal btnLoadPluginToggled
+ signal btnPreferencesPluginClicked
+
+ highlighted: ListView.isCurrentItem
+
+ RowLayout{
+ anchors.fill: parent
+
+ Label{
+ Layout.leftMargin: 7
+ Layout.bottomMargin: 7
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ background: Rectangle{
+ anchors.fill: parent
+ Image {
+ anchors.fill: parent
+ source: "file:"+pluginIcon
+ }
+ }
+ }
+
+ ColumnLayout{
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.leftMargin: 7
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+
+ RowLayout{
+
+ Layout.minimumHeight: 30
+
+ Label{
+ id: labelDeviceId
+
+ Layout.minimumHeight: 20
+
+ font.pointSize: 10
+ font.kerning: true
+ text: pluginName === "" ? pluginId : pluginName
+ }
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.minimumWidth: 0
+ Layout.minimumHeight: 20
+ }
+ }
+ }
+
+ Switch {
+ id: loadSwitch
+ property bool isHovering: false
+
+ Layout.bottomMargin: 7
+ Layout.rightMargin: 15
+
+ Layout.maximumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.minimumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ ToolTip.visible: isHovering
+ ToolTip.text: {
+ return qsTr("Load/Unload")
+ }
+
+ checked: isLoaded
+ onClicked: {
+ btnLoadPluginToggled()
+ }
+
+ background: Rectangle {
+ id: switchBackground
+ MouseArea {
+ id: btnMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onPressed: {
+ }
+ onReleased: {
+ loadSwitch.clicked()
+ }
+ onEntered: {
+ loadSwitch.isHovering = true
+ }
+ onExited: {
+ loadSwitch.isHovering = false
+ }
+ }
+ }
+ }
+
+ HoverableRadiusButton{
+ id: btnPreferencesPlugin
+
+ Layout.bottomMargin: 7
+ Layout.rightMargin: 7
+ Layout.alignment: Qt.AlignRight
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ source:{
+ return "qrc:/images/icons/round-settings-24px.svg"
+ }
+
+ ToolTip.visible: isHovering
+ ToolTip.text: {
+ return qsTr("Edit preferences")
+ }
+
+ onClicked: {
+ btnPreferencesPluginClicked()
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/PluginListPreferencesView.qml b/src/settingsview/components/PluginListPreferencesView.qml
new file mode 100644
index 0000000..9b8c03a
--- /dev/null
+++ b/src/settingsview/components/PluginListPreferencesView.qml
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import Qt.labs.platform 1.1
+import QtGraphicalEffects 1.14
+import net.jami.Models 1.0
+import "../../commoncomponents"
+
+Rectangle {
+ id: pluginListPreferencesViewRect
+
+ enum Type {
+ LIST,
+ DEFAULT
+ }
+
+ signal updatePluginList
+
+ property string pluginName: ""
+ property string pluginIcon: ""
+ property string pluginId: ""
+ property bool isLoaded: false
+ property int size: 0
+
+ visible: false
+
+ function updatePreferenceListDisplayed(show){
+ // settings
+ getSize(pluginId, show)
+ preferenceItemListModel.pluginId = pluginId
+ preferenceItemListModel.reset()
+ }
+
+ function resetPluginSlot(){
+ resetPluginMessageBox.open()
+ }
+
+ function resetPlugin(){
+ ClientWrapper.pluginModel.resetPluginPreferencesValues(pluginId, isLoaded)
+ updatePluginList()
+ }
+
+ function uninstallPluginSlot(){
+ uninstallPluginMessageBox.open()
+ }
+
+ function uninstallPlugin(){
+ ClientWrapper.pluginModel.uninstallPlugin(pluginId)
+ updatePluginList()
+ }
+
+ function getSize(pluginId, show){
+ size = 50 * ClientWrapper.pluginModel.getPluginPreferences(pluginId).length
+ if (show) {
+ height = 200 + size
+ pluginPreferenceView.height = size
+ } else {
+ height = 25
+ }
+ }
+
+ function editPreferenceSlot(preferenceType, preferenceName, preferenceEntryValues){
+ switch (preferenceType){
+ case PluginListPreferencesView.LIST:
+ console.log("LIST")
+ editListMessageBox.preferenceName = preferenceName
+ editListMessageBox.preferenceEntryValues = preferenceEntryValues
+ editListMessageBox.open()
+ break
+ case PluginListPreferencesView.DEFAULT:
+ console.log("Unrecognizable Type")
+ break
+ default:
+ console.log("Unrecognizable Type")
+ break
+ }
+ }
+
+ function setPreference(pluginId, preferenceKey, preferenceNewValue)
+ {
+ ClientWrapper.pluginModel.setPluginPreferences(pluginId, preferenceKey, preferenceNewValue, isLoaded)
+ preferenceItemListModel.reset()
+ }
+
+ MessageBox{
+ id: uninstallPluginMessageBox
+
+ title:qsTr("Uninstall plugin")
+ text :qsTr("Are you sure you wish to uninstall " + pluginName + " ?")
+ standardButtons: StandardButton.Ok | StandardButton.Cancel
+
+ onYes: {
+ accepted()
+ }
+
+ onNo:{
+ rejected()
+ }
+
+ onDiscard: {
+ rejected()
+ }
+
+ onAccepted: {
+ uninstallPlugin()
+ pluginListPreferencesViewRect.visible = false
+ }
+
+ onRejected: {}
+ }
+
+ MessageBox{
+ id: resetPluginMessageBox
+
+ title:qsTr("Reset preferences")
+ text :qsTr("Are you sure you wish to reset "+ pluginName + " preferences?")
+
+ standardButtons: StandardButton.Ok | StandardButton.Cancel
+
+ onYes: {
+ accepted()
+ }
+
+ onNo:{
+ rejected()
+ }
+
+ onDiscard: {
+ rejected()
+ }
+
+ onAccepted: {
+ resetPlugin()
+ }
+
+ onRejected: {}
+ }
+
+ MessageBox{
+ id: editListMessageBox
+
+ property string preferenceName: ""
+ property var preferenceEntryValues: []
+
+ title:qsTr("Edit " + preferenceName)
+ text :qsTr(preferenceName + " options: " + preferenceEntryValues)
+
+ standardButtons: StandardButton.Ok | StandardButton.Cancel
+
+ onYes: {
+ accepted()
+ }
+
+ onNo:{
+ rejected()
+ }
+
+ onDiscard: {
+ rejected()
+ }
+
+ onAccepted: {
+ // setPreference(pluginId, preferenceItemDelegate.preferenceKey, preferenceItemDelegate.preferenceNewValue)
+ }
+
+ onRejected: {}
+ }
+
+ PreferenceItemListModel {
+ id: preferenceItemListModel
+ }
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ spacing: 6
+ Layout.fillHeight: true
+ Layout.maximumWidth: 580
+ Layout.preferredWidth: 580
+ Layout.minimumWidth: 580
+
+ Label{
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ background: Rectangle{
+ anchors.fill: parent
+ Image {
+ anchors.fill: parent
+ source: "file:"+pluginIcon
+ }
+ }
+ }
+
+ Label {
+ Layout.alignment: Qt.AlignHCenter
+ Layout.topMargin: 10
+ Layout.fillWidth: true
+ Layout.minimumHeight: 25
+ Layout.preferredHeight: 25
+ Layout.maximumHeight: 25
+
+ text: qsTr(pluginName + "\npreferences")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ RowLayout {
+ spacing: 6
+ Layout.fillWidth: true
+ Layout.topMargin: 10
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ HoverableRadiusButton {
+ id: resetButton
+
+ Layout.maximumWidth: 157
+ Layout.preferredWidth: 157
+ Layout.minimumWidth: 157
+
+ Layout.fillHeight: true
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/settings_backup_restore-black-18dp.svg"
+ icon.height: 24
+ icon.width: 24
+
+ text: qsTr("Reset")
+ fontPointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ resetPluginSlot()
+ }
+ }
+
+ HoverableRadiusButton {
+ id: uninstallButton
+
+ Layout.maximumWidth: 157
+ Layout.preferredWidth: 157
+ Layout.minimumWidth: 157
+
+ Layout.fillHeight: true
+
+ radius: height / 2
+
+ icon.source: "qrc:/images/icons/ic_delete_black_18dp_2x.png"
+ icon.height: 24
+ icon.width: 24
+
+ text: qsTr("Uninstall")
+ fontPointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ uninstallPluginSlot()
+ }
+ }
+ }
+
+ ListViewJami {
+ id: pluginPreferenceView
+
+ Layout.minimumWidth: 320
+ Layout.preferredWidth: 320
+ Layout.maximumWidth: 320
+
+ Layout.minimumHeight: 0
+ Layout.preferredHeight: height
+ Layout.maximumHeight: 1000
+
+ model: preferenceItemListModel
+
+ delegate: PreferenceItemDelegate{
+ id: preferenceItemDelegate
+
+ width: pluginPreferenceView.width
+ height: 50
+
+ preferenceKey : PreferenceKey
+ preferenceName: PreferenceName
+ preferenceSummary: PreferenceSummary
+ preferenceType: PreferenceType
+ preferenceDefaultValue: PreferenceDefaultValue
+ preferenceEntries: PreferenceEntries
+ preferenceEntryValues: PreferenceEntryValues
+
+ onClicked: {
+ pluginPreferenceView.currentIndex = index
+ }
+ onBtnPreferenceClicked: {
+ console.log("edit preference ", preferenceName)
+ console.log("preference type ", preferenceType)
+ console.log("preference entry values ", preferenceEntryValues.length)
+ editPreferenceSlot(preferenceType, preferenceName, preferenceEntryValues)
+ }
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/PluginListSettingsView.qml b/src/settingsview/components/PluginListSettingsView.qml
new file mode 100644
index 0000000..09434a3
--- /dev/null
+++ b/src/settingsview/components/PluginListSettingsView.qml
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import Qt.labs.platform 1.1
+import QtGraphicalEffects 1.14
+import net.jami.Models 1.0
+import "../../commoncomponents"
+
+Rectangle {
+ id: pluginListSettingsViewRect
+
+ property PluginListPreferencesView pluginListPreferencesView
+ visible: false
+ signal scrollView
+
+ function updatePluginListDisplayed() {
+ // settings
+ }
+
+ function openPluginFileSlot(){
+ pluginPathDialog.open()
+ }
+
+ function updateAndShowPluginsSlot()
+ {
+ pluginItemListModel.reset()
+ }
+
+ function loadPluginSlot(pluginId, isLoaded){
+ var loaded = false
+ if (isLoaded)
+ ClientWrapper.pluginModel.unloadPlugin(pluginId)
+ else
+ loaded = ClientWrapper.pluginModel.loadPlugin(pluginId)
+ if(pluginListPreferencesView.pluginId === pluginId)
+ pluginListPreferencesView.isLoaded = loaded
+ updateAndShowPluginsSlot()
+ }
+
+ function openPreferencesPluginSlot(pluginName, pluginIcon, pluginId, isLoaded){
+ updateAndShowPluginPreferenceSlot(pluginName, pluginIcon, pluginId, isLoaded)
+ }
+
+ function updateAndShowPluginPreferenceSlot(pluginName, pluginIcon, pluginId, isLoaded){
+ pluginListPreferencesView.pluginName = pluginName
+ pluginListPreferencesView.pluginIcon = pluginIcon
+ pluginListPreferencesView.pluginId = pluginId
+ pluginListPreferencesView.isLoaded = isLoaded
+ pluginListPreferencesView.updatePreferenceListDisplayed(!pluginListPreferencesView.visible)
+ pluginListPreferencesView.visible = !pluginListPreferencesView.visible
+ scrollView()
+ }
+
+ JamiFileDialog {
+ id: pluginPathDialog
+
+ mode: JamiFileDialog.OpenFile
+ title: qsTr("Select A Plugin to Install")
+ folder: StandardPaths.writableLocation(StandardPaths.DownloadLocation)
+
+ nameFilters: [qsTr("Plugin Files") + " (*.jpl)", qsTr(
+ "All files") + " (*)"]
+
+ onRejected: {}
+
+ onVisibleChanged: {
+ if (!visible) {
+ rejected()
+ }
+ }
+
+ onAccepted: {
+ var url = ClientWrapper.utilsAdaptor.getAbsPath(file.toString())
+ ClientWrapper.pluginModel.installPlugin(url, true)
+ updateAndShowPluginsSlot()
+ }
+ }
+
+ PluginItemListModel {
+ id: pluginItemListModel
+ }
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ id: pluginListViewLayout
+
+ Layout.fillHeight: true
+ Layout.maximumWidth: 580
+ Layout.preferredWidth: 580
+ Layout.minimumWidth: 580
+
+ Label {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 25
+ Layout.preferredHeight: 25
+ Layout.maximumHeight: 25
+
+ text: qsTr("Installed plugins")
+ font.pointSize: 13
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ ColumnLayout {
+ spacing: 6
+
+ Layout.fillWidth: true
+ Layout.topMargin: 6
+
+ HoverableRadiusButton {
+ id: installButton
+
+ Layout.leftMargin: 20
+
+ Layout.maximumWidth: 320
+ Layout.preferredWidth: 320
+ Layout.minimumWidth: 320
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ radius: height / 2
+
+ text: qsTr("+ Install plugin")
+ fontPointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ openPluginFileSlot()
+ }
+ }
+
+ ListViewJami {
+ id: pluginListView
+
+ Layout.leftMargin: 20
+
+ Layout.minimumWidth: 320
+ Layout.preferredWidth: 320
+ Layout.maximumWidth: 320
+
+ Layout.minimumHeight: 175
+ Layout.preferredHeight: 175
+ Layout.maximumHeight: 175
+
+ model: pluginItemListModel
+
+ delegate: PluginItemDelegate{
+ id: pluginItemDelegate
+
+ width: pluginListView.width
+ height: 50
+
+ pluginName : PluginName
+ pluginId: PluginId
+ pluginIcon: PluginIcon
+ isLoaded: IsLoaded
+
+ onClicked: {
+ pluginListView.currentIndex = index
+ }
+
+ onBtnLoadPluginToggled:{
+ loadPluginSlot(pluginId, isLoaded)
+ }
+
+ onBtnPreferencesPluginClicked:{
+ openPreferencesPluginSlot(pluginName, pluginIcon, pluginId, isLoaded)
+ }
+ }
+ }
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/src/settingsview/components/PluginSettingsPage.qml b/src/settingsview/components/PluginSettingsPage.qml
new file mode 100644
index 0000000..b71f7aa
--- /dev/null
+++ b/src/settingsview/components/PluginSettingsPage.qml
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import Qt.labs.platform 1.1
+import QtGraphicalEffects 1.14
+import net.jami.Models 1.0
+import "../../commoncomponents"
+
+Rectangle {
+ id: pluginSettingsRect
+
+ function populatePluginSettings(){
+ // settings
+ enabledplugin.checked = ClientWrapper.pluginModel.getPluginsEnabled()
+ pluginListSettingsView.visible = enabledplugin.checked
+ if (pluginListSettingsView.visible) {
+ pluginListSettingsView.updatePluginListDisplayed()
+ }
+ }
+
+ function slotSetPluginEnabled(state){
+ ClientWrapper.pluginModel.setPluginsEnabled(state)
+ }
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 6
+
+ width: parent.width
+ height: parent.height
+
+ Label {
+ width: parent.width
+ height: parent.height
+
+ Layout.leftMargin: 35
+ Layout.topMargin: 15
+ Layout.alignment: Qt.AlignTop
+
+ text: qsTr("Plugin")
+
+ font.pointSize: 15
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignBottom
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ ScrollView {
+ id: pluginScrollView
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ width: parent.width
+ height: parent.height
+ focus: true
+
+ clip: true
+
+ ColumnLayout {
+ id: pluginViewLayout
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ToggleSwitch {
+ id: enabledplugin
+
+ Layout.topMargin: 15
+ Layout.leftMargin: 36
+
+ labelText: "Enable"
+ fontPointSize: 13
+
+ onSwitchToggled: {
+ slotSetPluginEnabled(checked)
+
+ pluginListSettingsView.visible = checked
+ if (!checked) {
+ pluginListPreferencesView.visible = checked
+ }
+ if (pluginListSettingsView.visible) {
+ pluginListSettingsView.updatePluginListDisplayed()
+ }
+ }
+ }
+ ColumnLayout {
+ spacing: 6
+ Layout.fillHeight: true
+ width:380
+ height:100
+
+ // instantiate plugin list setting page
+ PluginListSettingsView {
+ id: pluginListSettingsView
+
+ width:380
+ height:265
+ Layout.leftMargin: 35
+ Layout.topMargin: 15
+ Layout.alignment: Qt.AlignHCenter
+
+ pluginListPreferencesView: pluginListPreferencesView
+
+ onScrollView:{ }
+ }
+
+ PluginListPreferencesView {
+ id: pluginListPreferencesView
+
+ width:380
+ Layout.minimumHeight: 175
+ Layout.preferredHeight: height
+ Layout.maximumHeight: 1000
+ Layout.alignment: Qt.AlignHCenter
+ Layout.leftMargin: 55
+
+ onUpdatePluginList:{
+ pluginListSettingsView.updateAndShowPluginsSlot()
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/PreferenceItemDelegate.qml b/src/settingsview/components/PreferenceItemDelegate.qml
new file mode 100644
index 0000000..88574f2
--- /dev/null
+++ b/src/settingsview/components/PreferenceItemDelegate.qml
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+import "../../commoncomponents"
+
+ItemDelegate {
+ id: preferenceItemDelegate
+
+ property string preferenceKey: ""
+ property string preferenceName: ""
+ property string preferenceSummary: ""
+ property int preferenceType: -1
+ property string preferenceDefaultValue: ""
+ property var preferenceEntries: []
+ property var preferenceEntryValues: []
+ property string preferenceNewValue: ""
+
+ signal btnPreferenceClicked
+
+ highlighted: ListView.isCurrentItem
+
+ RowLayout{
+ anchors.fill: parent
+
+ ColumnLayout{
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+ Layout.leftMargin: 7
+
+ Layout.minimumHeight: 30
+
+ Label{
+ Layout.minimumHeight: 10
+ width: 320 - 36
+
+ font.pointSize: 10
+ font.kerning: true
+ font.bold: true
+ text: preferenceName
+ }
+ }
+
+ HoverableRadiusButton{
+ id: btnPreference
+
+ Layout.alignment: Qt.AlignRight
+ Layout.bottomMargin: 7
+ Layout.rightMargin: 7
+
+ Layout.minimumWidth: 30
+ Layout.preferredWidth: 30
+ Layout.maximumWidth: 30
+
+ Layout.minimumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.maximumHeight: 30
+
+ buttonImageHeight: height
+ buttonImageWidth: height
+
+ source:{
+ return "qrc:/images/icons/round-settings-24px.svg"
+ }
+
+ ToolTip.visible: isHovering
+ ToolTip.text: {
+ return qsTr("Modify preference")
+ }
+
+ onClicked: {
+ btnPreferenceClicked()
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/RevokeDevicePasswordDialog.qml b/src/settingsview/components/RevokeDevicePasswordDialog.qml
new file mode 100644
index 0000000..69d433f
--- /dev/null
+++ b/src/settingsview/components/RevokeDevicePasswordDialog.qml
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtQuick.Controls.Styles 1.4
+
+import "../../commoncomponents"
+
+Dialog {
+ id: revokeDevicePasswordDialog
+
+ property string deviceId : ""
+
+ signal revokeDeviceWithPassword(string idOfDevice, string password)
+
+ function openRevokeDeviceDialog(deviceIdIn){
+ deviceId = deviceIdIn
+ passwordEdit.clear()
+ revokeDevicePasswordDialog.open()
+ }
+
+ visible: false
+
+ anchors.centerIn: parent.Center
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+
+ title: qsTr("Enter this account's password to confirm the removal of this device")
+
+ onClosed: {
+ reject()
+ }
+
+ onAccepted:{
+ revokeDeviceWithPassword(deviceId,passwordEdit.text)
+ }
+
+ contentItem: Rectangle{
+ implicitWidth: 365
+ implicitHeight: 120
+
+ ColumnLayout{
+ anchors.fill: parent
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ InfoLineEdit{
+ id: passwordEdit
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.minimumWidth: 294
+ Layout.preferredWidth: 294
+
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ echoMode: TextInput.Password
+
+ placeholderText: qsTr("Password")
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+
+ RowLayout{
+ spacing: 7
+
+ Layout.alignment: Qt.AlignHCenter
+
+ Layout.fillWidth: true
+
+ Item{
+ Layout.fillWidth: true
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ HoverableRadiusButton{
+ id: btnOkay
+
+ Layout.maximumWidth: 130
+ Layout.preferredWidth: 130
+ Layout.minimumWidth: 130
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ radius: height /2
+
+ text: qsTr("Okay")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ accept()
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+ Layout.minimumWidth: 40
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ HoverableButtonTextItem {
+ id: btnCancel
+
+ Layout.maximumWidth: 130
+ Layout.preferredWidth: 130
+ Layout.minimumWidth: 130
+
+ Layout.maximumHeight: 30
+ Layout.preferredHeight: 30
+ Layout.minimumHeight: 30
+
+ backgroundColor: "red"
+ onEnterColor: Qt.rgba(150 / 256, 0, 0, 0.7)
+ onDisabledBackgroundColor: Qt.rgba(
+ 255 / 256,
+ 0, 0, 0.8)
+ onPressColor: backgroundColor
+ textColor: "white"
+
+ radius: height /2
+
+ text: qsTr("Cancel")
+ font.pointSize: 10
+ font.kerning: true
+
+ onClicked: {
+ reject()
+ }
+ }
+
+ Item{
+ Layout.fillWidth: true
+ Layout.minimumWidth: 40
+
+ Layout.maximumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.minimumHeight: 20
+ }
+
+ }
+
+ Item{
+ Layout.fillHeight: true
+
+ Layout.maximumWidth: 20
+ Layout.preferredWidth: 20
+ Layout.minimumWidth: 20
+ }
+ }
+ }
+}
diff --git a/src/settingsview/components/SettingParaCombobox.qml b/src/settingsview/components/SettingParaCombobox.qml
new file mode 100644
index 0000000..b691acb
--- /dev/null
+++ b/src/settingsview/components/SettingParaCombobox.qml
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+
+ComboBox {
+ id: control
+
+ delegate: ItemDelegate {
+ width: control.width
+ contentItem: Text {
+ text: {
+ var currentItem = control.delegateModel.items.get(index)
+ return currentItem.model[control.textRole].toString()
+ }
+ color: "black"
+ font: control.font
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+ highlighted: control.highlightedIndex === index
+ }
+
+ indicator: Canvas {
+ id: canvas
+ x: control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ width: 12
+ height: 8
+ contextType: "2d"
+
+ Connections {
+ target: control
+ function onPressedChanged(){
+ canvas.requestPaint()
+ }
+ }
+
+ onPaint: {
+ context.reset();
+ context.moveTo(0, 0);
+ context.lineTo(width, 0);
+ context.lineTo(width / 2, height);
+ context.closePath();
+ context.fillStyle = control.pressed ? "#17a81a" : "#21be2b";
+ context.fill();
+ }
+ }
+
+ contentItem: Text {
+ leftPadding: 0
+ rightPadding: control.indicator.width + control.spacing
+
+ text: control.displayText
+ font: control.font
+ color: "black"
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: Rectangle {
+ implicitWidth: 120
+ implicitHeight: 40
+ border.color: "white"
+ border.width: control.visualFocus ? 2 : 1
+ radius: 2
+ }
+
+ popup: Popup {
+ y: control.height - 1
+ width: control.width
+ implicitHeight: contentItem.implicitHeight
+ padding: 1
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+
+ ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: Rectangle {
+ border.color: "gray"
+ radius: 2
+ }
+ }
+}
diff --git a/src/settingsview/components/ToggleSwitch.qml b/src/settingsview/components/ToggleSwitch.qml
new file mode 100644
index 0000000..27c84bd
--- /dev/null
+++ b/src/settingsview/components/ToggleSwitch.qml
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+
+RowLayout {
+ property string labelText: value
+ property int widthOfSwitch: 50
+ property int heightOfSwitch: 10
+ property int heightOfLayout: 30
+ property int fontPointSize: 13
+
+ property alias toggleSwitch: switchOfLayout
+ property alias checked: switchOfLayout.checked
+
+ signal switchToggled
+
+ spacing: 18
+ Layout.fillWidth: true
+ Layout.maximumHeight: 30
+
+ Switch {
+ id: switchOfLayout
+ Layout.alignment: Qt.AlignVCenter
+
+ Layout.maximumWidth: widthOfSwitch
+ Layout.preferredWidth: widthOfSwitch
+ Layout.minimumWidth: widthOfSwitch
+
+ Layout.minimumHeight: heightOfSwitch
+ Layout.preferredHeight: heightOfSwitch
+ Layout.maximumHeight: heightOfSwitch
+
+ onToggled: {
+ switchToggled()
+ }
+ }
+
+ Label {
+ Layout.fillWidth: true
+
+ Layout.minimumHeight: heightOfLayout
+ Layout.preferredHeight: heightOfLayout
+ Layout.maximumHeight: heightOfLayout
+
+ text: qsTr(labelText)
+ font.pointSize: fontPointSize
+ font.kerning: true
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/settingsview/components/VideoCodecDelegate.qml b/src/settingsview/components/VideoCodecDelegate.qml
new file mode 100644
index 0000000..a01fd28
--- /dev/null
+++ b/src/settingsview/components/VideoCodecDelegate.qml
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019-2020 by Savoir-faire Linux
+ * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Universal 2.12
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.14
+import QtQuick.Controls.Styles 1.4
+import net.jami.Models 1.0
+
+ItemDelegate {
+ id: videoCodecDelegate
+
+ property string videoCodecName : ""
+ property bool isEnabled : false
+ property int videoCodecId
+
+ signal videoCodecStateChange(string idToSet , bool isToBeEnabled)
+
+ property int checkBoxWidth: 10
+
+ highlighted: ListView.isCurrentItem
+
+ RowLayout{
+ anchors.fill: parent
+
+ spacing: 10
+
+ CheckBox{
+ id: checkBoxIsEnabled
+
+ Layout.leftMargin: 20
+
+ Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
+ Layout.fillHeight: true
+
+ Layout.minimumWidth: checkBoxWidth
+ Layout.preferredWidth: checkBoxWidth
+ Layout.maximumWidth: checkBoxWidth
+
+ tristate: false
+ checkState: isEnabled ? Qt.Checked : Qt.Unchecked
+
+ indicator.implicitWidth: checkBoxWidth
+ indicator.implicitHeight:checkBoxWidth
+
+ indicator.layer.textureSize.width: checkBoxWidth
+ indicator.layer.textureSize.height: checkBoxWidth
+
+ text: ""
+
+ nextCheckState: function() {
+ var result
+ var result_bool
+
+ if (checkState === Qt.Checked){
+ result = Qt.Unchecked
+ result_bool = false
+ } else {
+ result = Qt.Checked
+ result_bool = true
+ }
+ videoCodecStateChange(videoCodecId,result_bool)
+ return result
+ }
+ }
+
+ Label{
+ id: formatNameLabel
+
+ Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ text: videoCodecName
+ font.pointSize: 8
+ font.kerning: true
+ }
+ }
+}