Feature : display accounts.
- Implement shaders to make round images and use qsb --qt6. - Add picture to Friend. - Display username if displayname is not found. - Compute initials from C++ with emojis. - Add Accounts list in a popup from main window. - Add a hack on account to update avatar on all AcountModel. - Add Avatar item for initials/picture. - Add Contact description item. - Make sizes proportionals to match designs. - Add image colorization.
This commit is contained in:
parent
41ee79c070
commit
a1d72e6382
24 changed files with 537 additions and 30 deletions
|
|
@ -40,6 +40,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
|
||||||
mFriendModel->setSelf(mFriendModel);
|
mFriendModel->setSelf(mFriendModel);
|
||||||
mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence());
|
mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence());
|
||||||
mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
|
mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
|
||||||
|
mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
|
||||||
auto address = contact->getAddress();
|
auto address = contact->getAddress();
|
||||||
mAddress = address ? Utils::coreStringToAppString(contact->getAddress()->asString()) : "NoAddress";
|
mAddress = address ? Utils::coreStringToAppString(contact->getAddress()->asString()) : "NoAddress";
|
||||||
mIsSaved = true;
|
mIsSaved = true;
|
||||||
|
|
@ -71,6 +72,14 @@ void FriendCore::setSelf(SafeSharedPointer<QObject> me) {
|
||||||
setPresenceTimestamp(presenceTimestamp);
|
setPresenceTimestamp(presenceTimestamp);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
mFriendModelConnection->makeConnect(mFriendModel.get(), &FriendModel::pictureUriChanged, [this](QString uri) {
|
||||||
|
mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); });
|
||||||
|
});
|
||||||
|
|
||||||
|
// From GUI
|
||||||
|
mFriendModelConnection->makeConnect(this, &FriendCore::lSetPictureUri, [this](QString uri) {
|
||||||
|
mFriendModelConnection->invokeToModel([this, uri]() { mFriendModel->setPictureUri(uri); });
|
||||||
|
});
|
||||||
|
|
||||||
} else { // Create
|
} else { // Create
|
||||||
mFriendModelConnection = QSharedPointer<SafeConnection>(
|
mFriendModelConnection = QSharedPointer<SafeConnection>(
|
||||||
|
|
@ -133,6 +142,15 @@ void FriendCore::setPresenceTimestamp(QDateTime presenceTimestamp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString FriendCore::getPictureUri() const {
|
||||||
|
return mPictureUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FriendCore::onPictureUriChanged(QString uri) {
|
||||||
|
mPictureUri = uri;
|
||||||
|
emit pictureUriChanged();
|
||||||
|
}
|
||||||
|
|
||||||
bool FriendCore::getIsSaved() const {
|
bool FriendCore::getIsSaved() const {
|
||||||
return mIsSaved;
|
return mIsSaved;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class FriendCore : public QObject, public AbstractObject {
|
||||||
Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY
|
Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY
|
||||||
consolidatedPresenceChanged)
|
consolidatedPresenceChanged)
|
||||||
Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged)
|
Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged)
|
||||||
|
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE lSetPictureUri NOTIFY pictureUriChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Should be call from model Thread. Will be automatically in App thread after initialization
|
// Should be call from model Thread. Will be automatically in App thread after initialization
|
||||||
|
|
@ -70,6 +71,9 @@ public:
|
||||||
bool getIsSaved() const;
|
bool getIsSaved() const;
|
||||||
void setIsSaved(bool isSaved);
|
void setIsSaved(bool isSaved);
|
||||||
|
|
||||||
|
QString getPictureUri() const;
|
||||||
|
void onPictureUriChanged(QString uri);
|
||||||
|
|
||||||
void onPresenceReceived(LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp);
|
void onPresenceReceived(LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp);
|
||||||
|
|
||||||
Q_INVOKABLE void remove();
|
Q_INVOKABLE void remove();
|
||||||
|
|
@ -84,10 +88,13 @@ signals:
|
||||||
void presenceTimestampChanged(QDateTime presenceTimestamp);
|
void presenceTimestampChanged(QDateTime presenceTimestamp);
|
||||||
void sipAddressAdded(const QString &sipAddress);
|
void sipAddressAdded(const QString &sipAddress);
|
||||||
void sipAddressRemoved(const QString &sipAddress);
|
void sipAddressRemoved(const QString &sipAddress);
|
||||||
|
void pictureUriChanged();
|
||||||
void saved();
|
void saved();
|
||||||
void isSavedChanged(bool isSaved);
|
void isSavedChanged(bool isSaved);
|
||||||
void removed(FriendCore *contact);
|
void removed(FriendCore *contact);
|
||||||
|
|
||||||
|
void lSetPictureUri(QString pictureUri);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void writeInto(std::shared_ptr<linphone::Friend> contact) const;
|
void writeInto(std::shared_ptr<linphone::Friend> contact) const;
|
||||||
void writeFrom(const std::shared_ptr<linphone::Friend> &contact);
|
void writeFrom(const std::shared_ptr<linphone::Friend> &contact);
|
||||||
|
|
@ -96,6 +103,7 @@ protected:
|
||||||
QDateTime mPresenceTimestamp;
|
QDateTime mPresenceTimestamp;
|
||||||
QString mName;
|
QString mName;
|
||||||
QString mAddress;
|
QString mAddress;
|
||||||
|
QString mPictureUri;
|
||||||
bool mIsSaved;
|
bool mIsSaved;
|
||||||
std::shared_ptr<FriendModel> mFriendModel;
|
std::shared_ptr<FriendModel> mFriendModel;
|
||||||
QSharedPointer<SafeConnection> mFriendModelConnection;
|
QSharedPointer<SafeConnection> mFriendModelConnection;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
|
||||||
"data/image/info.svg"
|
"data/image/info.svg"
|
||||||
"data/image/belledonne.svg"
|
"data/image/belledonne.svg"
|
||||||
"data/image/user-circle.svg"
|
"data/image/user-circle.svg"
|
||||||
|
"data/image/user-circle-gear.svg"
|
||||||
"data/image/logo.svg"
|
"data/image/logo.svg"
|
||||||
"data/image/login_image.svg"
|
"data/image/login_image.svg"
|
||||||
"data/image/eye-slash.svg"
|
"data/image/eye-slash.svg"
|
||||||
|
|
@ -45,6 +46,9 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
|
||||||
"data/image/outgoing_call_missed.svg"
|
"data/image/outgoing_call_missed.svg"
|
||||||
"data/image/outgoing_call_rejected.svg"
|
"data/image/outgoing_call_rejected.svg"
|
||||||
|
|
||||||
|
data/shaders/roundEffect.vert.qsb
|
||||||
|
data/shaders/roundEffect.frag.qsb
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(_LINPHONEAPP_RC_FILES ${_LINPHONEAPP_RC_FILES} PARENT_SCOPE)
|
set(_LINPHONEAPP_RC_FILES ${_LINPHONEAPP_RC_FILES} PARENT_SCOPE)
|
||||||
|
|
|
||||||
18
Linphone/data/shaders/roundEffect.frag
Normal file
18
Linphone/data/shaders/roundEffect.frag
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#version 440
|
||||||
|
layout(location = 0) in vec2 coord;
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 qt_Matrix;
|
||||||
|
float qt_Opacity;
|
||||||
|
float edge;
|
||||||
|
};
|
||||||
|
layout(binding = 1) uniform sampler2D src;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float dist = distance(coord, vec2( 0.5 ));
|
||||||
|
float delta = fwidth(dist);
|
||||||
|
float alpha = smoothstep( mix(clamp(edge, 0.0, 1.0), 0.0, 0.5) - delta, 0.5, dist );
|
||||||
|
|
||||||
|
vec4 tex = texture(src, coord);
|
||||||
|
fragColor = mix( tex, vec4(0.0), alpha) * qt_Opacity;
|
||||||
|
}
|
||||||
BIN
Linphone/data/shaders/roundEffect.frag.qsb
Normal file
BIN
Linphone/data/shaders/roundEffect.frag.qsb
Normal file
Binary file not shown.
13
Linphone/data/shaders/roundEffect.vert
Normal file
13
Linphone/data/shaders/roundEffect.vert
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 440
|
||||||
|
layout(location = 0) in vec4 qt_Vertex;
|
||||||
|
layout(location = 1) in vec2 qt_MultiTextCoord0;
|
||||||
|
layout(location = 0) out vec2 coord;
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 qt_Matrix;
|
||||||
|
float qt_Opacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
coord = qt_MultiTextCoord0;
|
||||||
|
gl_Position = qt_Matrix * qt_Vertex;
|
||||||
|
}
|
||||||
BIN
Linphone/data/shaders/roundEffect.vert.qsb
Normal file
BIN
Linphone/data/shaders/roundEffect.vert.qsb
Normal file
Binary file not shown.
|
|
@ -34,6 +34,10 @@ AccountModel::AccountModel(const std::shared_ptr<linphone::Account> &account, QO
|
||||||
mustBeInLinphoneThread(getClassName());
|
mustBeInLinphoneThread(getClassName());
|
||||||
connect(CoreModel::getInstance().get(), &CoreModel::defaultAccountChanged, this,
|
connect(CoreModel::getInstance().get(), &CoreModel::defaultAccountChanged, this,
|
||||||
&AccountModel::onDefaultAccountChanged);
|
&AccountModel::onDefaultAccountChanged);
|
||||||
|
|
||||||
|
// Hack because Account doesn't provide callbacks on updated data
|
||||||
|
connect(this, &AccountModel::defaultAccountChanged, this,
|
||||||
|
[this]() { emit pictureUriChanged(Utils::coreStringToAppString(mMonitor->getParams()->getPictureUri())); });
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountModel::~AccountModel() {
|
AccountModel::~AccountModel() {
|
||||||
|
|
@ -61,7 +65,10 @@ void AccountModel::setPictureUri(QString uri) {
|
||||||
}
|
}
|
||||||
params->setPictureUri(Utils::appStringToCoreString(uri));
|
params->setPictureUri(Utils::appStringToCoreString(uri));
|
||||||
account->setParams(params);
|
account->setParams(params);
|
||||||
emit pictureUriChanged(uri);
|
// Hack because Account doesn't provide callbacks on updated data
|
||||||
|
// emit pictureUriChanged(uri);
|
||||||
|
emit CoreModel::getInstance()->defaultAccountChanged(CoreModel::getInstance()->getCore(),
|
||||||
|
CoreModel::getInstance()->getCore()->getDefaultAccount());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountModel::onDefaultAccountChanged() {
|
void AccountModel::onDefaultAccountChanged() {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,11 @@
|
||||||
|
|
||||||
#include "FriendModel.hpp"
|
#include "FriendModel.hpp"
|
||||||
|
|
||||||
|
#include "core/path/Paths.hpp"
|
||||||
|
#include "tool/Utils.hpp"
|
||||||
|
#include "tool/providers/AvatarProvider.hpp"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
DEFINE_ABSTRACT_OBJECT(FriendModel)
|
DEFINE_ABSTRACT_OBJECT(FriendModel)
|
||||||
|
|
||||||
|
|
@ -48,3 +52,21 @@ QDateTime FriendModel::getPresenceTimestamp() const {
|
||||||
void FriendModel::onPresenceReceived(const std::shared_ptr<linphone::Friend> &contact) {
|
void FriendModel::onPresenceReceived(const std::shared_ptr<linphone::Friend> &contact) {
|
||||||
emit presenceReceived(LinphoneEnums::fromLinphone(contact->getConsolidatedPresence()), getPresenceTimestamp());
|
emit presenceReceived(LinphoneEnums::fromLinphone(contact->getConsolidatedPresence()), getPresenceTimestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FriendModel::setPictureUri(QString uri) {
|
||||||
|
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||||
|
auto account = std::dynamic_pointer_cast<linphone::Account>(mMonitor);
|
||||||
|
auto params = account->getParams()->clone();
|
||||||
|
auto oldPictureUri = Utils::coreStringToAppString(params->getPictureUri());
|
||||||
|
if (!oldPictureUri.isEmpty()) {
|
||||||
|
QString appPrefix = QStringLiteral("image://%1/").arg(AvatarProvider::ProviderId);
|
||||||
|
if (oldPictureUri.startsWith(appPrefix)) {
|
||||||
|
oldPictureUri = Paths::getAvatarsDirPath() + oldPictureUri.mid(appPrefix.length());
|
||||||
|
}
|
||||||
|
QFile oldPicture(oldPictureUri);
|
||||||
|
if (!oldPicture.remove()) qWarning() << log().arg("Cannot delete old avatar file at " + oldPictureUri);
|
||||||
|
}
|
||||||
|
params->setPictureUri(Utils::appStringToCoreString(uri));
|
||||||
|
account->setParams(params);
|
||||||
|
emit pictureUriChanged(uri);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,13 @@ public:
|
||||||
~FriendModel();
|
~FriendModel();
|
||||||
|
|
||||||
QDateTime getPresenceTimestamp() const;
|
QDateTime getPresenceTimestamp() const;
|
||||||
|
|
||||||
std::shared_ptr<linphone::Friend> getFriend() const;
|
std::shared_ptr<linphone::Friend> getFriend() const;
|
||||||
|
|
||||||
|
void setPictureUri(QString uri);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void pictureUriChanged(QString uri);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_ABSTRACT_OBJECT
|
DECLARE_ABSTRACT_OBJECT
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ QString ToolModel::getDisplayName(const std::shared_ptr<const linphone::Address>
|
||||||
QString displayName;
|
QString displayName;
|
||||||
if (address) {
|
if (address) {
|
||||||
displayName = Utils::coreStringToAppString(address->getDisplayName());
|
displayName = Utils::coreStringToAppString(address->getDisplayName());
|
||||||
|
if (displayName.isEmpty()) displayName = Utils::coreStringToAppString(address->getUsername());
|
||||||
// TODO
|
// TODO
|
||||||
// std::shared_ptr<linphone::Address> cleanAddress = address->clone();
|
// std::shared_ptr<linphone::Address> cleanAddress = address->clone();
|
||||||
// cleanAddress->clean();
|
// cleanAddress->clean();
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,26 @@ VariantObject *Utils::getDisplayName(const QString &address) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Utils::getInitials(const QString &username) {
|
||||||
|
if (username.isEmpty()) return "";
|
||||||
|
|
||||||
|
QRegularExpression regex("[\\s\\.]+");
|
||||||
|
QStringList words = username.split(regex); // Qt 5.14: Qt::SkipEmptyParts
|
||||||
|
QStringList initials;
|
||||||
|
auto str32 = words[0].toStdU32String();
|
||||||
|
std::u32string char32;
|
||||||
|
char32 += str32[0];
|
||||||
|
initials << QString::fromStdU32String(char32);
|
||||||
|
for (int i = 1; i < words.size() && initials.size() <= 1; ++i) {
|
||||||
|
if (words[i].size() > 0) {
|
||||||
|
str32 = words[i].toStdU32String();
|
||||||
|
char32[0] = str32[0];
|
||||||
|
initials << QString::fromStdU32String(char32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QLocale().toUpper(initials.join(""));
|
||||||
|
}
|
||||||
|
|
||||||
VariantObject *Utils::createCall(const QString &sipAddress,
|
VariantObject *Utils::createCall(const QString &sipAddress,
|
||||||
const QString &prepareTransfertAddress,
|
const QString &prepareTransfertAddress,
|
||||||
const QHash<QString, QString> &headers) {
|
const QHash<QString, QString> &headers) {
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_INVOKABLE static VariantObject *getDisplayName(const QString &address);
|
Q_INVOKABLE static VariantObject *getDisplayName(const QString &address);
|
||||||
|
Q_INVOKABLE static QString getInitials(const QString &username); // Support UTF32
|
||||||
Q_INVOKABLE static VariantObject *createCall(const QString &sipAddress,
|
Q_INVOKABLE static VariantObject *createCall(const QString &sipAddress,
|
||||||
const QString &prepareTransfertAddress = "",
|
const QString &prepareTransfertAddress = "",
|
||||||
const QHash<QString, QString> &headers = {});
|
const QHash<QString, QString> &headers = {});
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import QtCore
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Controls 2.2 as Control
|
import QtQuick.Controls 2.2 as Control
|
||||||
import QtQuick.Dialogs
|
import QtQuick.Effects
|
||||||
|
|
||||||
import Linphone
|
import Linphone
|
||||||
import UtilsCpp
|
import UtilsCpp
|
||||||
|
|
@ -17,7 +17,7 @@ Item {
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
// spacing: 30
|
// spacing: 30
|
||||||
anchors.topMargin: 18
|
anchors.topMargin: 18 * DefaultStyle.dp
|
||||||
VerticalTabBar {
|
VerticalTabBar {
|
||||||
id: tabbar
|
id: tabbar
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
@ -32,7 +32,9 @@ Item {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.leftMargin: 25
|
id: topRow
|
||||||
|
Layout.leftMargin: 25 * DefaultStyle.dp
|
||||||
|
Layout.rightMargin: 41 * DefaultStyle.dp
|
||||||
TextInput {
|
TextInput {
|
||||||
fillWidth: true
|
fillWidth: true
|
||||||
placeholderText: qsTr("Rechercher un contact, appeler ou envoyer un message...")
|
placeholderText: qsTr("Rechercher un contact, appeler ou envoyer un message...")
|
||||||
|
|
@ -41,42 +43,44 @@ Item {
|
||||||
id: avatarButton
|
id: avatarButton
|
||||||
AccountProxy{
|
AccountProxy{
|
||||||
id: accountProxy
|
id: accountProxy
|
||||||
property bool haveAvatar: defaultAccount && defaultAccount.core.pictureUri || false
|
//property bool haveAvatar: defaultAccount && defaultAccount.core.pictureUri || false
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.preferredWidth: 30
|
Layout.preferredWidth: 54 * DefaultStyle.dp
|
||||||
Layout.preferredHeight: 30
|
Layout.preferredHeight: width
|
||||||
background: Item {
|
background: Item {
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
contentItem: Image {
|
contentItem: Avatar {
|
||||||
id: avatar
|
id: avatar
|
||||||
source: accountProxy.haveAvatar ? accountProxy.defaultAccount.core.pictureUri : AppIcons.welcomeLinphoneLogo
|
height: avatarButton.height
|
||||||
fillMode: Image.PreserveAspectFit
|
width: avatarButton.width
|
||||||
|
account: accountProxy.defaultAccount
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
fileDialog.open()
|
accountList.open()
|
||||||
}
|
}
|
||||||
FileDialog {
|
|
||||||
id: fileDialog
|
|
||||||
currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
|
|
||||||
onAccepted: {
|
|
||||||
var avatarPath = UtilsCpp.createAvatar( selectedFile )
|
|
||||||
if(avatarPath){
|
|
||||||
accountProxy.defaultAccount.core.pictureUri = avatarPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Control.Button {
|
Control.Button {
|
||||||
|
id: settingsButton
|
||||||
enabled: false
|
enabled: false
|
||||||
Layout.preferredWidth: 30
|
Layout.preferredWidth: 30 * DefaultStyle.dp
|
||||||
Layout.preferredHeight: 30
|
Layout.preferredHeight: 30 * DefaultStyle.dp
|
||||||
background: Item {
|
background: Item {
|
||||||
}
|
}
|
||||||
contentItem: Image {
|
contentItem: Image {
|
||||||
source: AppIcons.verticalDots
|
source: AppIcons.verticalDots
|
||||||
}
|
}
|
||||||
|
Popup{
|
||||||
|
id: accountList
|
||||||
|
x: -width + parent.width
|
||||||
|
y: settingsButton.height + (10 * DefaultStyle.dp)
|
||||||
|
contentWidth: accounts.width
|
||||||
|
contentHeight: accounts.height
|
||||||
|
Accounts{
|
||||||
|
id: accounts
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StackLayout {
|
StackLayout {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import Linphone
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
id: mainWindow
|
id: mainWindow
|
||||||
width: 1025
|
width: 1512 * DefaultStyle.dp
|
||||||
height: 641
|
height: 930 * DefaultStyle.dp
|
||||||
visible: true
|
visible: true
|
||||||
title: qsTr("Linphone")
|
title: qsTr("Linphone")
|
||||||
property bool firstConnection: true
|
property bool firstConnection: true
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,17 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
||||||
view/App/Layout/LoginLayout.qml
|
view/App/Layout/LoginLayout.qml
|
||||||
view/App/Layout/MainLayout.qml
|
view/App/Layout/MainLayout.qml
|
||||||
|
|
||||||
|
view/Item/Account/Accounts.qml
|
||||||
|
|
||||||
view/Item/Button.qml
|
view/Item/Button.qml
|
||||||
view/Item/Carousel.qml
|
view/Item/Carousel.qml
|
||||||
view/Item/CheckBox.qml
|
view/Item/CheckBox.qml
|
||||||
view/Item/ComboBox.qml
|
view/Item/ComboBox.qml
|
||||||
|
|
||||||
|
view/Item/Contact/Avatar.qml
|
||||||
|
view/Item/Contact/Contact.qml
|
||||||
|
view/Item/Contact/ContactDescription.qml
|
||||||
|
|
||||||
view/Item/DesktopPopup.qml
|
view/Item/DesktopPopup.qml
|
||||||
view/Item/DigitInput.qml
|
view/Item/DigitInput.qml
|
||||||
|
|
||||||
|
|
@ -18,6 +25,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
||||||
view/Item/NumericPad.qml
|
view/Item/NumericPad.qml
|
||||||
view/Item/PhoneNumberComboBox.qml
|
view/Item/PhoneNumberComboBox.qml
|
||||||
view/Item/PhoneNumberInput.qml
|
view/Item/PhoneNumberInput.qml
|
||||||
|
view/Item/Popup.qml
|
||||||
view/Item/RadioButton.qml
|
view/Item/RadioButton.qml
|
||||||
view/Item/RectangleTest.qml
|
view/Item/RectangleTest.qml
|
||||||
view/Item/SearchBar.qml
|
view/Item/SearchBar.qml
|
||||||
|
|
|
||||||
73
Linphone/view/Item/Account/Accounts.qml
Normal file
73
Linphone/view/Item/Account/Accounts.qml
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Controls 2.2 as Control
|
||||||
|
|
||||||
|
import Linphone
|
||||||
|
import UtilsCpp
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: mainItem
|
||||||
|
width: 517 * DefaultStyle.dp
|
||||||
|
readonly property int topPadding: 23 * DefaultStyle.dp
|
||||||
|
readonly property int bottomPadding: 18 * DefaultStyle.dp
|
||||||
|
readonly property int leftPadding: 32 * DefaultStyle.dp
|
||||||
|
readonly property int rightPadding: 32 * DefaultStyle.dp
|
||||||
|
readonly property int spacing: 16 * DefaultStyle.dp
|
||||||
|
implicitHeight: list.contentHeight + topPadding + bottomPadding + 32 * DefaultStyle.dp + 1 + newAccountArea.height
|
||||||
|
ColumnLayout{
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: mainItem.topPadding
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: mainItem.leftPadding
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: mainItem.rightPadding
|
||||||
|
ListView{
|
||||||
|
id: list
|
||||||
|
Layout.preferredHeight: contentHeight
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: mainItem.spacing
|
||||||
|
model: AccountProxy{}
|
||||||
|
delegate: Contact{
|
||||||
|
width: list.width
|
||||||
|
account: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rectangle{
|
||||||
|
id: separator
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: mainItem.spacing
|
||||||
|
Layout.bottomMargin: mainItem.spacing
|
||||||
|
height: 1
|
||||||
|
color: DefaultStyle.main2_300
|
||||||
|
}
|
||||||
|
MouseArea{ // TODO
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 32 * DefaultStyle.dp
|
||||||
|
onClicked: console.log('New!')
|
||||||
|
RowLayout{
|
||||||
|
id: newAccountArea
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 5 * DefaultStyle.dp
|
||||||
|
EffectImage {
|
||||||
|
id: newAccount
|
||||||
|
image.source: AppIcons.plusCircle
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: height
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
image.fillMode: Image.PreserveAspectFit
|
||||||
|
colorizationColor: DefaultStyle.main2_500main
|
||||||
|
}
|
||||||
|
Text{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
font.weight: 400 * DefaultStyle.dp
|
||||||
|
font.pixelSize: 14 * DefaultStyle.dp
|
||||||
|
color: DefaultStyle.main2_500main
|
||||||
|
text: 'Ajouter un compte'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
77
Linphone/view/Item/Contact/Avatar.qml
Normal file
77
Linphone/view/Item/Contact/Avatar.qml
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
import Linphone
|
||||||
|
import UtilsCpp
|
||||||
|
|
||||||
|
// Avatar using initial of the username in case
|
||||||
|
// they don't have any profile picture
|
||||||
|
|
||||||
|
StackView{
|
||||||
|
id: mainItem
|
||||||
|
property FriendGui contact
|
||||||
|
property AccountGui account
|
||||||
|
onAccountChanged: if(account) replace(avatar, StackView.Immediate)
|
||||||
|
property string address: account ? account.core.identityAddress : ''
|
||||||
|
property var displayNameObj: UtilsCpp.getDisplayName(address)
|
||||||
|
property bool haveAvatar: (account && account.core.pictureUri )
|
||||||
|
|| (contact && contact.core.pictureUri)
|
||||||
|
|
||||||
|
initialItem: haveAvatar ? avatar : initials
|
||||||
|
Component{
|
||||||
|
id: initials
|
||||||
|
Rectangle {
|
||||||
|
id: initialItem
|
||||||
|
property string initials: UtilsCpp.getInitials(mainItem.displayNameObj.value)
|
||||||
|
onInitialsChanged: console.log("newInit:"+initials)
|
||||||
|
radius: width / 2
|
||||||
|
color: DefaultStyle.main2_200
|
||||||
|
height: mainItem.height
|
||||||
|
width: height
|
||||||
|
Component.onCompleted: console.log("init:"+initials)
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.centerIn: parent
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: initialItem.initials
|
||||||
|
font {
|
||||||
|
pixelSize: initialItem.height * 36 / 120
|
||||||
|
weight: 800 * DefaultStyle.dp
|
||||||
|
capitalization: Font.AllUppercase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component{
|
||||||
|
id: avatar
|
||||||
|
Item {
|
||||||
|
id: avatarItem
|
||||||
|
height: mainItem.height
|
||||||
|
width: height
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
visible: false
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
sourceSize.width: avatarItem.width
|
||||||
|
sourceSize.height: avatarItem.height
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
anchors.centerIn: parent
|
||||||
|
source: mainItem.account ? mainItem.account.core.pictureUri : mainItem.contact.core.pictureUri
|
||||||
|
mipmap: true
|
||||||
|
}
|
||||||
|
ShaderEffect {
|
||||||
|
id: roundEffect
|
||||||
|
property variant src: image
|
||||||
|
property double edge: 0.9
|
||||||
|
anchors.fill: parent
|
||||||
|
vertexShader: 'qrc:/data/shaders/roundEffect.vert.qsb'
|
||||||
|
fragmentShader: 'qrc:/data/shaders/roundEffect.frag.qsb'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
137
Linphone/view/Item/Contact/Contact.qml
Normal file
137
Linphone/view/Item/Contact/Contact.qml
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
||||||
|
import Linphone
|
||||||
|
import UtilsCpp
|
||||||
|
|
||||||
|
Rectangle{
|
||||||
|
id: mainItem
|
||||||
|
property AccountGui account
|
||||||
|
height: 45 * DefaultStyle.dp
|
||||||
|
RowLayout{
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
Avatar{
|
||||||
|
id: avatar
|
||||||
|
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
|
account: mainItem.account
|
||||||
|
MouseArea{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: fileDialog.open()
|
||||||
|
}
|
||||||
|
FileDialog {
|
||||||
|
id: fileDialog
|
||||||
|
currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
|
||||||
|
onAccepted: {
|
||||||
|
var avatarPath = UtilsCpp.createAvatar( selectedFile )
|
||||||
|
if(avatarPath){
|
||||||
|
mainItem.account.core.pictureUri = avatarPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ContactDescription{
|
||||||
|
id: description
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.leftMargin: 10 * DefaultStyle.dp
|
||||||
|
account: mainItem.account
|
||||||
|
}
|
||||||
|
Item{
|
||||||
|
id: registrationStatusItem
|
||||||
|
Layout.preferredWidth: 97 * DefaultStyle.dp
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Rectangle{
|
||||||
|
id: registrationStatus
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: Math.min(text.implicitWidth + (2 * 8 * DefaultStyle.dp), registrationStatusItem.width)
|
||||||
|
height: 24 * DefaultStyle.dp
|
||||||
|
color: DefaultStyle.main2_200
|
||||||
|
radius: 90 * DefaultStyle.dp
|
||||||
|
Text{
|
||||||
|
id: text
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 8 * DefaultStyle.dp
|
||||||
|
anchors.rightMargin: 8 * DefaultStyle.dp
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
visible: mainItem.account
|
||||||
|
readonly property int mode : !mainItem.account || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Ok
|
||||||
|
? 0
|
||||||
|
: mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Cleared || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.None
|
||||||
|
? 1
|
||||||
|
: mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Progress || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Refreshing
|
||||||
|
? 2
|
||||||
|
: 3
|
||||||
|
// Test texts
|
||||||
|
//Timer{
|
||||||
|
// running: true
|
||||||
|
// interval: 1000
|
||||||
|
// repeat: true
|
||||||
|
// onTriggered: text.mode = (++text.mode) % 4
|
||||||
|
//}
|
||||||
|
font.weight: 300 * DefaultStyle.dp
|
||||||
|
font.pixelSize: 12 * DefaultStyle.dp
|
||||||
|
color: mode == 0
|
||||||
|
? DefaultStyle.success_500main
|
||||||
|
: mode == 1
|
||||||
|
? DefaultStyle.warning_600
|
||||||
|
: mode == 2
|
||||||
|
? DefaultStyle.main2_500main
|
||||||
|
: DefaultStyle.danger_500main
|
||||||
|
text: mode == 0
|
||||||
|
? 'Connecté'
|
||||||
|
: mode == 1
|
||||||
|
? 'Désactivé'
|
||||||
|
: mode == 2
|
||||||
|
? 'Connexion...'
|
||||||
|
: 'Erreur'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item{ // TODO
|
||||||
|
Layout.preferredWidth: 100 * DefaultStyle.dp
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Rectangle{
|
||||||
|
id: unreadNotifications
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 10 * DefaultStyle.dp
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 22 * DefaultStyle.dp
|
||||||
|
height: 22 * DefaultStyle.dp
|
||||||
|
radius: width/2
|
||||||
|
color: DefaultStyle.danger_500main
|
||||||
|
border.color: DefaultStyle.grey_0
|
||||||
|
border.width: 2 * DefaultStyle.dp
|
||||||
|
Text{
|
||||||
|
id: unreadCount
|
||||||
|
anchors.fill: parent
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: DefaultStyle.grey_0
|
||||||
|
text: '2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EffectImage {
|
||||||
|
id: manageAccount
|
||||||
|
image.source: AppIcons.manageProfile
|
||||||
|
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
image.sourceSize.width: 24 * DefaultStyle.dp
|
||||||
|
image.fillMode: Image.PreserveAspectFit
|
||||||
|
colorizationColor: DefaultStyle.main2_500main
|
||||||
|
MouseArea{ // TODO
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: console.log('Manage!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
Linphone/view/Item/Contact/ContactDescription.qml
Normal file
37
Linphone/view/Item/Contact/ContactDescription.qml
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
import Linphone
|
||||||
|
import UtilsCpp
|
||||||
|
|
||||||
|
ColumnLayout{
|
||||||
|
id: mainItem
|
||||||
|
property AccountGui account: null
|
||||||
|
property var displayName: account ? UtilsCpp.getDisplayName(account.core.identityAddress) : ''
|
||||||
|
property string topText: displayName ? displayName.value : ''
|
||||||
|
property string bottomText: account ? account.core.identityAddress : ''
|
||||||
|
spacing: 0
|
||||||
|
Text{
|
||||||
|
id: topTextItem
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
verticalAlignment: (bottomTextItem.visible?Text.AlignBottom:Text.AlignVCenter)
|
||||||
|
visible: text != ''
|
||||||
|
font.weight: 400 * DefaultStyle.dp
|
||||||
|
font.pixelSize: 14 * DefaultStyle.dp
|
||||||
|
color: DefaultStyle.main2_700
|
||||||
|
text: mainItem.topText
|
||||||
|
}
|
||||||
|
Text{
|
||||||
|
id: bottomTextItem
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
verticalAlignment: (topTextItem.visible?Text.AlignTop:Text.AlignVCenter)
|
||||||
|
visible: text != ''
|
||||||
|
font.weight: 300 * DefaultStyle.dp
|
||||||
|
font.pixelSize: 12 * DefaultStyle.dp
|
||||||
|
color: DefaultStyle.main2_400
|
||||||
|
text: mainItem.bottomText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,21 +9,36 @@ Item {
|
||||||
id: mainItem
|
id: mainItem
|
||||||
property alias image: image
|
property alias image: image
|
||||||
property alias effect: effect
|
property alias effect: effect
|
||||||
|
property alias effect2: effect2
|
||||||
|
property var colorizationColor
|
||||||
|
readonly property bool useColor: colorizationColor != undefined
|
||||||
width: image.width
|
width: image.width
|
||||||
height: image.height
|
height: image.height
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: image
|
id: image
|
||||||
width: 20
|
width: parent.width
|
||||||
height: 20
|
height: parent.height
|
||||||
sourceSize.width: 20
|
//sourceSize.width: parent.width
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
visible: !effect2.enabled
|
||||||
}
|
}
|
||||||
MultiEffect {
|
MultiEffect {
|
||||||
id: effect
|
id: effect
|
||||||
anchors.fill: image
|
anchors.fill: image
|
||||||
source: image
|
source: image
|
||||||
maskSource: image
|
maskSource: image
|
||||||
|
visible: !effect2.enabled
|
||||||
|
brightness: effect2.enabled ? 1.0 : 0.0
|
||||||
|
}
|
||||||
|
MultiEffect {
|
||||||
|
id: effect2
|
||||||
|
enabled: mainItem.useColor
|
||||||
|
anchors.fill: effect
|
||||||
|
source: effect
|
||||||
|
maskSource: effect
|
||||||
|
colorizationColor: effect2.enabled ? mainItem.colorizationColor : 'black'
|
||||||
|
colorization: effect2.enabled ? 1.0 : 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
27
Linphone/view/Item/Popup.qml
Normal file
27
Linphone/view/Item/Popup.qml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls as Control
|
||||||
|
import QtQuick.Effects
|
||||||
|
import Linphone
|
||||||
|
|
||||||
|
Control.Popup{
|
||||||
|
id: mainItem
|
||||||
|
padding: 0
|
||||||
|
background: Item{
|
||||||
|
Rectangle{
|
||||||
|
id: backgroundItem
|
||||||
|
width: mainItem.width
|
||||||
|
height: mainItem.height
|
||||||
|
radius: 16 * DefaultStyle.dp
|
||||||
|
border.color: DefaultStyle.grey_0
|
||||||
|
border.width: 1
|
||||||
|
}
|
||||||
|
MultiEffect {
|
||||||
|
anchors.fill: backgroundItem
|
||||||
|
source: backgroundItem
|
||||||
|
maskSource: backgroundItem
|
||||||
|
shadowEnabled: true
|
||||||
|
shadowBlur: 1.0
|
||||||
|
shadowOpacity: 0.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ QtObject {
|
||||||
property string loginImage: "image://internal/login_image.svg"
|
property string loginImage: "image://internal/login_image.svg"
|
||||||
property string belledonne: "image://internal/belledonne.svg"
|
property string belledonne: "image://internal/belledonne.svg"
|
||||||
property string profile: "image://internal/user-circle.svg"
|
property string profile: "image://internal/user-circle.svg"
|
||||||
|
property string manageProfile: "image://internal/user-circle-gear.svg"
|
||||||
property string verif_page_image: "image://internal/verif_page_image.svg"
|
property string verif_page_image: "image://internal/verif_page_image.svg"
|
||||||
property string check: "image://internal/check.svg"
|
property string check: "image://internal/check.svg"
|
||||||
property string dialer: "image://internal/dialer.svg"
|
property string dialer: "image://internal/dialer.svg"
|
||||||
|
|
|
||||||
|
|
@ -78,4 +78,16 @@ QtObject {
|
||||||
|
|
||||||
property color splitViewHandleColor: "#F9F9F9"
|
property color splitViewHandleColor: "#F9F9F9"
|
||||||
property color splitViewHoveredHandleColor: "#EDEDED"
|
property color splitViewHoveredHandleColor: "#EDEDED"
|
||||||
|
|
||||||
|
property color danger_500main: "#DD5F5F"
|
||||||
|
property color grey_0: "#FFFFFF"
|
||||||
|
property color success_500main: "#4FAE80"
|
||||||
|
property color warning_600: "#DBB820"
|
||||||
|
property color main2_200: "#DFECF2"
|
||||||
|
property color main2_300: "#C0D1D9"
|
||||||
|
property color main2_400: "#9AABB5"
|
||||||
|
property color main2_700: "#364860"
|
||||||
|
property color main2_500main: "#6C7A87"
|
||||||
|
|
||||||
|
property double dp: 1.0//0.66
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue