verify friend device (TODO : add an automatic update when sdk allows it, for now it is done when call ends)

This commit is contained in:
Gaelle Braud 2024-06-11 17:51:49 +02:00
parent 1e065cfa72
commit 891f9acd8c
12 changed files with 565 additions and 344 deletions

View file

@ -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> FriendCore::create(const std::shared_ptr<linphone::Friend> &contact) {
auto sharedPointer = QSharedPointer<FriendCore>(new FriendCore(contact), &QObject::deleteLater);
sharedPointer->setSelf(sharedPointer);
@ -75,6 +83,15 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &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<FriendCore> me) {
void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
if (me) {
if (mFriendModel) {
mCoreModelConnection = nullptr; // No more needed
mFriendModelConnection = QSharedPointer<SafeConnection<FriendCore, FriendModel>>(
new SafeConnection<FriendCore, FriendModel>(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<FriendCore> me) {
mFriendModelConnection->makeConnectToCore(&FriendCore::lSetStarred, [this](bool starred) {
mFriendModelConnection->invokeToModel([this, starred]() { mFriendModel->setStarred(starred); });
});
if (!mCoreModelConnection) {
mCoreModelConnection = QSharedPointer<SafeConnection<FriendCore, CoreModel>>(
new SafeConnection<FriendCore, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
}
mCoreModelConnection->makeConnectToModel(
&CoreModel::callStateChanged,
[this](const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Call> &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<SafeConnection<FriendCore, CoreModel>>(
@ -332,6 +384,27 @@ QList<QVariant> FriendCore::getAllAddresses() const {
return mAddressList + mPhoneNumberList;
}
QList<QVariant> FriendCore::getDevices() const {
return mDeviceList;
}
void FriendCore::updateVerifiedDevicesCount() {
mVerifiedDeviceCount = 0;
for (auto &device : mDeviceList) {
auto map = device.toMap();
if (map["securityLevel"].value<LinphoneEnums::SecurityLevel>() ==
LinphoneEnums::SecurityLevel::EndToEndEncryptedAndVerified)
++mVerifiedDeviceCount;
}
emit verifiedDevicesChanged();
}
void FriendCore::setDevices(QVariantList devices) {
mDeviceList.clear();
mDeviceList.append(devices);
emit devicesChanged();
}
QString FriendCore::getDefaultAddress() const {
return mDefaultAddress;
}

View file

@ -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<QVariant> allAddresses READ getAllAddresses NOTIFY allAddressesChanged)
Q_PROPERTY(QList<QVariant> phoneNumbers READ getPhoneNumbers NOTIFY phoneNumberChanged)
Q_PROPERTY(QList<QVariant> addresses READ getAddresses NOTIFY addressChanged)
Q_PROPERTY(QList<QVariant> 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<QVariant> getAllAddresses() const;
QList<QVariant> 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<QVariant> mPhoneNumberList;
QList<QVariant> mAddressList;
QList<QVariant> mDeviceList;
int mVerifiedDeviceCount;
QString mDefaultAddress;
QString mPictureUri;
bool mIsSaved;

View file

@ -275,6 +275,10 @@ QString FriendModel::getVCardAsString() const {
return Utils::coreStringToAppString(mMonitor->getVcard()->asVcard4String());
}
std::list<std::shared_ptr<linphone::FriendDevice>> FriendModel::getDevices() const {
return mMonitor->getDevices();
}
void FriendModel::setPictureUri(const QString &uri) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto oldPictureUri = Utils::coreStringToAppString(mMonitor->getPhoto());

View file

@ -54,6 +54,7 @@ public:
std::shared_ptr<linphone::Friend> getFriend() const;
QString getPictureUri() const;
QString getVCardAsString() const;
std::list<std::shared_ptr<linphone::FriendDevice>> getDevices() const;
protected:
void setAddress(const std::shared_ptr<linphone::Address> &address);

View file

@ -29,6 +29,7 @@
void LinphoneEnums::registerMetaTypes() {
qRegisterMetaType<LinphoneEnums::CallState>();
qRegisterMetaType<LinphoneEnums::CallStatus>();
qRegisterMetaType<LinphoneEnums::SecurityLevel>();
qRegisterMetaType<LinphoneEnums::ChatMessageState>();
qRegisterMetaType<LinphoneEnums::ChatRoomState>();
qRegisterMetaType<LinphoneEnums::ConferenceLayout>();
@ -118,6 +119,14 @@ QString LinphoneEnums::toString(const LinphoneEnums::CallStatus &data) {
}
}
linphone::SecurityLevel LinphoneEnums::toLinphone(const LinphoneEnums::SecurityLevel &level) {
return static_cast<linphone::SecurityLevel>(level);
}
LinphoneEnums::SecurityLevel LinphoneEnums::fromLinphone(const linphone::SecurityLevel &level) {
return static_cast<LinphoneEnums::SecurityLevel>(level);
}
LinphoneEnums::CallDir LinphoneEnums::fromLinphone(const linphone::Call::Dir &data) {
return static_cast<LinphoneEnums::CallDir>(data);
}

View file

@ -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)

View file

@ -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<QString, QString> &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);

View file

@ -26,6 +26,7 @@
#include <QString>
#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<QString, QString> &headers = {});
Q_INVOKABLE static void
createCall(const QString &sipAddress,
QVariantMap options = {},
LinphoneEnums::MediaEncryption mediaEncryption = LinphoneEnums::MediaEncryption::None,
const QString &prepareTransfertAddress = "",
const QHash<QString, QString> &headers = {});
Q_INVOKABLE static void openCallsWindow(CallGui *call);
Q_INVOKABLE static void setupConference(ConferenceInfoGui *confGui);
Q_INVOKABLE static QQuickWindow *getMainWindow();

View file

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

View file

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

View file

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

View file

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