diff --git a/Linphone/core/friend/FriendCore.cpp b/Linphone/core/friend/FriendCore.cpp index 92a0f5218..ed27e862e 100644 --- a/Linphone/core/friend/FriendCore.cpp +++ b/Linphone/core/friend/FriendCore.cpp @@ -37,6 +37,14 @@ QVariant createFriendAddressVariant(const QString &label, const QString &address return map; } +QVariant createFriendDevice(const QString &name, const QString &address, LinphoneEnums::SecurityLevel level) { + QVariantMap map; + map.insert("name", name); + map.insert("address", address); + map.insert("securityLevel", QVariant::fromValue(level)); + return map; +} + QSharedPointer FriendCore::create(const std::shared_ptr &contact) { auto sharedPointer = QSharedPointer(new FriendCore(contact), &QObject::deleteLater); sharedPointer->setSelf(sharedPointer); @@ -75,6 +83,15 @@ FriendCore::FriendCore(const std::shared_ptr &contact) : QObje Utils::coreStringToAppString(phoneNumber->getPhoneNumber()))); } + auto devices = contact->getDevices(); + for (auto &device : devices) { + mDeviceList.append(createFriendDevice(Utils::coreStringToAppString(device->getDisplayName()), + // do not use uri only as we want the unique device + Utils::coreStringToAppString(device->getAddress()->asString()), + LinphoneEnums::fromLinphone(device->getSecurityLevel()))); + } + updateVerifiedDevicesCount(); + mStarred = contact->getStarred(); mIsSaved = true; } else { @@ -110,16 +127,28 @@ void FriendCore::setSelf(SafeSharedPointer me) { void FriendCore::setSelf(QSharedPointer me) { if (me) { if (mFriendModel) { - mCoreModelConnection = nullptr; // No more needed mFriendModelConnection = QSharedPointer>( new SafeConnection(me, mFriendModel), &QObject::deleteLater); mFriendModelConnection->makeConnectToModel( &FriendModel::presenceReceived, [this](LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp) { - mFriendModelConnection->invokeToCore([this, consolidatedPresence, presenceTimestamp]() { - setConsolidatedPresence(consolidatedPresence); - setPresenceTimestamp(presenceTimestamp); - }); + auto devices = mFriendModel->getDevices(); + QVariantList devicesList; + for (auto &device : devices) { + devicesList.append( + createFriendDevice(Utils::coreStringToAppString(device->getDisplayName()), + // do not use uri only as we want the unique device + Utils::coreStringToAppString(device->getAddress()->asString()), + LinphoneEnums::fromLinphone(device->getSecurityLevel()))); + } + mFriendModelConnection->invokeToCore( + [this, consolidatedPresence, presenceTimestamp, devicesList]() { + setConsolidatedPresence(consolidatedPresence); + setPresenceTimestamp(presenceTimestamp); + + setDevices(devicesList); + updateVerifiedDevicesCount(); + }); }); mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](const QString &uri) { mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); }); @@ -165,6 +194,29 @@ void FriendCore::setSelf(QSharedPointer me) { mFriendModelConnection->makeConnectToCore(&FriendCore::lSetStarred, [this](bool starred) { mFriendModelConnection->invokeToModel([this, starred]() { mFriendModel->setStarred(starred); }); }); + if (!mCoreModelConnection) { + mCoreModelConnection = QSharedPointer>( + new SafeConnection(me, CoreModel::getInstance()), &QObject::deleteLater); + } + mCoreModelConnection->makeConnectToModel( + &CoreModel::callStateChanged, + [this](const std::shared_ptr &core, const std::shared_ptr &call, + linphone::Call::State state, const std::string &message) { + if (state != linphone::Call::State::End && state != linphone::Call::State::Released) return; + auto devices = mFriendModel->getDevices(); + QVariantList devicesList; + for (auto &device : devices) { + devicesList.append( + createFriendDevice(Utils::coreStringToAppString(device->getDisplayName()), + // do not use uri only as we want the unique device + Utils::coreStringToAppString(device->getAddress()->asString()), + LinphoneEnums::fromLinphone(device->getSecurityLevel()))); + } + mCoreModelConnection->invokeToCore([this, devicesList]() { + setDevices(devicesList); + updateVerifiedDevicesCount(); + }); + }); } else { // Create mCoreModelConnection = QSharedPointer>( @@ -332,6 +384,27 @@ QList FriendCore::getAllAddresses() const { return mAddressList + mPhoneNumberList; } +QList FriendCore::getDevices() const { + return mDeviceList; +} + +void FriendCore::updateVerifiedDevicesCount() { + mVerifiedDeviceCount = 0; + for (auto &device : mDeviceList) { + auto map = device.toMap(); + if (map["securityLevel"].value() == + LinphoneEnums::SecurityLevel::EndToEndEncryptedAndVerified) + ++mVerifiedDeviceCount; + } + emit verifiedDevicesChanged(); +} + +void FriendCore::setDevices(QVariantList devices) { + mDeviceList.clear(); + mDeviceList.append(devices); + emit devicesChanged(); +} + QString FriendCore::getDefaultAddress() const { return mDefaultAddress; } diff --git a/Linphone/core/friend/FriendCore.hpp b/Linphone/core/friend/FriendCore.hpp index 730501b78..6b5ed8aa9 100644 --- a/Linphone/core/friend/FriendCore.hpp +++ b/Linphone/core/friend/FriendCore.hpp @@ -41,12 +41,20 @@ class CoreModel; class FriendCore; +struct FriendDevice { + QString name; + QString address; + LinphoneEnums::SecurityLevel securityLevel; +}; + class FriendCore : public QObject, public AbstractObject { Q_OBJECT Q_PROPERTY(QList allAddresses READ getAllAddresses NOTIFY allAddressesChanged) Q_PROPERTY(QList phoneNumbers READ getPhoneNumbers NOTIFY phoneNumberChanged) Q_PROPERTY(QList addresses READ getAddresses NOTIFY addressChanged) + Q_PROPERTY(QList devices READ getDevices NOTIFY devicesChanged) + Q_PROPERTY(int verifiedDeviceCount MEMBER mVerifiedDeviceCount NOTIFY verifiedDevicesChanged) Q_PROPERTY(QString givenName READ getGivenName WRITE setGivenName NOTIFY givenNameChanged) Q_PROPERTY(QString familyName READ getFamilyName WRITE setFamilyName NOTIFY familyNameChanged) Q_PROPERTY(QString displayName READ getDisplayName NOTIFY displayNameChanged) @@ -106,6 +114,10 @@ public: QList getAllAddresses() const; + QList getDevices() const; + void updateVerifiedDevicesCount(); + void setDevices(QVariantList devices); + LinphoneEnums::ConsolidatedPresence getConsolidatedPresence() const; void setConsolidatedPresence(LinphoneEnums::ConsolidatedPresence presence); @@ -147,7 +159,8 @@ signals: void removed(FriendCore *contact); void defaultAddressChanged(); void allAddressesChanged(); - + void devicesChanged(); + void verifiedDevicesChanged(); void lSetStarred(bool starred); protected: @@ -163,6 +176,8 @@ protected: bool mStarred; QList mPhoneNumberList; QList mAddressList; + QList mDeviceList; + int mVerifiedDeviceCount; QString mDefaultAddress; QString mPictureUri; bool mIsSaved; diff --git a/Linphone/model/friend/FriendModel.cpp b/Linphone/model/friend/FriendModel.cpp index 31b59be19..ad5bbfc72 100644 --- a/Linphone/model/friend/FriendModel.cpp +++ b/Linphone/model/friend/FriendModel.cpp @@ -275,6 +275,10 @@ QString FriendModel::getVCardAsString() const { return Utils::coreStringToAppString(mMonitor->getVcard()->asVcard4String()); } +std::list> FriendModel::getDevices() const { + return mMonitor->getDevices(); +} + void FriendModel::setPictureUri(const QString &uri) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto oldPictureUri = Utils::coreStringToAppString(mMonitor->getPhoto()); diff --git a/Linphone/model/friend/FriendModel.hpp b/Linphone/model/friend/FriendModel.hpp index 5e5ffe5cb..75b6c638c 100644 --- a/Linphone/model/friend/FriendModel.hpp +++ b/Linphone/model/friend/FriendModel.hpp @@ -54,6 +54,7 @@ public: std::shared_ptr getFriend() const; QString getPictureUri() const; QString getVCardAsString() const; + std::list> getDevices() const; protected: void setAddress(const std::shared_ptr &address); diff --git a/Linphone/tool/LinphoneEnums.cpp b/Linphone/tool/LinphoneEnums.cpp index fb6652a68..bbeb8f65f 100644 --- a/Linphone/tool/LinphoneEnums.cpp +++ b/Linphone/tool/LinphoneEnums.cpp @@ -29,6 +29,7 @@ void LinphoneEnums::registerMetaTypes() { qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); @@ -118,6 +119,14 @@ QString LinphoneEnums::toString(const LinphoneEnums::CallStatus &data) { } } +linphone::SecurityLevel LinphoneEnums::toLinphone(const LinphoneEnums::SecurityLevel &level) { + return static_cast(level); +} + +LinphoneEnums::SecurityLevel LinphoneEnums::fromLinphone(const linphone::SecurityLevel &level) { + return static_cast(level); +} + LinphoneEnums::CallDir LinphoneEnums::fromLinphone(const linphone::Call::Dir &data) { return static_cast(data); } diff --git a/Linphone/tool/LinphoneEnums.hpp b/Linphone/tool/LinphoneEnums.hpp index 17583e117..7e1e1b91c 100644 --- a/Linphone/tool/LinphoneEnums.hpp +++ b/Linphone/tool/LinphoneEnums.hpp @@ -36,9 +36,9 @@ void registerMetaTypes(); enum class MediaEncryption { None = int(linphone::MediaEncryption::None), - Dtls = int(linphone::MediaEncryption::DTLS), Srtp = int(linphone::MediaEncryption::SRTP), - Zrtp = int(linphone::MediaEncryption::ZRTP) + Zrtp = int(linphone::MediaEncryption::ZRTP), + Dtls = int(linphone::MediaEncryption::DTLS) }; Q_ENUM_NS(MediaEncryption) @@ -159,6 +159,18 @@ linphone::Call::Status toLinphone(const LinphoneEnums::CallStatus &data); LinphoneEnums::CallStatus fromLinphone(const linphone::Call::Status &data); QString toString(const LinphoneEnums::CallStatus &data); +enum class SecurityLevel { + None = int(linphone::SecurityLevel::None), + Unsafe = int(linphone::SecurityLevel::Unsafe), + EndToEndEncrypted = int(linphone::SecurityLevel::EndToEndEncrypted), + EndToEndEncryptedAndVerified = int(linphone::SecurityLevel::EndToEndEncryptedAndVerified), + PointToPointEncrypted = int(linphone::SecurityLevel::PointToPointEncrypted) +}; +Q_ENUM_NS(SecurityLevel) + +linphone::SecurityLevel toLinphone(const LinphoneEnums::SecurityLevel &level); +LinphoneEnums::SecurityLevel fromLinphone(const linphone::SecurityLevel &level); + enum class CallDir { Outgoing = int(linphone::Call::Dir::Outgoing), Incoming = int(linphone::Call::Dir::Incoming) }; Q_ENUM_NS(CallDir) @@ -308,6 +320,8 @@ Q_ENUM_NS(TransportType) linphone::TransportType toLinphone(const LinphoneEnums::TransportType &type); LinphoneEnums::TransportType fromLinphone(const linphone::TransportType &type); +QString toString(const LinphoneEnums::TransportType &type); +void fromString(const QString &transportType, LinphoneEnums::TransportType *transport); enum VideoSourceScreenSharingType { VideoSourceScreenSharingTypeArea = int(linphone::VideoSourceScreenSharingType::Area), @@ -319,8 +333,6 @@ Q_ENUM_NS(VideoSourceScreenSharingType) linphone::VideoSourceScreenSharingType toLinphone(const LinphoneEnums::VideoSourceScreenSharingType &type); LinphoneEnums::VideoSourceScreenSharingType fromLinphone(const linphone::VideoSourceScreenSharingType &type); -QString toString(const LinphoneEnums::TransportType &type); -void fromString(const QString &transportType, LinphoneEnums::TransportType *transport); } // namespace LinphoneEnums /* Q_DECLARE_METATYPE(LinphoneEnums::CallState) diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index 155e92425..5d8ee2823 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -105,13 +105,14 @@ QString Utils::getInitials(const QString &username) { void Utils::createCall(const QString &sipAddress, QVariantMap options, + LinphoneEnums::MediaEncryption mediaEncryption, const QString &prepareTransfertAddress, const QHash &headers) { - lDebug() << "[Utils] create call with uri :" << sipAddress; - App::postModelAsync([sipAddress, options, prepareTransfertAddress, headers]() { + lDebug() << "[Utils] create call with uri :" << sipAddress << mediaEncryption; + App::postModelAsync([sipAddress, options, mediaEncryption, prepareTransfertAddress, headers]() { QString errorMessage; bool success = ToolModel::createCall(sipAddress, options, prepareTransfertAddress, headers, - linphone::MediaEncryption::None, &errorMessage); + LinphoneEnums::toLinphone(mediaEncryption), &errorMessage); if (!success) { if (errorMessage.isEmpty()) errorMessage = tr("L'appel n'a pas pu être créé"); showInformationPopup("Erreur", errorMessage, false); diff --git a/Linphone/tool/Utils.hpp b/Linphone/tool/Utils.hpp index e5dfa17c0..7def8167f 100644 --- a/Linphone/tool/Utils.hpp +++ b/Linphone/tool/Utils.hpp @@ -26,6 +26,7 @@ #include #include "Constants.hpp" +#include "tool/LinphoneEnums.hpp" // ============================================================================= @@ -59,10 +60,12 @@ public: Q_INVOKABLE static QString getFamilyNameFromFullName(const QString &fullName); Q_INVOKABLE static QString getInitials(const QString &username); // Support UTF32 - Q_INVOKABLE static void createCall(const QString &sipAddress, - QVariantMap options = {}, - const QString &prepareTransfertAddress = "", - const QHash &headers = {}); + Q_INVOKABLE static void + createCall(const QString &sipAddress, + QVariantMap options = {}, + LinphoneEnums::MediaEncryption mediaEncryption = LinphoneEnums::MediaEncryption::None, + const QString &prepareTransfertAddress = "", + const QHash &headers = {}); Q_INVOKABLE static void openCallsWindow(CallGui *call); Q_INVOKABLE static void setupConference(ConferenceInfoGui *confGui); Q_INVOKABLE static QQuickWindow *getMainWindow(); diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index 544381ec3..64cb5009f 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -74,6 +74,7 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Item/PhoneNumberInput.qml view/Item/Popup.qml view/Item/PopupButton.qml + view/Item/ProgressBar.qml view/Item/SecurityRadioButton.qml view/Item/RadioButton.qml view/Item/RectangleTest.qml diff --git a/Linphone/view/Item/ProgressBar.qml b/Linphone/view/Item/ProgressBar.qml new file mode 100644 index 000000000..18790ebaf --- /dev/null +++ b/Linphone/view/Item/ProgressBar.qml @@ -0,0 +1,41 @@ +import QtQuick +import QtQuick.Controls +import Linphone + +ProgressBar { + id: mainItem + + padding: 3 * DefaultStyle.dp + + property color backgroundColor: DefaultStyle.main2_100 + property color innerColor: DefaultStyle.info_500_main + property color innerTextColor: DefaultStyle.grey_0 + property bool innerTextVisible: true + property string innerText: Number.parseFloat(value*100).toFixed(0) + "%" + + background: Rectangle { + color: mainItem.backgroundColor + radius: 50 * DefaultStyle.dp + anchors.fill: mainItem + width: mainItem.width + height: mainItem.height + } + contentItem: Item { + Rectangle { + color: mainItem.innerColor + radius: 50 * DefaultStyle.dp + width: mainItem.visualPosition * mainItem.width + height: parent.height + Text { + visible: innerTextVisible && mainItem.value > 0 + text: mainItem.innerText + anchors.centerIn: parent + color: mainItem.innerTextColor + font { + pixelSize: 10 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } + } + } + } +} \ No newline at end of file diff --git a/Linphone/view/Page/Main/ContactPage.qml b/Linphone/view/Page/Main/ContactPage.qml index 229810bd4..9f5a58645 100644 --- a/Linphone/view/Page/Main/ContactPage.qml +++ b/Linphone/view/Page/Main/ContactPage.qml @@ -4,6 +4,8 @@ import QtQuick.Layouts import QtQuick.Controls as Control import Linphone import UtilsCpp 1.0 +import EnumsToStringCpp 1.0 +import SettingsCpp 1.0 AbstractMainPage { id: mainItem @@ -266,357 +268,415 @@ AbstractMainPage { Component { id: contactDetail - RowLayout { + Item { property string objectName: "contactDetail" - visible: mainItem.selectedContact != undefined - Layout.fillWidth: true - Layout.fillHeight: true Control.StackView.onActivated: mainItem.leftPanelEnabled = true Control.StackView.onDeactivated: mainItem.leftPanelEnabled = false - ContactLayout { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.alignment: Qt.AlignLeft | Qt.AlignTop - Layout.topMargin: 45 * DefaultStyle.dp - contact: mainItem.selectedContact - Layout.preferredWidth: 360 * DefaultStyle.dp - buttonContent: Button { - width: 24 * DefaultStyle.dp - height: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - background: Item{} - onClicked: mainItem.editContact(mainItem.selectedContact) - icon.source: AppIcons.pencil - } - detailContent: ColumnLayout { - Layout.fillWidth: false + RowLayout { + visible: mainItem.selectedContact != undefined + anchors.fill: parent + anchors.topMargin: 45 * DefaultStyle.dp + anchors.bottomMargin: 23 * DefaultStyle.dp + ContactLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + contact: mainItem.selectedContact Layout.preferredWidth: 360 * DefaultStyle.dp - spacing: 32 * DefaultStyle.dp + buttonContent: Button { + width: 24 * DefaultStyle.dp + height: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + background: Item{} + onClicked: mainItem.editContact(mainItem.selectedContact) + icon.source: AppIcons.pencil + } + detailContent: ColumnLayout { + Layout.fillWidth: false + Layout.preferredWidth: 360 * DefaultStyle.dp + spacing: 32 * DefaultStyle.dp + ColumnLayout { + spacing: 9 * DefaultStyle.dp + Text { + Layout.leftMargin: 10 * DefaultStyle.dp + text: qsTr("Informations") + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + + RoundedBackgroundControl { + Layout.preferredHeight: Math.min(226 * DefaultStyle.dp, addrList.contentHeight + topPadding + bottomPadding) + height: Math.min(226 * DefaultStyle.dp, addrList.contentHeight) + Layout.fillWidth: true + topPadding: 12 * DefaultStyle.dp + bottomPadding: 12 * DefaultStyle.dp + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + contentItem: ListView { + id: addrList + width: 360 * DefaultStyle.dp + height: contentHeight + clip: true + spacing: 9 * DefaultStyle.dp + model: VariantList { + model: mainItem.selectedContact ? mainItem.selectedContact.core.allAddresses : [] + } + delegate: Item { + width: addrList.width + height: 46 * DefaultStyle.dp + + ColumnLayout { + anchors.fill: parent + // anchors.topMargin: 5 * DefaultStyle.dp + RowLayout { + Layout.fillWidth: true + // Layout.fillHeight: true + // Layout.alignment: Qt.AlignVCenter + // Layout.topMargin: 10 * DefaultStyle.dp + // Layout.bottomMargin: 10 * DefaultStyle.dp + ColumnLayout { + Layout.fillWidth: true + Text { + Layout.fillWidth: true + text: modelData.label + font { + pixelSize: 13 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } + } + Text { + Layout.fillWidth: true + text: modelData.address + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + } + Item { + Layout.fillWidth: true + } + Button { + background: Item{} + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.source: AppIcons.phone + width: 24 * DefaultStyle.dp + height: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + onClicked: { + UtilsCpp.createCall(modelData.address) + } + } + } + + Rectangle { + visible: index != addrList.model.count - 1 + Layout.fillWidth: true + Layout.preferredHeight: 1 * DefaultStyle.dp + Layout.rightMargin: 3 * DefaultStyle.dp + Layout.leftMargin: 3 * DefaultStyle.dp + color: DefaultStyle.main2_200 + clip: true + } + } + } + } + } + } + RoundedBackgroundControl { + visible: companyText.text.length != 0 || jobText.text.length != 0 + Layout.fillWidth: true + topPadding: 17 * DefaultStyle.dp + bottomPadding: 17 * DefaultStyle.dp + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + // Layout.fillHeight: true + + contentItem: ColumnLayout { + // height: 100 * DefaultStyle.dp + RowLayout { + height: 50 * DefaultStyle.dp + Text { + text: qsTr("Company :") + font { + pixelSize: 13 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } + } + Text { + id: companyText + text: mainItem.selectedContact && mainItem.selectedContact.core.organization + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + } + RowLayout { + height: 50 * DefaultStyle.dp + Text { + text: qsTr("Job :") + font { + pixelSize: 13 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } + } + Text { + id: jobText + text: mainItem.selectedContact && mainItem.selectedContact.core.job + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + } + } + ColumnLayout { + visible: false + Text { + text: qsTr("Medias") + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + Button { + Rectangle { + anchors.fill: parent + color: DefaultStyle.grey_0 + radius: 15 * DefaultStyle.dp + } + contentItem: RowLayout { + Image { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + source: AppIcons.shareNetwork + } + Text { + text: qsTr("Show media shared") + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + } + onClicked: console.debug("TODO : go to shared media") + } + } + } + } + } + ColumnLayout { + spacing: 10 * DefaultStyle.dp + Layout.rightMargin: 90 * DefaultStyle.dp + ColumnLayout { + RowLayout { + Text { + text: qsTr("Confiance") + Layout.leftMargin: 10 * DefaultStyle.dp + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + } + RoundedBackgroundControl { + contentItem: ColumnLayout { + spacing: 13 * DefaultStyle.dp + Text { + text: qsTr("Niveau de confiance - Appareils vérifiés") + font { + pixelSize: 13 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } + } + Text { + visible: deviceList.count === 0 + text: qsTr("Aucun appareil") + } + ProgressBar { + visible: deviceList.count > 0 + Layout.preferredWidth: 320 * DefaultStyle.dp + Layout.preferredHeight: 28 * DefaultStyle.dp + value: mainItem.selectedContact ? mainItem.selectedContact.core.verifiedDeviceCount / deviceList.count : 0 + } + ListView { + id: deviceList + Layout.fillWidth: true + Layout.preferredHeight: Math.min(200 * DefaultStyle.dp, contentHeight) + clip: true + model: mainItem.selectedContact ? mainItem.selectedContact.core.devices : [] + spacing: 16 * DefaultStyle.dp + delegate: RowLayout { + id: deviceDelegate + width: deviceList.width + height: 30 * DefaultStyle.dp + property var callObj + property CallGui deviceCall: callObj ? callObj.value : null + Text { + text: modelData.name.length != 0 ? modelData.name : qsTr("Appareil sans nom") + font.pixelSize: 14 * DefaultStyle.dp + } + Item{Layout.fillWidth: true} + Image{ + visible: modelData.securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified + source: AppIcons.trusted + width: 22 * DefaultStyle.dp + height: 22 * DefaultStyle.dp + } + Button { + visible: modelData.securityLevel != LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified + color: DefaultStyle.main1_100 + icon.source: AppIcons.warningCircle + contentImageColor: DefaultStyle.main1_500_main + textColor: DefaultStyle.main1_500_main + textSize: 13 * DefaultStyle.dp + text: qsTr("Vérifier") + leftPadding: 12 * DefaultStyle.dp + rightPadding: 12 * DefaultStyle.dp + topPadding: 6 * DefaultStyle.dp + bottomPadding: 6 * DefaultStyle.dp + onClicked: { + UtilsCpp.createCall(modelData.address, {}, LinphoneEnums.MediaEncryption.Zrtp) + parent.callObj = UtilsCpp.getCallByAddress(modelData.address) + } + } + } + } + } + } + } ColumnLayout { spacing: 9 * DefaultStyle.dp Text { + Layout.preferredHeight: 22 * DefaultStyle.dp Layout.leftMargin: 10 * DefaultStyle.dp - text: qsTr("Informations") + text: qsTr("Other actions") font { pixelSize: 16 * DefaultStyle.dp weight: 800 * DefaultStyle.dp } } - RoundedBackgroundControl { - Layout.preferredHeight: Math.min(226 * DefaultStyle.dp, addrList.contentHeight + topPadding + bottomPadding) - height: Math.min(226 * DefaultStyle.dp, addrList.contentHeight) - Layout.fillWidth: true - topPadding: 12 * DefaultStyle.dp - bottomPadding: 12 * DefaultStyle.dp - leftPadding: 20 * DefaultStyle.dp - rightPadding: 20 * DefaultStyle.dp - contentItem: ListView { - id: addrList - width: 360 * DefaultStyle.dp - height: contentHeight - clip: true - spacing: 9 * DefaultStyle.dp - model: VariantList { - model: mainItem.selectedContact ? mainItem.selectedContact.core.allAddresses : [] + Layout.preferredWidth: 360 * DefaultStyle.dp + contentItem: ColumnLayout { + width: parent.width + + IconLabelButton { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 50 * DefaultStyle.dp + iconSize: 24 * DefaultStyle.dp + iconSource: AppIcons.pencil + text: qsTr("Edit") + onClicked: mainItem.editContact(mainItem.selectedContact) } - delegate: Item { - width: addrList.width - height: 46 * DefaultStyle.dp - - ColumnLayout { - anchors.fill: parent - // anchors.topMargin: 5 * DefaultStyle.dp - RowLayout { - Layout.fillWidth: true - // Layout.fillHeight: true - // Layout.alignment: Qt.AlignVCenter - // Layout.topMargin: 10 * DefaultStyle.dp - // Layout.bottomMargin: 10 * DefaultStyle.dp - ColumnLayout { - Layout.fillWidth: true - Text { - Layout.fillWidth: true - text: modelData.label - font { - pixelSize: 13 * DefaultStyle.dp - weight: 700 * DefaultStyle.dp - } - } - Text { - Layout.fillWidth: true - text: modelData.address - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } - } - } - Item { - Layout.fillWidth: true - } - Button { - background: Item{} - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.source: AppIcons.phone - width: 24 * DefaultStyle.dp - height: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - onClicked: { - UtilsCpp.createCall(modelData.address) - } - } - } - - Rectangle { - visible: index != addrList.model.count - 1 - Layout.fillWidth: true - Layout.preferredHeight: 1 * DefaultStyle.dp - Layout.rightMargin: 3 * DefaultStyle.dp - Layout.leftMargin: 3 * DefaultStyle.dp - color: DefaultStyle.main2_200 - clip: true + Rectangle { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 1 * DefaultStyle.dp + color: DefaultStyle.main2_200 + } + IconLabelButton { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 50 * DefaultStyle.dp + iconSize: 24 * DefaultStyle.dp + iconSource: mainItem.selectedContact && mainItem.selectedContact.core.starred ? AppIcons.heartFill : AppIcons.heart + text: mainItem.selectedContact && mainItem.selectedContact.core.starred ? qsTr("Remove from favourites") : qsTr("Add to favourites") + onClicked: if (mainItem.selectedContact) mainItem.selectedContact.core.lSetStarred(!mainItem.selectedContact.core.starred) + } + Rectangle { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 1 * DefaultStyle.dp + color: DefaultStyle.main2_200 + } + IconLabelButton { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 50 * DefaultStyle.dp + iconSize: 24 * DefaultStyle.dp + iconSource: AppIcons.shareNetwork + text: qsTr("Share") + onClicked: { + if (mainItem.selectedContact) { + var vcard = mainItem.selectedContact.core.getVCard() + UtilsCpp.copyToClipboard(vcard) + UtilsCpp.showInformationPopup(qsTr("Copié"), qsTr("VCard copiée dans le presse-papier")) } } } - } - } - } - RoundedBackgroundControl { - visible: companyText.text.length != 0 || jobText.text.length != 0 - Layout.fillWidth: true - topPadding: 17 * DefaultStyle.dp - bottomPadding: 17 * DefaultStyle.dp - leftPadding: 20 * DefaultStyle.dp - rightPadding: 20 * DefaultStyle.dp - // Layout.fillHeight: true - - contentItem: ColumnLayout { - // height: 100 * DefaultStyle.dp - RowLayout { - height: 50 * DefaultStyle.dp - Text { - text: qsTr("Company :") - font { - pixelSize: 13 * DefaultStyle.dp - weight: 700 * DefaultStyle.dp + Rectangle { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 1 * DefaultStyle.dp + color: DefaultStyle.main2_200 + } + IconLabelButton { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 50 * DefaultStyle.dp + iconSize: 24 * DefaultStyle.dp + iconSource: AppIcons.bellSlash + text: qsTr("Mute") + onClicked: console.log("TODO : mute contact") + } + Rectangle { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 1 * DefaultStyle.dp + color: DefaultStyle.main2_200 + } + IconLabelButton { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 50 * DefaultStyle.dp + iconSize: 24 * DefaultStyle.dp + iconSource: AppIcons.empty + text: qsTr("Block") + onClicked: console.log("TODO : block contact") + } + Rectangle { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 1 * DefaultStyle.dp + color: DefaultStyle.main2_200 + } + IconLabelButton { + Layout.fillWidth: true + Layout.leftMargin: 15 * DefaultStyle.dp + Layout.rightMargin: 15 * DefaultStyle.dp + Layout.preferredHeight: 50 * DefaultStyle.dp + iconSize: 24 * DefaultStyle.dp + iconSource: AppIcons.trashCan + color: DefaultStyle.danger_500main + text: qsTr("Delete this contact") + onClicked: { + // mainItem.selectedContact.core.remove() + dialog.contact = mainItem.selectedContact + dialog.open() } } - Text { - id: companyText - text: mainItem.selectedContact && mainItem.selectedContact.core.organization - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } - } - } - RowLayout { - height: 50 * DefaultStyle.dp - Text { - text: qsTr("Job :") - font { - pixelSize: 13 * DefaultStyle.dp - weight: 700 * DefaultStyle.dp - } - } - Text { - id: jobText - text: mainItem.selectedContact && mainItem.selectedContact.core.job - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } - } - } - } - } - ColumnLayout { - visible: false - Text { - text: qsTr("Medias") - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - } - Button { - Rectangle { - anchors.fill: parent - color: DefaultStyle.grey_0 - radius: 15 * DefaultStyle.dp - } - contentItem: RowLayout { - Image { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - source: AppIcons.shareNetwork - } - Text { - text: qsTr("Show media shared") - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } - } - } - onClicked: console.debug("TODO : go to shared media") - } - } - } - } - ColumnLayout { - spacing: 10 * DefaultStyle.dp - Layout.rightMargin: 90 * DefaultStyle.dp - ColumnLayout { - visible: false - RowLayout { - Text { - text: qsTr("Confiance") - Layout.leftMargin: 10 * DefaultStyle.dp - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - } - } - RoundedBackgroundControl { - contentItem: ColumnLayout { - Text { - text: qsTr("Niveau de confiance - Appareils vérifiés") - } - } - } - } - ColumnLayout { - spacing: 9 * DefaultStyle.dp - Text { - Layout.preferredHeight: 22 * DefaultStyle.dp - Layout.leftMargin: 10 * DefaultStyle.dp - text: qsTr("Other actions") - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - } - RoundedBackgroundControl { - Layout.preferredWidth: 360 * DefaultStyle.dp - contentItem: ColumnLayout { - width: parent.width - - IconLabelButton { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 50 * DefaultStyle.dp - iconSize: 24 * DefaultStyle.dp - iconSource: AppIcons.pencil - text: qsTr("Edit") - onClicked: mainItem.editContact(mainItem.selectedContact) - } - Rectangle { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 1 * DefaultStyle.dp - color: DefaultStyle.main2_200 - } - IconLabelButton { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 50 * DefaultStyle.dp - iconSize: 24 * DefaultStyle.dp - iconSource: mainItem.selectedContact && mainItem.selectedContact.core.starred ? AppIcons.heartFill : AppIcons.heart - text: mainItem.selectedContact && mainItem.selectedContact.core.starred ? qsTr("Remove from favourites") : qsTr("Add to favourites") - onClicked: if (mainItem.selectedContact) mainItem.selectedContact.core.lSetStarred(!mainItem.selectedContact.core.starred) - } - Rectangle { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 1 * DefaultStyle.dp - color: DefaultStyle.main2_200 - } - IconLabelButton { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 50 * DefaultStyle.dp - iconSize: 24 * DefaultStyle.dp - iconSource: AppIcons.shareNetwork - text: qsTr("Share") - onClicked: { - if (mainItem.selectedContact) { - var vcard = mainItem.selectedContact.core.getVCard() - UtilsCpp.copyToClipboard(vcard) - UtilsCpp.showInformationPopup(qsTr("Copié"), qsTr("VCard copiée dans le presse-papier")) - } - } - } - Rectangle { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 1 * DefaultStyle.dp - color: DefaultStyle.main2_200 - } - IconLabelButton { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 50 * DefaultStyle.dp - iconSize: 24 * DefaultStyle.dp - iconSource: AppIcons.bellSlash - text: qsTr("Mute") - onClicked: console.log("TODO : mute contact") - } - Rectangle { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 1 * DefaultStyle.dp - color: DefaultStyle.main2_200 - } - IconLabelButton { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 50 * DefaultStyle.dp - iconSize: 24 * DefaultStyle.dp - iconSource: AppIcons.empty - text: qsTr("Block") - onClicked: console.log("TODO : block contact") - } - Rectangle { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 1 * DefaultStyle.dp - color: DefaultStyle.main2_200 - } - IconLabelButton { - Layout.fillWidth: true - Layout.leftMargin: 15 * DefaultStyle.dp - Layout.rightMargin: 15 * DefaultStyle.dp - Layout.preferredHeight: 50 * DefaultStyle.dp - iconSize: 24 * DefaultStyle.dp - iconSource: AppIcons.trashCan - color: DefaultStyle.danger_500main - text: qsTr("Delete this contact") - onClicked: { - // mainItem.selectedContact.core.remove() - dialog.contact = mainItem.selectedContact - dialog.open() - } } } } } - // TODO : find device by friend } } } diff --git a/Linphone/view/Style/AppIcons.qml b/Linphone/view/Style/AppIcons.qml index a7d27dec7..870a5f165 100644 --- a/Linphone/view/Style/AppIcons.qml +++ b/Linphone/view/Style/AppIcons.qml @@ -98,4 +98,5 @@ QtObject { property string debug: "image://internal/debug.svg" property string world: "image://internal/world.svg" property string detective: "image://internal/detective.svg" + property string warningCircle: "image://internal/warning-circle.svg" }