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:
Julien Wadel 2023-12-01 11:21:50 +01:00
parent 41ee79c070
commit a1d72e6382
24 changed files with 537 additions and 30 deletions

View file

@ -40,6 +40,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
mFriendModel->setSelf(mFriendModel);
mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence());
mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
auto address = contact->getAddress();
mAddress = address ? Utils::coreStringToAppString(contact->getAddress()->asString()) : "NoAddress";
mIsSaved = true;
@ -71,6 +72,14 @@ void FriendCore::setSelf(SafeSharedPointer<QObject> me) {
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
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 {
return mIsSaved;
}

View file

@ -44,6 +44,7 @@ class FriendCore : public QObject, public AbstractObject {
Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY
consolidatedPresenceChanged)
Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged)
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE lSetPictureUri NOTIFY pictureUriChanged)
public:
// Should be call from model Thread. Will be automatically in App thread after initialization
@ -70,6 +71,9 @@ public:
bool getIsSaved() const;
void setIsSaved(bool isSaved);
QString getPictureUri() const;
void onPictureUriChanged(QString uri);
void onPresenceReceived(LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp);
Q_INVOKABLE void remove();
@ -84,10 +88,13 @@ signals:
void presenceTimestampChanged(QDateTime presenceTimestamp);
void sipAddressAdded(const QString &sipAddress);
void sipAddressRemoved(const QString &sipAddress);
void pictureUriChanged();
void saved();
void isSavedChanged(bool isSaved);
void removed(FriendCore *contact);
void lSetPictureUri(QString pictureUri);
protected:
void writeInto(std::shared_ptr<linphone::Friend> contact) const;
void writeFrom(const std::shared_ptr<linphone::Friend> &contact);
@ -96,6 +103,7 @@ protected:
QDateTime mPresenceTimestamp;
QString mName;
QString mAddress;
QString mPictureUri;
bool mIsSaved;
std::shared_ptr<FriendModel> mFriendModel;
QSharedPointer<SafeConnection> mFriendModelConnection;

View file

@ -4,6 +4,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
"data/image/info.svg"
"data/image/belledonne.svg"
"data/image/user-circle.svg"
"data/image/user-circle-gear.svg"
"data/image/logo.svg"
"data/image/login_image.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_rejected.svg"
data/shaders/roundEffect.vert.qsb
data/shaders/roundEffect.frag.qsb
)
set(_LINPHONEAPP_RC_FILES ${_LINPHONEAPP_RC_FILES} PARENT_SCOPE)

View 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;
}

Binary file not shown.

View 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;
}

Binary file not shown.

View file

