diff --git a/src/accountview/qml/accountdialog.qml b/src/accountview/qml/accountdialog.qml index 59e26ab0..394d69ed 100644 --- a/src/accountview/qml/accountdialog.qml +++ b/src/accountview/qml/accountdialog.qml @@ -1,134 +1,135 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import org.kde.kirigami 2.2 as Kirigami import QtQuick.Controls 2.2 import QtQuick.Layouts 1.0 import RingQmlWidgets 1.0 import Ring 1.0 import "Pages/" as Pages import net.lvindustries.ringqtquick 1.0 as RingQtQuick import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews +import net.lvindustries.ringqtquick 1.0 as RingQtQuick Dialog { id: accountDialog standardButtons: Dialog.Save | Dialog.Cancel property var profilePage: undefined parent: applicationWindow().contentItem x: applicationWindow().contentItem.width / 2 - width/2 y: applicationWindow().contentItem.height / 2 - height/2 width: applicationWindow().contentItem.width * 0.85 height: applicationWindow().contentItem.height * 0.85 onAccepted: { if (accountTree.selectedAccount) { if (profilePage) profilePage.save() - accountTree.selectedAccount.performAction(Account.SAVE) + accountTree.selectedAccount.performAction(RingQtQuick.Account.SAVE) } } onRejected: { if (accountTree.selectedAccount) { - accountTree.selectedAccount.performAction(Account.CANCEL) + accountTree.selectedAccount.performAction(RingQtQuick.Account.CANCEL) } } RowLayout { anchors.fill: parent Accounts { id: accountTree Layout.fillHeight: true Layout.preferredWidth: 300 Layout.maximumWidth: 300 } KQuickItemViews.IndexView { Layout.fillHeight: true Layout.fillWidth: true modelIndex: accountTree.selectedAccount ? accountTree.selectedAccount.index : undefined clip: true delegate: RingQtQuick.AccountFields { anchors.fill: parent account: object ColumnLayout { anchors.fill: parent TabBar { id: pageTabs Layout.fillWidth: true TabButton { text: i18n("Basic") } TabButton { text: i18n("Profile") } TabButton { text: i18n("Advanced") } TabButton { text: i18n("Network") } TabButton { text: i18n("Devices") } TabButton { text: i18n("Codecs") } TabButton { text: i18n("Credentials") } TabButton { text: i18n("Security") } TabButton { text: i18n("Ringtones") } } SwipeView { currentIndex: pageTabs.currentIndex interactive : false Layout.fillHeight: true Layout.fillWidth: true Pages.Basic {} Pages.Profiles { id: prof Component.onCompleted: { accountDialog.profilePage = prof } } Pages.Advanced {} Pages.Network {} Pages.Devices {} Pages.Codecs {} Pages.Credentials {} Pages.Security {} Pages.Ringtones {} } } } } } } diff --git a/src/accountview/qml/accountlist.qml b/src/accountview/qml/accountlist.qml index 33c0f3db..4063e1fb 100644 --- a/src/accountview/qml/accountlist.qml +++ b/src/accountview/qml/accountlist.qml @@ -1,296 +1,297 @@ /*************************************************************************** * Copyright (C) 2018 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Layouts 1.0 import RingQmlWidgets 1.0 import Ring 1.0 import QtQuick.Controls 2.2 import ContactView 1.0 import org.kde.kirigami 2.2 as Kirigami import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews +import net.lvindustries.ringqtquick 1.0 as RingQtQuick ListView { id: accountList interactive: false height: totalHeight implicitHeight: totalHeight model: AccountModel property real totalHeight: footerItem + contentHeight + headerItem + 10 property real footerItem: 0 property real headerItem: 0 property bool enableAdd: true Component { id: accountErrorComponent RowLayout { anchors.fill: parent Image { Layout.fillHeight: true fillMode: Image.PreserveAspectFit width: parent.width sourceSize.width: 22 sourceSize.height: 22 horizontalAlignment: Image.AlignHCenter source: "image://SymbolicColorizer/:/sharedassets/outline/warning.svg" } Label { Layout.fillWidth: true Layout.fillHeight: true text: error color: activePalette.text wrapMode: Text.WordWrap width: parent.width } } } Component { id: defaultAccountComponent RowLayout { CheckBox { Layout.fillHeight: true Layout.preferredWidth: Kirigami.Units.fontMetrics.height * 2 Layout.minimumWidth: Kirigami.Units.fontMetrics.height * 2 checked: obj.enabled onClicked: { obj.enabled = checked - obj.performAction(Account.SAVE) + obj.performAction(RingQtQuick.Account.SAVE) } } Rectangle { height: Kirigami.Units.fontMetrics.height * 0.66 width: Kirigami.Units.fontMetrics.height * 0.66 radius: 99 - color: obj.registrationState == Account.READY ? + color: obj.registrationState == RingQtQuick.Account.READY ? Kirigami.Theme.positiveTextColor : ( - obj.registrationState == Account.TRYING ? + obj.registrationState == RingQtQuick.Account.TRYING ? Kirigami.Theme.neutralTextColor : Kirigami.Theme.negativeTextColor ) } Label { Layout.fillHeight: true Layout.fillWidth: true text: obj.alias } Item { Layout.fillHeight: true KQuickItemViews.DecorationAdapter { pixmap: secIcon anchors.verticalCenter: parent.verticalCenter height: (Kirigami.Units.fontMetrics.height * 2) - 6 width: (Kirigami.Units.fontMetrics.height * 2) - 6 } } // Do not cover the handle Item { width: (Kirigami.Units.fontMetrics.height * 2) } } } Component { id: errorComponent RowLayout { anchors.fill: parent CheckBox { Layout.fillHeight: true Layout.preferredWidth: Kirigami.Units.fontMetrics.height * 2 Layout.minimumWidth: Kirigami.Units.fontMetrics.height * 2 checked: obj.enabled onClicked: { obj.enabled = checked - obj.performAction(Account.SAVE) + obj.performAction(RingQtQuick.Account.SAVE) } } Rectangle { height: Kirigami.Units.fontMetrics.height * 0.66 width: Kirigami.Units.fontMetrics.height * 0.66 radius: 99 - color: obj.registrationState == Account.READY ? + color: obj.registrationState == RingQtQuick.Account.READY ? Kirigami.Theme.positiveTextColor : ( - obj.registrationState == Account.TRYING ? + obj.registrationState == RingQtQuick.Account.TRYING ? Kirigami.Theme.neutralTextColor : Kirigami.Theme.negativeTextColor ) } ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true Loader { property string error: obj.lastErrorMessage property int code: obj.lastErrorCode id: accountError Layout.minimumHeight: active ? Kirigami.Units.fontMetrics.height * 1.5 : 0 Layout.fillWidth: true active: true sourceComponent: accountErrorComponent } Label { Layout.fillHeight: true Layout.fillWidth: true text: obj.alias } } KQuickItemViews.DecorationAdapter { pixmap: secIcon anchors.verticalCenter: parent.verticalCenter height: (Kirigami.Units.fontMetrics.height * 2) - 6 width: (Kirigami.Units.fontMetrics.height * 2) - 6 } // Do not cover the handle Item { width: (Kirigami.Units.fontMetrics.height * 2) } } } Loader { id: accountDeleter property string name: "" property var account: "" active: false sourceComponent: Dialog { height: 150 parent: applicationWindow().contentItem x: applicationWindow().contentItem.width / 2 - width/2 y: applicationWindow().contentItem.height / 2 - height/2 standardButtons: Dialog.Ok | Dialog.Cancel closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent modal: true title: i18n("Delete an account") Label { text: i18n("
Are you sure you want to delete the account called ") + name + i18n(".

This cannot be undone and you will lose the account permanently
") } onAccepted: { accountDeleter.active = false AccountModel.remove(account) AccountModel.save() accountDeleter.account = null } onRejected: { accountDeleter.active = false accountDeleter.account = null } } } delegate: Kirigami.SwipeListItem { - property bool hasProblems: object.enabled && registrationState != Account.READY + property bool hasProblems: object.enabled && registrationState != RingQtQuick.Account.READY height: Kirigami.Units.fontMetrics.height * (hasProblems ? 3.5 : 2) width: accountList.width actions: [ Kirigami.Action { iconName: "message-news" text: i18n("Status logs") onTriggered: { - object.performAction(Account.RELOAD) + object.performAction(RingQtQuick.Account.RELOAD) } }, Kirigami.Action { iconName: "document-share" text: i18n("Share") onTriggered: { //TODO } }, Kirigami.Action { iconName: "edit-delete" text: i18n("Delete") onTriggered: { accountDeleter.name = alias accountDeleter.account = object accountDeleter.active = true accountDeleter.item.open() //applicationWindow().globalDrawer.drawerOpen = false //FIXME } }, Kirigami.Action { iconName: "view-refresh" text: i18n("Reload") onTriggered: { - object.performAction(Account.RELOAD) + object.performAction(RingQtQuick.Account.RELOAD) } } ] Loader { anchors.fill: parent property QtObject obj: object property var secIcon: securityLevelIcon sourceComponent: hasProblems ? errorComponent : defaultAccountComponent } } header: Kirigami.Heading { level: 2 text: i18n("Accounts") Component.onCompleted: { headerItem = Math.max(height, implicitHeight) } onHeightChanged: { headerItem = Math.max(height, implicitHeight) } } footer: OutlineButton { id: mainArea height: enableAdd ? fontMetrics.height * 3.5 : 0 expandedHeight: fontMetrics.height * 3.5 sideMargin: 2 width: parent.width label: i18n("Add an account") topPadding: 2 visible: enableAdd onClicked: { applicationWindow().globalDrawer.drawerOpen = false ActionCollection.showWizard.trigger() } Component.onCompleted: { footerItem = Math.max(height, implicitHeight) } onHeightChanged: { footerItem = Math.max(height, implicitHeight) } } } diff --git a/src/accountview/qml/accounts.qml b/src/accountview/qml/accounts.qml index c4b6a06f..98cd6709 100644 --- a/src/accountview/qml/accounts.qml +++ b/src/accountview/qml/accounts.qml @@ -1,178 +1,178 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.8 import org.kde.kirigami 2.5 as Kirigami import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import Ring 1.0 import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews import net.lvindustries.ringqtquick 1.0 as RingQtQuick ListView { id: accountList property QtObject selectedAccount: null spacing : 10 model: ProfileModel delegate: codecDelegate Component { id: codecDelegate Kirigami.Card { id: card x: 5 width: accountList.width - 10 height: content.height + 20 implicitHeight: content.height + 20 property var pModel : ProfileModel.profilesForPerson(model.object) ColumnLayout { id: content height: implicitHeight width: parent.width Kirigami.Heading { text: model.display level:4 } ListView { id: profileList interactive: false model: pModel implicitHeight: contentHeight height: contentHeight width: parent.width delegate: Kirigami.SwipeListItem { id: listItem width: card.width background: Rectangle { id: background property var listItem: parent color: listItem.checked || listItem.highlighted || ( listItem.supportsMouseEvents && listItem.pressed && !listItem.checked && !listItem.sectionDelegate ) ? listItem.activeBackgroundColor : listItem.backgroundColor visible: listItem.ListView.view ? listItem.ListView.view.highlight === null : true Rectangle { id: internal property bool indicateActiveFocus: listItem.pressed || listItem.activeFocus || (listItem.ListView.view ? listItem.ListView.view.activeFocus : false) anchors.fill: parent visible: !listItem.supportsMouseEvents color: listItem.activeBackgroundColor opacity: (listItem.hovered || listItem.highlighted || listItem.activeFocus) && !listItem.pressed ? 0.5 : 0 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration } } } Rectangle { opacity: 0.9 anchors.fill: parent color: object == accountList.selectedAccount ? activePalette.highlight : registrationStateColor } KQuickItemViews.DecorationAdapter { width: check.implicitHeight height: check.implicitHeight anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter pixmap: securityLevelIcon } readonly property bool __separatorVisible: listItem.separatorVisible on__SeparatorVisibleChanged: { if (__separatorVisible) { var newObject = Qt.createQmlObject('import QtQuick 2.0; import org.kde.kirigami 2.4; Separator {anchors {left: parent.left; right: parent.right; bottom: parent.top} visible: listItem.separatorVisible}', background); newObject = Qt.createQmlObject('import QtQuick 2.0; import org.kde.kirigami 2.4; Separator {anchors {left: parent.left; right: parent.right; bottom: parent.bottom} visible: listItem.separatorVisible}', background); } } } RowLayout { width: parent.width height: check.implicitHeight*2 CheckBox { id: check width: height checked: model.enabled } KQuickItemViews.DecorationAdapter { height: check.implicitHeight width: check.implicitHeight pixmap: decoration } Label { text: alias Layout.fillWidth: true } } actions: [ Kirigami.Action { text: i18n("Remove") iconName: "list-remove" onTriggered: {} } ] onPressedChanged: { //TODO add a popup if (accountList.selectedAccount) { accountList.selectedAccount.performAction( - Account.CANCEL + RingQtQuick.Account.CANCEL ) } accountList.selectedAccount = object } } } } } } RingQtQuick.AccountBuilder { id: accountBuilder } footer: OutlineButtons { function callback(index) { selectedAccount = accountBuilder.buildFor(index) } width: accountList.width rows: 2 padding: 5 model: accountBuilder action: callback } Component.onCompleted: { accountList.selectedAccount = AvailableAccountModel.currentDefaultAccount() } } diff --git a/src/callview/qml/actiontoolbar.qml b/src/callview/qml/actiontoolbar.qml index 7732e462..c99b1047 100644 --- a/src/callview/qml/actiontoolbar.qml +++ b/src/callview/qml/actiontoolbar.qml @@ -1,283 +1,286 @@ /*************************************************************************** * Copyright (C) 2015 by Emmanuel Lepage Vallee * * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.0 import Ring 1.0 import QtQuick.Layouts 1.0 +import net.lvindustries.ringqtquick 1.0 as RingQtQuick +import net.lvindustries.ringqtquick.models 1.0 as RingQtModels import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews Rectangle { id: toolbar color: "#55000000" height: actionGrid.contentHeight width:parent.width y:parent.height-toolbar.height -10 z: 100 property var userActionModel: null Timer { id: hideLabel running: false repeat: false interval: 5000 onTriggered: { currentText.visible = false } } // Use a separate label. This allows to use only icons in the buttons, // this reducing the footprint and avoiding a second row. Rectangle { id: currentText clip: true color: "#333333" height: 20 width: 200 radius: 99 // circle visible: false anchors.horizontalCenter: parent.horizontalCenter y: - 30 Text { id: currentTextText anchors.fill: parent color: "white" font.bold : true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter onContentWidthChanged: parent.width = contentWidth + 20 onContentHeightChanged: parent.height = contentHeight + 10 } Behavior on width { NumberAnimation {duration: 50} } } // Show the accept and hangup buttons in green and red function selectColor(action) { - if (action == UserActionModel.HANGUP) + if (action == RingQtModels.UserActionModel.HANGUP) return "#550000"; - else if(action == UserActionModel.ACCEPT) + else if(action == RingQtModels.UserActionModel.ACCEPT) return "#005500" // Default return "#CC222222" } function selectLabelColor(action) { - if (action == UserActionModel.HANGUP || action == UserActionModel.ACCEPT) + if (action == RingQtModels.UserActionModel.HANGUP || + action == RingQtModels.UserActionModel.ACCEPT) return "white" // Default return "white" } Component { id: actionDelegate Item { id: mainArea width: actionGrid.cellWidth height: actionGrid.cellHeight Rectangle { id: background color: mouseArea.containsMouse ? "#CC333333" : selectColor(action) radius: 99 // circle anchors.leftMargin: 5 anchors.rightMargin: 5 anchors.fill: parent border.width: mouseArea.containsMouse ? 3 : 0 border.color: "#dd5555" RowLayout { anchors.margins: 15 anchors.fill: parent KQuickItemViews.DecorationAdapter { anchors.verticalCenter: parent.verticalCenter pixmap: decoration width: 30 height: 30 } Text { id: label text: display visible: false horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: selectLabelColor(action) font.bold: true anchors.leftMargin: 10 Layout.fillHeight: true Layout.fillWidth: true anchors.verticalCenter: parent.verticalCenter } } MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true z: 101 onClicked: { userActionModel.execute(action) } onContainsMouseChanged: { if (containsMouse) { currentText.visible = true currentTextText.text = display } hideLabel.restart() } } Behavior on color { ColorAnimation {duration: 300} } Behavior on border.width { NumberAnimation {duration: 200} } StateGroup { id: stateGroup states: [ State { name: "" when: actionGrid.count > 2 || actionGrid.count == 0 PropertyChanges { target: background radius: 99 anchors.margins: 0 } PropertyChanges { target: mainArea width: 70 } PropertyChanges { target: label visible: false } }, State { name: "single" when: actionGrid.count == 1 PropertyChanges { target: background radius: 5 anchors.margins: 2 } PropertyChanges { target: mainArea width: (toolbar.width/1) } PropertyChanges { target: label visible: true } }, State { name: "two" when: actionGrid.count == 2 PropertyChanges { target: background radius: 5 anchors.margins: 2 } PropertyChanges { target: mainArea width: (toolbar.width/2) } PropertyChanges { target: label visible: true } } ] } } } } GridView { id: actionGrid anchors.fill: parent model: CallModel.userActionModel.activeActionModel delegate: actionDelegate cellWidth: 70; cellHeight: 60 StateGroup { id: stateGroup states: [ State { name: "" when: actionGrid.count > 2 || actionGrid.count == 0 PropertyChanges { target: actionGrid cellWidth: 70 } }, State { name: "single2" when: actionGrid.count == 1 PropertyChanges { target: actionGrid cellWidth: (toolbar.width/1) } }, State { name: "two2" when: actionGrid.count == 2 PropertyChanges { target: actionGrid cellWidth: (toolbar.width/2) } } ] } } // Hide the label when the mouse is out MouseArea { z: -100 anchors.fill: parent hoverEnabled: true onContainsMouseChanged: { if (!containsMouse) currentText.visible = false } } onVisibleChanged: { if (!visible) currentText.visible = false } onUserActionModelChanged: { if (!userActionModel) { userActionModel = CallModel.userActionModel return } actionGrid.model = (userActionModel && userActionModel.activeActionModel) ? userActionModel.activeActionModel : CallModel.userActionModel.activeActionModel } } diff --git a/src/callview/qml/callbackground.qml b/src/callview/qml/callbackground.qml index cb90603a..1ec1d1d6 100644 --- a/src/callview/qml/callbackground.qml +++ b/src/callview/qml/callbackground.qml @@ -1,197 +1,198 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import RingQmlWidgets 1.0 import Ring 1.0 +import net.lvindustries.ringqtquick 1.0 as RingQtQuick Rectangle { property QtObject call: null; property string mode: "PREVIEW" property alias toubleshooting: troubleshootDispatcher property real bottomMargin: 0 id: placeholderMessage color: "black" Text { id: defaultText color: "white" text: i18n("[No video]") anchors.centerIn: parent visible: false } Troubleshoot { id: troubleshootDispatcher call: placeholderMessage.call anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: 5 z: 100000 } NewCall { id: newCall visible: false anchors.centerIn: parent } Ringing { id: ringingIndicator anchors.centerIn: parent running: false visible: false } Searching { id: searchingIndicator anchors.centerIn: parent visible: false running: false } Progress { id: progresIndicator anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom anchors.margins: 5 visible: false anchors.bottomMargin: bottomMargin > 0 ? bottomMargin : undefined transitions: Transition { AnchorAnimation { duration: 300 } } } Rectangle { id: callEnded radius: 5 color: "white" width: 100 height: 30 visible: false anchors.centerIn: parent Text { color: "black" text: i18n("Call Ended") anchors.centerIn: parent } } onCallChanged: { - if (call && (call.state == Call.RINGING || call.state == 1 /*Call.INCOMING*/)) + if (call && (call.state == RingQtQuick.Call.RINGING || call.state == 1 /*Call.INCOMING*/)) callStateGroup.state = "RINGING" - else if (call && (call.state == Call.CONNECTED || call.state == 14 /*Call.INITIALIZATION*/)) + else if (call && (call.state == RingQtQuick.Call.CONNECTED || call.state == 14 /*Call.INITIALIZATION*/)) callStateGroup.state = "CONNECTED" else callStateGroup.state = "DEFAULT" lifecycleStateGroup.state = "INITIALIZATION" progresIndicator.call = call } Timer { id: clearNotifications interval: 3000 running: false repeat: false onTriggered: { - if (call.lifeCycleState == Call.FINISHED) + if (call.lifeCycleState == RingQtQuick.Call.FINISHED) call = null } } StateGroup { id: callStateGroup states: [ State { name: "DEFAULT" when: !call PropertyChanges { target: defaultText visible: mode == "PREVIEW" } PropertyChanges { target: newCall visible: mode != "PREVIEW" && !troubleshootDispatcher.isActive } }, State { name: "RINGING" - when: call && (call.state == Call.RINGING || call.state == 1 /*Call.INCOMING*/) + when: call && (call.state == RingQtQuick.Call.RINGING || call.state == 1 /*Call.INCOMING*/) PropertyChanges { target: ringingIndicator visible: true running: true } }, State { name: "CONNECTED" - when: call && (call.state == Call.CONNECTED || call.state == 14 /*Call.INITIALIZATION*/) + when: call && (call.state == RingQtQuick.Call.CONNECTED || call.state == 14 /*Call.INITIALIZATION*/) PropertyChanges { target: searchingIndicator visible: true running: true } }, State { name: "ENDED" - when: call.lifeCycleState == Call.FINISHED + when: call.lifeCycleState == RingQtQuick.Call.FINISHED PropertyChanges { target: callEnded visible: true } PropertyChanges { target: clearNotifications running: true } } ] } StateGroup { id: lifecycleStateGroup states: [ State { name: "CREATION" - when: call.lifeCycleState == Call.CREATION + when: call.lifeCycleState == RingQtQuick.Call.CREATION PropertyChanges { target: progresIndicator visible: true } }, State { name: "INITIALIZATION" - when: call.lifeCycleState == Call.INITIALIZATION + when: call.lifeCycleState == RingQtQuick.Call.INITIALIZATION PropertyChanges { target: progresIndicator visible: true } }, State { name: "PROGRESS" - when: call.lifeCycleState == Call.PROGRESS + when: call.lifeCycleState == RingQtQuick.Call.PROGRESS }, State { name: "FINISHED" - when: (!call) || call.lifeCycleState == Call.FINISHED + when: (!call) || call.lifeCycleState == RingQtQuick.Call.FINISHED } ] } } diff --git a/src/callview/qml/callview.qml b/src/callview/qml/callview.qml index a784dd21..8355eb6a 100644 --- a/src/callview/qml/callview.qml +++ b/src/callview/qml/callview.qml @@ -1,280 +1,281 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Layouts 1.0 import Ring 1.0 +import net.lvindustries.ringqtquick 1.0 as RingQtQuick Item { id: videoDock signal callWithVideo () signal callWithAudio () signal callWithScreen() height: 480 width: 640 // C++ bindings property alias rendererName : videoWidget.rendererName property bool displayPreview : false property string mode : "PREVIEW" property bool previewRunning : false property alias peerRunning : videoWidget.started property QtObject call : null property QtObject renderer : call ? call.renderer : null property bool previewVisible: mode != "PREVIEW" && call && PreviewManager.previewing Connections { target: renderer onDestroyed: { videoWidget.started = false } } // Let the animations finish before Timer { id: toolbarTimer running: false interval: 150 repeat: false onTriggered: { actionToolbar.visible = false videoSource.visible = false controlToolbar.visible = false } } function showToolbars() { actionToolbar.visible = true videoSource.visible = true // This toolbar is only useful when there is video if (videoWidget.started) controlToolbar.visible = true actionToolbar.opacity = 1 videoSource.opacity = 1 controlToolbar.opacity = 1 videoPreview.opacity = 0.8 actionToolbar.anchors.bottomMargin = 0 videoSource.anchors.rightMargin = 0 controlToolbar.anchors.topMargin = 0 } function hideToolbars() { actionToolbar.opacity = 0 videoSource.opacity = 0 controlToolbar.opacity = 0 videoPreview.opacity = 1 videoSource.anchors.rightMargin = -20 actionToolbar.anchors.bottomMargin = -20 controlToolbar.anchors.topMargin = -20 toolbarTimer.running = true } VideoWidget { id: videoWidget anchors.fill: parent z: -100 started: false visible: started && !hasFailed call: videoDock.call } VideoWidget { id: videoPreview z: -95 started: false visible: previewVisible anchors.right: parent.right anchors.bottom: parent.bottom width: 192 height: 108 } VideoControlToolbar { id: controlToolbar anchors.top: parent.top visible: false Behavior on opacity { NumberAnimation {duration: 100} } Behavior on anchors.topMargin { NumberAnimation {duration: 150} } } ActionToolbar { id: actionToolbar anchors.bottom: parent.bottom visible: false Behavior on opacity { NumberAnimation {duration: 100} } Behavior on anchors.bottomMargin { NumberAnimation {duration: 150} } } RecordingIcon { anchors.right: videoDock.right anchors.top: controlToolbar.bottom } DeviceSetting { id: deviceSettings visible: mode == "PREVIEW" width: parent.width z: 100 Rectangle { anchors.fill: parent color: "black" opacity: 0.5 z: -1 } } VideoSource { id: videoSource z: 101 visible: false anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter Behavior on opacity { NumberAnimation {duration: 100} } Behavior on anchors.rightMargin { NumberAnimation {duration: 150} } } // The background CallBackground { id: placeholderMessage z: -99 anchors.fill: parent bottomMargin: actionToolbar.visible ? actionToolbar.height : 0 } // Hide both toolbars when the mouse isn't moving //TODO keep visible if the mouse if over the toolbars MouseArea { id: mainMouseArea Timer { id: activityTimer interval: 3000 running: true repeat: false onTriggered: { hideToolbars() } } function trackActivity() { if (mode == "PREVIEW") { deviceSettings.visible = true } else if (call) { showToolbars() } activityTimer.restart() } anchors.fill: parent hoverEnabled: true propagateComposedEvents: true onMouseXChanged: trackActivity() onMouseYChanged: trackActivity() } onModeChanged: { if (mode == "PREVIEW") { hideToolbars() videoWidget.rendererName = "preview" } else if (mode == "CONVERSATION") { videoPreview.started = PreviewManager.previewing videoWidget.rendererName = "peer" } placeholderMessage.mode = mode } onCallChanged: { if (call) { actionToolbar.userActionModel = call.userActionModel placeholderMessage.call = call videoSource.call = call controlToolbar.call = call } videoWidget.hasFailed = false mainMouseArea.visible = call != null || mode == "PREVIEW" } Connections { target: PreviewManager onPreviewingChanged: { if (mode == "PREVIEW") videoWidget.started = PreviewManager.previewing videoPreview.started = PreviewManager.previewing } } Connections { target: call } Connections { target: call onVideoStarted: { videoWidget.started = true } onVideoStopped: { videoWidget.started = false } onLiveMediaIssuesChanaged: { // This isn't using properties because the renderer live in their // own thread and QML doesn't support this yet - videoWidget.hasFailed = call.hasIssue(Call.VIDEO_ACQUISITION_FAILED) + videoWidget.hasFailed = call.hasIssue(RingQtQuick.Call.VIDEO_ACQUISITION_FAILED) } } Connections { target: videoWidget onStartedChanged: { placeholderMessage.visible = (!videoWidget.started) || (videoWidget.hasFailed) } onHasFailedChanged: { placeholderMessage.visible = (!videoWidget.started) || (videoWidget.hasFailed) } } Connections { target: call onStateChanged: { - if (call == null || call.lifeCycleState == Call.FINISHED) { + if (call == null || call.lifeCycleState == RingQtQuick.Call.FINISHED) { call = null hideToolbars() } } } } diff --git a/src/callview/qml/recordingicon.qml b/src/callview/qml/recordingicon.qml index ab225d8e..e5e2b4f3 100644 --- a/src/callview/qml/recordingicon.qml +++ b/src/callview/qml/recordingicon.qml @@ -1,64 +1,65 @@ /*************************************************************************** * Copyright (C) 2018 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Layouts 1.0 import org.kde.kirigami 2.2 as Kirigami import Ring 1.0 +import net.lvindustries.ringqtquick 1.0 as RingQtQuick Loader { active: call - && call.lifeCycleState == Call.PROGRESS + && call.lifeCycleState == RingQtQuick.Call.PROGRESS && call.recordingAV sourceComponent: RowLayout { height: 30 Timer { interval: 1000 running: true repeat: true onTriggered: { redCircle.visible = !redCircle.visible } } Item { height: 30 width: 30 Rectangle { id: redCircle radius: 99 height: 30 width: 30 color: Kirigami.Theme.negativeTextColor anchors.verticalCenter: parent.verticalCenter } } Text { text: i18n("Recording") color: "white" font.bold: true font.pointSize: 14 anchors.verticalCenter: parent.verticalCenter } Item { height: 1 width: 6 } } } diff --git a/src/callview/qml/troubleshoot.qml b/src/callview/qml/troubleshoot.qml index dbcd35a5..c3cd6cb9 100644 --- a/src/callview/qml/troubleshoot.qml +++ b/src/callview/qml/troubleshoot.qml @@ -1,145 +1,146 @@ /*************************************************************************** * Copyright (C) 2018 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import Ring 1.0 import QtQuick.Layouts 1.0 import org.kde.kirigami 2.2 as Kirigami import RingQmlWidgets 1.0 import QtQuick.Controls 2.2 +import net.lvindustries.ringqtquick.troubleshoot 1.0 as RingQtTroubleshoot /** * This is a frontend for the troubleshooting subsystem. * * It displays many useful errors when the call fail or the media are not * available. * * It also gives options to fix the problem. */ Rectangle { property QtObject call: null property bool isActive: troubleshootDispatcher.isActive && call property alias currentIssue: troubleshootDispatcher.currentIssue radius: 5 color: troubleshootDispatcher.severity == 2 ? Kirigami.Theme.neutralTextColor : Kirigami.Theme.negativeTextColor height: content.implicitHeight + 26 width: Math.min(parent.width, 400) opacity: 0.8 visible: troubleshootDispatcher.isActive || isActive - Dispatcher { + RingQtTroubleshoot.Dispatcher { id: troubleshootDispatcher call: placeholderMessage.call } ColumnLayout { id: content y: 10 x: 10 width: parent.width - 20 Image { height: 32 Layout.fillWidth: true fillMode: Image.PreserveAspectFit width: parent.width sourceSize.width: 32 sourceSize.height: 32 horizontalAlignment: Image.AlignHCenter source: "image://SymbolicColorizer/?color=#eeeeee;:/sharedassets/outline/warning.svg" } Text { Layout.fillWidth: true text: troubleshootDispatcher.headerText color: "white" wrapMode: Text.WordWrap width: parent.width horizontalAlignment: Text.AlignHCenter } Component { id: actionDelegate Rectangle { color: "transparent" border.width: 1 border.color: "white" height: buttonText.implicitHeight + 15 width: content.width radius: 5 Layout.fillWidth: true anchors.margins: 10 Text { id: buttonText anchors.centerIn: parent color: "white" text: display } MouseArea { anchors.fill: parent onClicked: { troubleshootDispatcher.setSelection(index) } } } } ListView { model: troubleshootDispatcher interactive: false height: contentHeight implicitHeight: contentHeight width: parent.width x: 10 spacing: 3 delegate: actionDelegate } Rectangle { color: "transparent" border.width: 1 border.color: "white" height: buttonText.implicitHeight + 15 width: content.width radius: 5 anchors.topMargin: 3 Layout.fillWidth: true anchors.margins: 10 Text { id: buttonText anchors.centerIn: parent color: "white" text: i18n("Dismiss") } MouseArea { anchors.fill: parent onClicked: { troubleshootDispatcher.dismiss() } } } } } diff --git a/src/callview/qml/videosource.qml b/src/callview/qml/videosource.qml index d34684d4..637aa869 100644 --- a/src/callview/qml/videosource.qml +++ b/src/callview/qml/videosource.qml @@ -1,223 +1,224 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.0 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import Ring 1.0 import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews +import net.lvindustries.ringqtquick.video.models 1.0 as RingQtVideoModel Item { property QtObject call: null property int current: -1 id: videoSource width: 50 height: elements.implicitHeight // Camera popup CanvasPopup { id: sourcePopup parent: videoSource.parent width: 400 height: 400 x: videoSource.parent.width - width - 50 y: 50 title: "Camera settings" contentItem: Component { ColumnLayout { anchors.fill: parent DeviceSetting { id: deviceSettings Layout.fillHeight: true Layout.fillWidth: true } Item { Layout.fillWidth: true height: applyButton.height Button { id: applyButton text: i18n("Apply") anchors.right: parent.right onClicked: { if (!videoSource.call) return videoSource.call.sourceModel.switchTo( videoSource.current ) } } } } } } // Screen sharing popup CanvasPopup { id: screenPopup parent: videoSource.parent width: 400 height: 400 x: videoSource.parent.width - width - 50 y: 50 title: "Screen sharing" contentItem: Component { ScreenSharing { id: deviceSettings call: videoSource.call anchors.fill: parent } } } // Streaming popup CanvasPopup { id: filePopup parent: videoSource.parent width: 400 height: 400 x: videoSource.parent.width - width - 50 y: 50 title: "Camera settings" contentItem: Component { Streaming { id: deviceSettings call: videoSource.call anchors.fill: parent } } } // Use a separate label. This allows to use only icons in the buttons, // this reducing the footprint and avoiding a second row. Rectangle { id: currentText clip: true color: "#333333" height: 20 width: 200 radius: 99 // circle visible: false anchors.verticalCenter: parent.verticalCenter anchors.right: parent.left anchors.margins: 5 Text { id: currentTextText anchors.fill: parent color: "white" font.bold : true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter onContentWidthChanged: parent.width = contentWidth + 20 onContentHeightChanged: parent.height = contentHeight + 10 } Behavior on width { NumberAnimation {duration: 50} } } onCallChanged: { devices.model = call ? call.sourceModel : null } Connections { target: call onMediaAdded: { devices.model = call.sourceModel } } MouseArea { anchors.fill: parent hoverEnabled: true ColumnLayout { id: elements anchors.fill: parent Component { id: deviceDelegate Rectangle { id: backgroundRect width: 50 height: 50 radius: 99 color: "#CC222222" border.width: mouseArea.containsMouse ? 3 : 0 border.color: "#dd5555" KQuickItemViews.DecorationAdapter { anchors.fill: parent anchors.margins: 10 pixmap: decoration } MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true onContainsMouseChanged: { if (containsMouse) { currentTextText.text = display } backgroundRect.color = containsMouse ? "#CC333333" : "#CC222222" } onClicked: { videoSource.current = index switch(index) { - case SourceModel.NONE: + case RingQtVideoModel.SourceModel.NONE: videoSource.call.sourceModel.switchTo(0) return - case SourceModel.SCREEN: + case RingQtVideoModel.SourceModel.SCREEN: screenPopup.show() return - case SourceModel.FILE: + case RingQtVideoModel.SourceModel.FILE: filePopup.show() return } sourcePopup.show() } } Behavior on color { ColorAnimation {duration: 300} } Behavior on border.width { NumberAnimation {duration: 200} } } } Repeater { id: devices delegate: deviceDelegate model: videoSource.call ? videoSource.call.sourceModel : null } } onContainsMouseChanged: { currentText.visible = containsMouse } } } diff --git a/src/callview/qml/videowidget.qml b/src/callview/qml/videowidget.qml index aa25f911..7832e03e 100644 --- a/src/callview/qml/videowidget.qml +++ b/src/callview/qml/videowidget.qml @@ -1,68 +1,69 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.0 import Ring 1.0 +import net.lvindustries.ringqtquick 1.0 as RingQtQuick Rectangle { property bool stretch: false property string rendererName: "preview" property alias started: frameTimer.running property bool hasFailed: false property QtObject call: null property int _delay: 0 color: "black" Image { id: videoBackground fillMode: Image.PreserveAspectFit anchors.fill: parent cache: false } // HACK This is a workaround until the OpenGL underlay based framebuffer // starts working. It Eats CPU and is otherwise ugly, but it works. property var counter: 1 Timer { id: frameTimer interval: 33 running: false repeat: true onTriggered: { videoBackground.source = "image://VideoFrame/"+rendererName+"/"+counter+".png" counter = counter + 1 // There is many race conditions with the different types of renderers. This // code helps cleanup the messes in case a new source of issues is introduced. // It was the case enough time I don't think ever removing this code is a good // idea. - if (rendererName == "peer" && ((!call) || (!call.lifeCycleState == Call.Finished))) + if (rendererName == "peer" && ((!call) || (!call.lifeCycleState == RingQtQuick.Call.Finished))) _delay = _delay + 1 if (_delay >= 10) { running = false _delay = 0 } } } onStretchChanged: { videoBackground.fillMode = stretch ? Image.Stretch : Image.PreserveAspectFit } } diff --git a/src/canvasindicators/qml/progress.qml b/src/canvasindicators/qml/progress.qml index b35b8ddb..5f24bf79 100644 --- a/src/canvasindicators/qml/progress.qml +++ b/src/canvasindicators/qml/progress.qml @@ -1,218 +1,219 @@ /*************************************************************************** * Copyright (C) 2017-2018 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Layouts 1.0 import Ring 1.0 import org.kde.kirigami 2.2 as Kirigami +import net.lvindustries.ringqtquick 1.0 as RingQtQuick Item { property QtObject call: null property bool displayLabels: true property color outlineColor: "#dddddd" property color backgroundColor: "black" width: 200 height: displayLabels ? 50 : 20 Component { id: circle Rectangle { border.width: 1 border.color: outlineColor color: backgroundColor radius: 99 height: 20 width: 20 Rectangle { color: circleColor radius: 99 height: 10 width: 10 Behavior on color { ColorAnimation {duration: 300} } anchors.centerIn: parent } Loader { active: displayLabels sourceComponent: Text { color: "white" text: label font.pointSize: fontSize transformOrigin: Item.Left y : -Math.sin(Math.PI/4)*implicitWidth - parent.height x : -(Math.cos(Math.PI/4)*implicitWidth) / 2 - parent.height/2 Behavior on font.pointSize { NumberAnimation {duration: 150} } transform: Rotation { origin.x: 0 origin.y: height/2 angle: 45 } } } } } Rectangle { id: backgroundBar anchors.verticalCenter: parent.verticalCenter width: parent.width height: 2 radius: 99 color: outlineColor } RowLayout { anchors.verticalCenter: parent.verticalCenter width: parent.width Item { Layout.fillWidth: true } Loader { id: initCircle property string label: i18n("Dialing") property string circleColor: outlineColor property real fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 sourceComponent: circle Layout.maximumWidth: 20 Layout.maximumHeight: 20 } Item { Layout.fillWidth: true } Loader { id: searchCircle property string label: i18n("Searching") property string circleColor: outlineColor property real fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 sourceComponent: circle Layout.maximumWidth: 20 Layout.maximumHeight: 20 } Item { Layout.fillWidth: true } Loader { id: ringCircle property string label: i18n("Ringing") property string circleColor: outlineColor property real fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 sourceComponent: circle Layout.maximumWidth: 20 Layout.maximumHeight: 20 } Item { Layout.fillWidth: true } Loader { property string label: i18n("Starting") property string circleColor: outlineColor property real fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 sourceComponent: circle Layout.maximumWidth: 20 Layout.maximumHeight: 20 } Item { Layout.fillWidth: true } } property var counter: 0 onCallChanged: { - if (call && (call.state == Call.RINGING || call.state == 1 /*Call.INCOMING*/)) + if (call && (call.state == RingQtQuick.Call.RINGING || call.state == 1 /*Call.INCOMING*/)) callStateGroup.state = "RINGING" - else if (call && call.state == Call.CONNECTED) + else if (call && call.state == RingQtQuick.Call.CONNECTED) callStateGroup.state = "CONNECTED" else callStateGroup.state = "INITIALIZATION" } StateGroup { id: callStateGroup states: [ State { name: "" PropertyChanges { target: initCircle fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 } PropertyChanges { target: searchCircle fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 } PropertyChanges { target: ringCircle fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 } }, State { name: "INITIALIZATION" when: call == null || call.state == 14 PropertyChanges { target: initCircle circleColor: "#298223" fontSize: Kirigami.Theme.defaultFont.pointSize*1.6 } }, State { name: "CONNECTED" - when: call && call.state == Call.CONNECTED + when: call && call.state == RingQtQuick.Call.CONNECTED extend: "INITIALIZATION" PropertyChanges { target: searchCircle circleColor: "#298223" fontSize: Kirigami.Theme.defaultFont.pointSize*1.6 } PropertyChanges { target: initCircle fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 } }, State { name: "RINGING" extend: "CONNECTED" - when: call && (call.state == Call.RINGING || call.state == 1 /*Call.INCOMING*/) + when: call && (call.state == RingQtQuick.Call.RINGING || call.state == 1 /*Call.INCOMING*/) PropertyChanges { target: ringCircle circleColor: "#298223" fontSize: Kirigami.Theme.defaultFont.pointSize*1.6 } PropertyChanges { target: initCircle fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 } PropertyChanges { target: searchCircle fontSize: Kirigami.Theme.defaultFont.pointSize*1.2 } } ] } } diff --git a/src/contactview/qml/mediaavailability.qml b/src/contactview/qml/mediaavailability.qml index c6c7846e..fff1b990 100644 --- a/src/contactview/qml/mediaavailability.qml +++ b/src/contactview/qml/mediaavailability.qml @@ -1,130 +1,131 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Layouts 1.0 import QtQuick.Controls 2.0 import QtQml.Models 2.2 import RingQmlWidgets 1.0 import Ring 1.0 import ContactView 1.0 +import net.lvindustries.ringqtquick.media 1.0 as RingQtMedia Rectangle { id: mediaAvailability property QtObject currentIndividual: null property real defaultSize: 48 property bool accountState: true - AvailabilityTracker { + RingQtMedia.AvailabilityTracker { id: availabilityTracker individual: currentIndividual } border.width: 1 border.color: activePalette.text color: "transparent" radius: 99 width: defaultSize height: defaultSize visible: availabilityTracker.hasWarning opacity: 0.5 SystemPalette { id: activePalette colorGroup: SystemPalette.Active } Image { height: defaultSize width: defaultSize sourceSize.width: defaultSize sourceSize.height: defaultSize anchors.verticalCenter: parent.verticalCenter source: "image://SymbolicColorizer/:/sharedassets/outline/warning.svg" } Label { id: errorMessage width: parent.width - 52 height: parent.height anchors.right: parent.right visible: false color: activePalette.text wrapMode: Text.WordWrap } MouseArea { id: mouseArea hoverEnabled: true anchors.fill: parent } Behavior on width { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } Behavior on height { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } Behavior on radius { NumberAnimation {duration: 100; easing.type: Easing.OutQuad } } Behavior on opacity { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } StateGroup { id: stateGroup states: [ State { name: "hover" when: mouseArea.containsMouse extend: "active" PropertyChanges { target: mediaAvailability opacity: 0.8 radius: 5 height: mediaAvailability.parent.height width: mediaAvailability.parent.width } PropertyChanges { target: errorMessage visible: true text: availabilityTracker.warningMessage } }, State { name: "active" when: availabilityTracker.hasWarning PropertyChanges { target: errorMessage visible: false } PropertyChanges { target: mediaAvailability visible: true opacity: 0.5 radius: 99 width: defaultSize } } ] } } diff --git a/src/contactview/qml/vcardform.qml b/src/contactview/qml/vcardform.qml index d4047da8..b1f0427d 100644 --- a/src/contactview/qml/vcardform.qml +++ b/src/contactview/qml/vcardform.qml @@ -1,163 +1,164 @@ /*************************************************************************** * Copyright (C) 2017-2018 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import RingQmlWidgets 1.0 +import net.lvindustries.ringqtquick 1.0 as RingQtQuick GridLayout { id: mainInfo property var currentContactMethod: null property var currentPerson: null property bool editing: true property real preferredHeight: implicitHeight property var individual: null property bool hasTarget: individual || currentContactMethod || currentPerson property alias name: formattedName.text signal changed() columns: 2 rowSpacing: 10 columnSpacing: 10 function syncDetails(person) { if ((!currentContactMethod) && (!currentPerson)) return // Changing the CM will flush the content, preserve it var old_formattedName = formattedName.text var old_firstName = firstName.text var old_secondName = lastName.text var old_preferredEmail = email.text // var old_organization = organization.text // Create a real contact method in case this is a temporary one - if (currentContactMethod && currentContactMethod.type == ContactMethod.TEMPORARY) + if (currentContactMethod && currentContactMethod.type == RingQtQuick.ContactMethod.TEMPORARY) currentContactMethod = PhoneDirectoryModel.getNumber( currentContactMethod.uri, null, currentContactMethod.account ) person.formattedName = old_formattedName person.firstName = old_firstName person.secondName = old_secondName person.preferredEmail = old_preferredEmail // person.organization = old_organization currentPerson = person } onCurrentContactMethodChanged: { if (!currentContactMethod) return currentPerson = currentContactMethod.person } onCurrentPersonChanged: { formattedName.text = currentPerson ? currentPerson.formattedName : "" firstName.text = currentPerson ? currentPerson.firstName : "" lastName.text = currentPerson ? currentPerson.secondName : "" email.text = currentPerson ? currentPerson.preferredEmail : "" // organization.text = currentPerson ? // currentPerson.organization : "" } onIndividualChanged: { if (formattedName.text == "" && individual) formattedName.text = individual.bestName } Component.onCompleted: { if (formattedName.text == "" && individual) formattedName.text = individual.bestName } Label { id: label text: i18n("Formatted name:") color: labelColor ? labelColor : activePalette.text } TextField { id: formattedName readOnly: hasTarget && !mainInfo.editing onTextChanged: { mainInfo.changed() } } Label { text: i18n("Primary name:") color: labelColor ? labelColor : activePalette.text } TextField { id: firstName readOnly: hasTarget && !mainInfo.editing onTextChanged: { mainInfo.changed() } } Label { text: i18n("Last name:") color: labelColor ? labelColor : activePalette.text } TextField { id: lastName readOnly: hasTarget && !mainInfo.editing onTextChanged: { mainInfo.changed() } } Label { text: i18n("Email:") color: labelColor ? labelColor : activePalette.text } TextField { id: email readOnly: hasTarget && !mainInfo.editing onTextChanged: { mainInfo.changed() } } // OutlineButton { // id: addButton // height: 54 // sideMargin: 2 // Layout.columnSpan: 2 // width: formattedName.width + label.width + 30 // label: i18n("Add a field") // topPadding: 2 // visible: mainInfo.editing // } } diff --git a/src/dialview/qml/calldelegateitem.qml b/src/dialview/qml/calldelegateitem.qml index 40f05b2d..3a5a45ab 100644 --- a/src/dialview/qml/calldelegateitem.qml +++ b/src/dialview/qml/calldelegateitem.qml @@ -1,451 +1,452 @@ /****************************************************************************** * Copyright (C) 2012 by Savoir-Faire Linux * * Author : Emmanuel Lepage Vallee * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the Lesser GNU General Public License * * along with this program. If not, see . * *****************************************************************************/ import QtQuick 2.0 import QtQuick.Layouts 1.0 import Ring 1.0 import RingQmlWidgets 1.0 import org.kde.kirigami 2.2 as Kirigami +import net.lvindustries.ringqtquick 1.0 as RingQtQuick import ContactView 1.0 Rectangle { id: callDelegateItem anchors.margins: 2 radius: 5 border.width: 0 color: selected ? activePalette.highlight: "transparent" height: content.implicitHeight + 20 + errorMessage.height property bool selected: object == CallModel.selectedCall property bool skipSelect: errorMessage.active || missedMessage.active property var labelColor: callDelegateItem.selected && !skipSelect ? activePalette.highlightedText : activePalette.text Drag.active: mouseArea.drag.active Drag.dragType: Drag.Automatic Drag.onDragStarted: { var ret = treeHelper.mimeData(model.rootIndex, index) Drag.mimeData = ret } Behavior on height { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } TreeHelper { id: treeHelper model: CallModel } Drag.onDragFinished: { if (dropAction == Qt.MoveAction) { item.display = "hello" } } OutlineButton { id: closeButton label: " "+i18n("Close") anchors.right: parent.right anchors.top: parent.top anchors.margins: 3 height: 24 visible: false z: 100 alignment: Qt.AlignRight property string colString: selected && !skipSelect ? activePalette.highlightedText.toString(16) : activePalette.text.toString(16) color: colString icon: "image://SymbolicColorizer/?color="+colString+";:/sharedassets/outline/close.svg" onClicked: { - object.performAction(Call.REFUSE) + object.performAction(RingQtQuick.Call.REFUSE) } } RowLayout { id: content spacing: 10 width: parent.width - 4 ContactPhoto { contactMethod: object.peerContactMethod height:40 width:40 drawEmptyOutline: false defaultColor: labelColor anchors.verticalCenter: parent.verticalCenter } Column { Layout.fillWidth: true Text { text: display width: parent.width wrapMode: Text.WrapAnywhere color: labelColor font.bold: true } Text { text: model.number width: parent.width wrapMode: Text.WrapAnywhere color: labelColor } } } DropArea { anchors.fill: parent keys: ["text/ring.call.id", "text/plain"] onEntered: { callDelegateItem.color = "red" } onExited: { callDelegateItem.color = "blue" } onDropped: { var formats = drop.formats var ret = {} ret["x-ring/dropaction"] = "join" // stupid lack of official APIs... for(var i=0; i< formats.length; i++) { ret[formats[i]] = drop.getDataAsArrayBuffer(formats[i]) } treeHelper.dropMimeData2(ret, model.rootIndex, index) } } MouseArea { id: mouseArea anchors.fill: parent propagateComposedEvents: true onClicked: { mouse.accepted = true CallModel.selectedCall = object dialView.selectCall(object) } drag.target: callDelegateItem } Loader { id: completionLoader active: false opacity: 0 anchors.bottom: parent.bottom anchors.bottomMargin: 10 width: callDelegateItem.width height: 0 Behavior on height { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } Behavior on opacity { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } sourceComponent: Component { ListView { clip: true anchors.fill: parent anchors.margins: 10 spacing: 10 model: CompletionModel currentIndex: completionSelection.currentIndex delegate: Rectangle { property bool selected: ListView.isCurrentItem height: searchDelegate.height width: callDelegateItem.width - 20 color: selected ? activePalette.highlightedText : "transparent" border.width: 1 border.color: activePalette.highlightedText radius: 5 clip: true CompletionDelegate { id: searchDelegate showPhoto: false showControls: false showSeparator: false labelHeight: fontMetrics.height } } onCountChanged: { completionLoader.height = Math.min(4, count)*(3*fontMetrics.height+12) callDelegateItem.height = content.implicitHeight + Math.min(4, count)*(3*fontMetrics.height+10) + 10 } } } } Loader { id: errorMessage anchors.top: content.bottom active: false width: parent.width height: active ? item.implicitHeight : 0 sourceComponent: Component { CallError { call: object width: errorMessage.width } } } Loader { id: outgoingMessage anchors.top: content.bottom active: false width: parent.width height: active ? item.implicitHeight : 0 sourceComponent: Component { OutgoingCall { call: object width: outgoingMessage.width } } } Loader { id: finishedMessage anchors.top: content.bottom active: false width: parent.width height: active ? item.implicitHeight : 0 sourceComponent: Component { FinishedCall { call: object width: finishedMessage.width } } } Loader { id: currentMessage anchors.top: content.bottom active: false width: parent.width height: active ? item.implicitHeight : 0 sourceComponent: Component { CurrentCall { call: object width: currentMessage.width } } } Loader { id: missedMessage active: false width: parent.width height: active ? item.implicitHeight : 0 sourceComponent: Component { MissedCall { call: object width: missedMessage.width } } } Loader { id: rigningAnimation active: false width: parent.width height: active ? 32 : 0 anchors.top: content.bottom anchors.horizontalCenter: parent.horizontalCenter sourceComponent: Component { IncomingCall { //call: object width: rigningAnimation.width } } } StateGroup { id: stateGroup states: [ State { name: "" PropertyChanges { target: callDelegateItem border.width: 0 } }, State { name: "dialing" - when: selected && object.state == Call.DIALING + when: selected && object.state == RingQtQuick.Call.DIALING PropertyChanges { target: callDelegateItem border.width: 0 height: content.implicitHeight + Math.min(4, count)*(3*fontMetrics.height+10) + 10 } PropertyChanges { target: completionLoader active: true opacity: 1 height: Math.min(4, count)*(3*fontMetrics.height+10) + 10 } PropertyChanges { target: closeButton visible: false } }, State { name: "error" - when: lifeCycleState == Call.FINISHED && object.state != Call.OVER - && object.state != Call.ABORTED + when: lifeCycleState == RingQtQuick.Call.FINISHED && object.state != RingQtQuick.Call.OVER + && object.state != RingQtQuick.Call.ABORTED PropertyChanges { target: errorMessage active: true } PropertyChanges { target: callDelegateItem color: "#33ff0000" border.width: 1 border.color: "#55ff0000" } PropertyChanges { target: closeButton visible: true } }, State { name: "missed" - when: object.state == Call.OVER && object.missed + when: object.state == RingQtQuick.Call.OVER && object.missed PropertyChanges { target: missedMessage active: true } PropertyChanges { target: content visible: false } PropertyChanges { target: callDelegateItem height: missedMessage.height color: "#33ff0000" border.width: 1 border.color: "#55ff0000" } PropertyChanges { target: closeButton visible: true } }, State { name: "incoming" when: object.state == 1/*iNCOMING*/ PropertyChanges { target: callDelegateItem border.width: 0 height: rigningAnimation.height + content.implicitHeight + 3 } PropertyChanges { target: rigningAnimation active: true } PropertyChanges { target: closeButton visible: false } }, State { name: "outgoing" - when: object.lifeCycleState == Call.INITIALIZATION && object.direction == 1/*OUTGOING*/ + when: object.lifeCycleState == RingQtQuick.Call.INITIALIZATION && object.direction == 1/*OUTGOING*/ PropertyChanges { target: callDelegateItem border.width: 0 height: outgoingMessage.height + content.implicitHeight } PropertyChanges { target: outgoingMessage active: true } PropertyChanges { target: closeButton visible: false } }, State { name: "finished" - when: object.state == Call.OVER + when: object.state == RingQtQuick.Call.OVER PropertyChanges { target: callDelegateItem border.width: 0 height: finishedMessage.height + content.implicitHeight } PropertyChanges { target: finishedMessage active: true } PropertyChanges { target: closeButton visible: true } }, State { name: "current" - when: object.lifeCycleState == Call.PROGRESS + when: object.lifeCycleState == RingQtQuick.Call.PROGRESS PropertyChanges { target: callDelegateItem border.width: 0 height: currentMessage.height + content.implicitHeight } PropertyChanges { target: currentMessage active: true } PropertyChanges { target: closeButton visible: false } } ] } } //Call delegate diff --git a/src/dialview/qml/dialview.qml b/src/dialview/qml/dialview.qml index b712e691..39811671 100644 --- a/src/dialview/qml/dialview.qml +++ b/src/dialview/qml/dialview.qml @@ -1,195 +1,196 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * 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 . * **************************************************************************/ import QtQuick 2.7 import Ring 1.0 import QtQuick.Layouts 1.0 import org.kde.kirigami 2.2 as Kirigami import RingQmlWidgets 1.0 +import net.lvindustries.ringqtquick 1.0 as RingQtQuick FocusScope { id: dialView focus: true anchors.fill: parent - signal selectCall(Call call) + signal selectCall(RingQtQuick.Call call) SystemPalette { id: inactivePalette colorGroup: SystemPalette.Disabled } SystemPalette { id: activePalette colorGroup: SystemPalette.Active } FontMetrics { id: fontMetrics } TreeHelper { id: completionSelection selectionModel: CompletionModel.selectionModel } CallList { anchors.fill: parent } DialPad { width: parent.width visible: CallModel.supportsDTMF height: 200 anchors.horizontalCenter: dialView.horizontalCenter anchors.bottom: actionToolbar.top anchors.bottomMargin: 50 } ActionToolbar { id: actionToolbar width: parent.width anchors.bottom: parent.bottom } function selectPrevious(call) { - if (call.state == Call.DIALING && completionSelection.selectPrevious()) + if (call.state == RingQtQuick.Call.DIALING && completionSelection.selectPrevious()) return completionSelection.clearSelection() var idx = CallModel.getIndex(call) if (!idx.valid) return var directPrev = CallModel.index(idx.row-1, 0, idx.parent) var nextCall = CallModel.getCall(directPrev) if (!nextCall) return CallModel.selectedCall = nextCall dialView.selectCall(nextCall) } function selectNext(call) { - if (call.state == Call.DIALING && completionSelection.selectNext()) + if (call.state == RingQtQuick.Call.DIALING && completionSelection.selectNext()) return completionSelection.clearSelection() var idx = CallModel.getIndex(call) if (!idx.valid) return var directPrev = CallModel.index(idx.row+1, 0, idx.parent) var nextCall = CallModel.getCall(directPrev) if (!nextCall) return CallModel.selectedCall = nextCall dialView.selectCall(nextCall) } function performCall() { var call = CallModel.selectedCall if (!call) { call = CallModel.dialingCall() CallModel.selectedCall = call } // Apply the auto completion - if (call.state == Call.DIALING && CompletionModel.selectedContactMethod) + if (call.state == RingQtQuick.Call.DIALING && CompletionModel.selectedContactMethod) call.peerContactMethod = CompletionModel.selectedContactMethod - call.performAction(Call.ACCEPT) + call.performAction(RingQtQuick.Call.ACCEPT) } function getCall() { var call = CallModel.selectedCall if (!call) { call = CallModel.dialingCall() CallModel.selectedCall = call } return call } Keys.onPressed: { switch (event.key) { case Qt.Key_Up: selectPrevious(getCall()) break case Qt.Key_Down: selectNext(getCall()) break case Qt.Key_Escape: - getCall().performAction(Call.REFUSE) + getCall().performAction(RingQtQuick.Call.REFUSE) break case Qt.Key_Backspace: getCall().backspaceItemText() break; case Qt.Key_Return: case Qt.Key_Enter: performCall() break default: // Prevent "control" from creating a dialing call if (event.text == "") return var call = getCall() call.appendText(event.text) call.playDTMF(event.text) } } Connections { target: CallModel onCallAttentionRequest: { CallModel.selectedCall = call } } Component.onCompleted: { dialView.forceActiveFocus() } MouseArea { z: 9999 anchors.fill: parent propagateComposedEvents: true onClicked: { mouse.accepted = false mouse.refused = true dialView.focus = true dialView.forceActiveFocus() } } } diff --git a/src/ringapplication.cpp b/src/ringapplication.cpp index 6a7625d4..02378b09 100644 --- a/src/ringapplication.cpp +++ b/src/ringapplication.cpp @@ -1,658 +1,630 @@ /*************************************************************************** * Copyright (C) 2009-2015 by Savoir-Faire Linux * * Author : Emmanuel Lepage Valle * * * * 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 . * **************************************************************************/ //Parent #include "ringapplication.h" //Qt #include #include #include #include #include #include #include #include #include #include #include #include //KDE #include #include #include #include //LRC #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include