@ -34,6 +34,10 @@ AccountModel::AccountModel(const std::shared_ptr<linphone::Account> &account, QO
mustBeInLinphoneThread(getClassName());
connect(CoreModel::getInstance().get(), &CoreModel::defaultAccountChanged, this,
&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() {
@ -61,7 +65,10 @@ void AccountModel::setPictureUri(QString uri) {
}
params->setPictureUri(Utils::appStringToCoreString(uri));
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() {

View file

@ -20,7 +20,11 @@
#include "FriendModel.hpp"
#include "core/path/Paths.hpp"
#include "tool/Utils.hpp"
#include "tool/providers/AvatarProvider.hpp"
#include <QDebug>
#include <QUrl>
DEFINE_ABSTRACT_OBJECT(FriendModel)
@ -48,3 +52,21 @@ QDateTime FriendModel::getPresenceTimestamp() const {
void FriendModel::onPresenceReceived(const std::shared_ptr<linphone::Friend> &contact) {
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);
}

View file

@ -39,9 +39,13 @@ public:
~FriendModel();
QDateTime getPresenceTimestamp() const;
std::shared_ptr<linphone::Friend> getFriend() const;
void setPictureUri(QString uri);
signals:
void pictureUriChanged(QString uri);
private:
DECLARE_ABSTRACT_OBJECT

View file

@ -51,6 +51,7 @@ QString ToolModel::getDisplayName(const std::shared_ptr<const linphone::Address>
QString displayName;
if (address) {
displayName = Utils::coreStringToAppString(address->getDisplayName());
if (displayName.isEmpty()) displayName = Utils::coreStringToAppString(address->getUsername());
// TODO
// std::shared_ptr<linphone::Address> cleanAddress = address->clone();
// cleanAddress->clean();

View file

@ -53,6 +53,26 @@ VariantObject *Utils::getDisplayName(const QString &address) {
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,
const QString &prepareTransfertAddress,
const QHash<QString, QString> &headers) {

View file

@ -49,6 +49,7 @@ public:
}
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,
const QString &prepareTransfertAddress = "",
const QHash<QString, QString> &headers = {});

View file

@ -6,7 +6,7 @@ import QtCore
import QtQuick 2.15
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2 as Control
import QtQuick.Dialogs
import QtQuick.Effects
import Linphone
import UtilsCpp
@ -17,7 +17,7 @@ Item {
RowLayout {
anchors.fill: parent
// spacing: 30
anchors.topMargin: 18
anchors.topMargin: 18 * DefaultStyle.dp
VerticalTabBar {
id: tabbar
Layout.fillHeight: true
@ -32,7 +32,9 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
RowLayout {
Layout.leftMargin: 25
id: topRow
Layout.leftMargin: 25 * DefaultStyle.dp
Layout.rightMargin: 41 * DefaultStyle.dp
TextInput {
fillWidth: true
placeholderText: qsTr("Rechercher un contact, appeler ou envoyer un message...")
@ -41,42 +43,44 @@ Item {
id: avatarButton
AccountProxy{
id: accountProxy
property bool haveAvatar: defaultAccount && defaultAccount.core.pictureUri || false
//property bool haveAvatar: defaultAccount && defaultAccount.core.pictureUri || false
}
Layout.preferredWidth: 30
Layout.preferredHeight: 30
Layout.preferredWidth: 54 * DefaultStyle.dp
Layout.preferredHeight: width
background: Item {
visible: false
}
contentItem: Image {
contentItem: Avatar {
id: avatar
source: accountProxy.haveAvatar ? accountProxy.defaultAccount.core.pictureUri : AppIcons.welcomeLinphoneLogo
fillMode: Image.PreserveAspectFit
height: avatarButton.height
width: avatarButton.width
account: accountProxy.defaultAccount
}
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 {
id: settingsButton
enabled: false
Layout.preferredWidth: 30
Layout.preferredHeight: 30
Layout.preferredWidth: 30 * DefaultStyle.dp
Layout.preferredHeight: 30 * DefaultStyle.dp
background: Item {
}
contentItem: Image {
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 {

View file

@ -6,8 +6,8 @@ import Linphone
Window {
id: mainWindow
width: 1025
height: 641
width: 1512 * DefaultStyle.dp
height: 930 * DefaultStyle.dp
visible: true
title: qsTr("Linphone")
property bool firstConnection: true

View file

@ -4,10 +4,17 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/App/Layout/LoginLayout.qml
view/App/Layout/MainLayout.qml
view/Item/Account/Accounts.qml
view/Item/Button.qml
view/Item/Carousel.qml
view/Item/CheckBox.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/DigitInput.qml
@ -18,6 +25,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Item/NumericPad.qml
view/Item/PhoneNumberComboBox.qml
view/Item/PhoneNumberInput.qml
view/Item/Popup.qml
view/Item/RadioButton.qml
view/Item/RectangleTest.qml
view/Item/SearchBar.qml

View 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'
}
}
}
}
}

View 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'
}
}
}
}

View 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!')
}
}
}
}

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

View file

@ -9,21 +9,36 @@ Item {
id: mainItem
property alias image: image
property alias effect: effect
property alias effect2: effect2
property var colorizationColor
readonly property bool useColor: colorizationColor != undefined
width: image.width
height: image.height
Image {
id: image
width: 20
height: 20
sourceSize.width: 20
width: parent.width
height: parent.height
//sourceSize.width: parent.width
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
visible: !effect2.enabled
}
MultiEffect {
id: effect
anchors.fill: image
source: 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
}
}

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

View file

@ -14,6 +14,7 @@ QtObject {
property string loginImage: "image://internal/login_image.svg"
property string belledonne: "image://internal/belledonne.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 check: "image://internal/check.svg"
property string dialer: "image://internal/dialer.svg"

View file

@ -78,4 +78,16 @@ QtObject {
property color splitViewHandleColor: "#F9F9F9"
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
}